Skip to content

Commit d109a01

Browse files
authored
add a plugin_v1 example (#236)
1 parent 0ea538b commit d109a01

5 files changed

Lines changed: 345 additions & 6 deletions

File tree

example/plugin_v1/CMakeLists.txt

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
cmake_minimum_required(VERSION 3.10)
2+
project(plugin_v1_lru_example)
3+
4+
# Set C++ standard
5+
set(CMAKE_CXX_STANDARD 17)
6+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
7+
8+
set(CMAKE_C_VISIBILITY_PRESET default)
9+
set(CMAKE_VISIBILITY_INLINES_HIDDEN 0)
10+
11+
12+
# Find required packages
13+
find_package(PkgConfig REQUIRED)
14+
pkg_check_modules(GLIB REQUIRED glib-2.0)
15+
message(STATUS "GLIB library: ${GLIB_LIBRARIES}")
16+
message(STATUS "GLIB include: ${GLIB_INCLUDE_DIRS}")
17+
18+
# Find libCacheSim
19+
# note that we need to find the shared library, not the static library
20+
find_library(LIBCACHESIM_LIBRARY
21+
NAMES CacheSim libCacheSim_shared
22+
PATHS /usr/local/lib /usr/lib
23+
DOC "libCacheSim unified library"
24+
)
25+
26+
find_path(LIBCACHESIM_INCLUDE_DIR
27+
NAMES libCacheSim.h
28+
PATHS /usr/local/include /usr/include
29+
DOC "libCacheSim include directory"
30+
)
31+
32+
message(STATUS "libCacheSim library: ${LIBCACHESIM_LIBRARY}")
33+
message(STATUS "libCacheSim include: ${LIBCACHESIM_INCLUDE_DIR}")
34+
35+
if(NOT LIBCACHESIM_LIBRARY OR NOT LIBCACHESIM_INCLUDE_DIR)
36+
message(FATAL_ERROR "libCacheSim not found! Please install libCacheSim first.")
37+
endif()
38+
39+
# Include directories
40+
include_directories(${GLIB_INCLUDE_DIRS})
41+
include_directories(${LIBCACHESIM_INCLUDE_DIR})
42+
43+
# Build plugin LRU shared library (plugin)
44+
add_library(plugin_lru SHARED plugin_lru.c)
45+
target_link_libraries(plugin_lru ${GLIB_LIBRARIES} ${LIBCACHESIM_LIBRARY} m)
46+
47+
# Build test programs
48+
add_executable(test_plugin test_plugin.c)
49+
target_link_libraries(test_plugin
50+
${GLIB_LIBRARIES}
51+
${LIBCACHESIM_LIBRARY}
52+
m
53+
dl)

example/plugin_v1/plugin_lru.c

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
//
2+
// a plugin_lru module that supports different obj size
3+
//
4+
//
5+
// plugin_lru.c
6+
// libCacheSim
7+
//
8+
// Created by Juncheng on 12/4/18.
9+
// Copyright © 2018 Juncheng. All rights reserved.
10+
//
11+
12+
#include "libCacheSim/cache.h"
13+
14+
#ifdef __cplusplus
15+
extern "C" {
16+
#endif
17+
18+
typedef struct plugin_lru_params {
19+
cache_obj_t *q_head;
20+
cache_obj_t *q_tail;
21+
} plugin_lru_params_t;
22+
23+
// ***********************************************************************
24+
// **** ****
25+
// **** function declarations ****
26+
// **** ****
27+
// ***********************************************************************
28+
29+
static void plugin_lru_free(cache_t *cache);
30+
static bool plugin_lru_get(cache_t *cache, const request_t *req);
31+
static cache_obj_t *plugin_lru_find(cache_t *cache, const request_t *req,
32+
bool update_cache);
33+
static cache_obj_t *plugin_lru_insert(cache_t *cache, const request_t *req);
34+
static cache_obj_t *plugin_lru_to_evict(cache_t *cache, const request_t *req);
35+
static void plugin_lru_evict(cache_t *cache, const request_t *req);
36+
static bool plugin_lru_remove(cache_t *cache, obj_id_t obj_id);
37+
38+
// ***********************************************************************
39+
// **** ****
40+
// **** end user facing functions ****
41+
// **** ****
42+
// **** init, free, get ****
43+
// ***********************************************************************
44+
45+
/**
46+
* @brief initialize a plugin_lru cache
47+
*
48+
* @param ccache_params some common cache parameters
49+
* @param cache_specific_params plugin_lru specific parameters, should be NULL
50+
* @return pointer to the initialized cache
51+
*/
52+
cache_t *plugin_lru_init(const common_cache_params_t ccache_params,
53+
const char *cache_specific_params) {
54+
cache_t *cache =
55+
cache_struct_init("plugin_lru", ccache_params, cache_specific_params);
56+
cache->cache_init = plugin_lru_init;
57+
cache->cache_free = plugin_lru_free;
58+
cache->get = plugin_lru_get;
59+
cache->find = plugin_lru_find;
60+
cache->insert = plugin_lru_insert;
61+
cache->evict = plugin_lru_evict;
62+
cache->remove = plugin_lru_remove;
63+
64+
plugin_lru_params_t *params = malloc(sizeof(plugin_lru_params_t));
65+
params->q_head = NULL;
66+
params->q_tail = NULL;
67+
cache->eviction_params = params;
68+
69+
return cache;
70+
}
71+
72+
/**
73+
* @brief free resources used by this cache
74+
*
75+
* @param cache the cache to free
76+
*/
77+
static void plugin_lru_free(cache_t *cache) {
78+
plugin_lru_params_t *params = (plugin_lru_params_t *)cache->eviction_params;
79+
free(params);
80+
cache_struct_free(cache);
81+
}
82+
83+
/**
84+
* @brief this function is the user facing API
85+
* it performs the following logic
86+
*
87+
* ```
88+
* if obj in cache:
89+
* update_metadata
90+
* return true
91+
* else:
92+
* if cache does not have enough space:
93+
* evict until it has space to insert
94+
* insert the object
95+
* return false
96+
* ```
97+
*
98+
* @param cache the cache
99+
* @param req the request
100+
* @return true if cache hit, false if cache miss
101+
*/
102+
static bool plugin_lru_get(cache_t *cache, const request_t *req) {
103+
plugin_lru_params_t *params = (plugin_lru_params_t *)cache->eviction_params;
104+
105+
cache_obj_t *obj = cache->find(cache, req, true);
106+
bool hit = (obj != NULL);
107+
108+
if (hit) {
109+
move_obj_to_head(&params->q_head, &params->q_tail, obj);
110+
} else {
111+
while (cache->get_occupied_byte(cache) + req->obj_size >
112+
cache->cache_size) {
113+
cache->evict(cache, req);
114+
}
115+
cache->insert(cache, req);
116+
}
117+
118+
return hit;
119+
}
120+
121+
// ***********************************************************************
122+
// **** ****
123+
// **** developer facing APIs (used by cache developer) ****
124+
// **** ****
125+
// ***********************************************************************
126+
127+
/**
128+
* @brief check whether an object is in the cache
129+
*
130+
* @param cache the cache
131+
* @param req the request
132+
* @param update_cache whether to update the cache,
133+
* if true, the object is promoted
134+
* and if the object is expired, it is removed from the cache
135+
* @return the cache object if found, NULL otherwise
136+
*/
137+
static cache_obj_t *plugin_lru_find(cache_t *cache, const request_t *req,
138+
const bool update_cache) {
139+
plugin_lru_params_t *params = (plugin_lru_params_t *)cache->eviction_params;
140+
cache_obj_t *cache_obj = cache_find_base(cache, req, update_cache);
141+
142+
if (cache_obj && likely(update_cache)) {
143+
move_obj_to_head(&params->q_head, &params->q_tail, cache_obj);
144+
}
145+
return cache_obj;
146+
}
147+
148+
/**
149+
* @brief insert an object into the cache,
150+
* update the hash table and cache metadata
151+
* this function assumes the cache has enough space
152+
* and eviction is not part of this function
153+
*
154+
* @param cache the cache
155+
* @param req the request
156+
* @return the inserted object
157+
*/
158+
static cache_obj_t *plugin_lru_insert(cache_t *cache, const request_t *req) {
159+
plugin_lru_params_t *params = (plugin_lru_params_t *)cache->eviction_params;
160+
161+
cache_obj_t *cache_obj = cache_insert_base(cache, req);
162+
prepend_obj_to_head(&params->q_head, &params->q_tail, cache_obj);
163+
164+
return cache_obj;
165+
}
166+
167+
/**
168+
* @brief find the object to be evicted
169+
* this function does not actually evict the object or update metadata
170+
*
171+
* @param cache the cache
172+
* @param req the request (not used in LRU)
173+
* @return the object to be evicted (least recently used)
174+
*/
175+
static cache_obj_t *plugin_lru_to_evict(cache_t *cache, const request_t *req) {
176+
plugin_lru_params_t *params = (plugin_lru_params_t *)cache->eviction_params;
177+
return params->q_tail;
178+
}
179+
180+
/**
181+
* @brief evict an object from the cache
182+
* it needs to call cache_evict_base before returning
183+
* which updates some metadata such as n_obj, occupied size, and hash table
184+
*
185+
* @param cache the cache
186+
* @param req the request (not used)
187+
*/
188+
static void plugin_lru_evict(cache_t *cache, const request_t *req) {
189+
plugin_lru_params_t *params = (plugin_lru_params_t *)cache->eviction_params;
190+
cache_obj_t *obj_to_evict = params->q_tail;
191+
DEBUG_ASSERT(params->q_tail != NULL);
192+
193+
remove_obj_from_list(&params->q_head, &params->q_tail, obj_to_evict);
194+
195+
cache_remove_obj_base(cache, obj_to_evict, true);
196+
}
197+
198+
/**
199+
* @brief remove the given object from the cache
200+
* note that eviction should not call this function, but rather call
201+
* `cache_evict_base` because we track extra metadata during eviction
202+
*
203+
* this function is different from eviction because it is used for user
204+
* triggered remove, and eviction is used by the cache to make space for new
205+
* objects
206+
*
207+
* @param cache the cache
208+
* @param obj the object to remove
209+
*/
210+
static void plugin_lru_remove_obj(cache_t *cache, cache_obj_t *obj) {
211+
if (obj == NULL) {
212+
return;
213+
}
214+
215+
plugin_lru_params_t *params = (plugin_lru_params_t *)cache->eviction_params;
216+
217+
remove_obj_from_list(&params->q_head, &params->q_tail, obj);
218+
cache_remove_obj_base(cache, obj, true);
219+
}
220+
221+
/**
222+
* @brief remove an object from the cache by object ID
223+
* this is different from cache_evict because it is used for user triggered
224+
* remove, and eviction is used by the cache to make space for new objects
225+
*
226+
* @param cache the cache
227+
* @param obj_id the object ID to remove
228+
* @return true if the object is removed, false if the object is not in the
229+
* cache
230+
*/
231+
static bool plugin_lru_remove(cache_t *cache, const obj_id_t obj_id) {
232+
request_t req = {.obj_id = obj_id, .obj_size = 0};
233+
cache_obj_t *obj = cache_find_base(cache, &req, false);
234+
235+
if (obj == NULL) {
236+
return false;
237+
}
238+
plugin_lru_remove_obj(cache, obj);
239+
return true;
240+
}
241+
242+
#ifdef __cplusplus
243+
}
244+
#endif

example/plugin_v1/test_plugin.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#include <assert.h>
2+
#include <dlfcn.h>
3+
#include <libCacheSim.h>
4+
#include <libCacheSim/plugin.h>
5+
#include <libgen.h>
6+
7+
void test_plugin_lru(int argc, char *argv[]) {
8+
common_cache_params_t ccache_params = {.cache_size = 1000,
9+
.default_ttl = 0,
10+
.hashpower = 20,
11+
.consider_obj_metadata = false};
12+
13+
// note that the plugin system assumes the plugin is in the same directory as
14+
// the test binary with a name of lib<plugin_name>.so
15+
cache_t *plugin_cache =
16+
create_cache_external("plugin_lru", ccache_params, NULL);
17+
cache_t *builtin_cache = create_cache_internal("LRU", ccache_params, NULL);
18+
19+
assert(plugin_cache != NULL);
20+
assert(builtin_cache != NULL);
21+
22+
// Test empty cache state
23+
assert(plugin_cache->get_n_obj(plugin_cache) == 0);
24+
assert(builtin_cache->get_n_obj(builtin_cache) == 0);
25+
26+
for (int i = 0; i < 1000; i++) {
27+
request_t req = {.obj_id = i, .obj_size = 100};
28+
bool plugin_hit = plugin_cache->get(plugin_cache, &req);
29+
bool builtin_hit = builtin_cache->get(builtin_cache, &req);
30+
assert(plugin_hit == builtin_hit);
31+
}
32+
33+
plugin_cache->cache_free(plugin_cache);
34+
builtin_cache->cache_free(builtin_cache);
35+
36+
INFO("test_plugin_lru passed\n");
37+
}
38+
39+
int main(int argc, char *argv[]) {
40+
test_plugin_lru(argc, argv);
41+
return 0;
42+
}

libCacheSim/cache/plugin.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ cache_t *create_cache_internal(const char *const cache_alg_name,
8585
abort();
8686
}
8787

88-
VERBOSE("internal cache %s loaded\n", cache_alg_name);
88+
INFO("internal cache %s loaded\n", cache_alg_name);
8989
cache_t *cache = cache_init(cc_params, cache_specific_params);
9090
return cache;
9191
}

test/CMakeLists.txt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
# Helper function to create test executables with explicit compiler flags
22
function(add_test_executable target_name source_file)
33
add_executable(${target_name} ${source_file})
4-
4+
55
# Apply appropriate compiler flags based on source file language
66
get_filename_component(file_ext ${source_file} EXT)
77
if(file_ext STREQUAL ".cpp" OR file_ext STREQUAL ".cxx" OR file_ext STREQUAL ".cc")
88
# C++ source file
9-
target_compile_options(${target_name} PRIVATE
9+
target_compile_options(${target_name} PRIVATE
1010
${LIBCACHESIM_CXX_FLAGS}
1111
)
1212
set_target_properties(${target_name} PROPERTIES
@@ -16,11 +16,11 @@ function(add_test_executable target_name source_file)
1616
)
1717
else()
1818
# C source file
19-
target_compile_options(${target_name} PRIVATE
19+
target_compile_options(${target_name} PRIVATE
2020
${LIBCACHESIM_C_FLAGS}
2121
)
2222
endif()
23-
23+
2424
target_link_libraries(${target_name} ${PROJECT_NAME})
2525

2626
# Add include directories for test compilation
@@ -71,4 +71,4 @@ if (ENABLE_3L_CACHE)
7171
add_executable(test3LCache test_3lcache.c)
7272
target_link_libraries(test3LCache ${core_libs} ${dependency_libs})
7373
add_test(NAME test3LCache COMMAND test3LCache WORKING_DIRECTORY .)
74-
endif (ENABLE_3L_CACHE)
74+
endif (ENABLE_3L_CACHE)

0 commit comments

Comments
 (0)