|
| 1 | +# libCacheSim Plugin System – Quick-Start Guide |
| 2 | + |
| 3 | +> **Audience**: Developers who want to add custom cache–replacement policies to *libCacheSim* without modifying the core library. |
| 4 | +> |
| 5 | +> **Goal**: Build a shared-library plugin that implements a few well-defined hook functions, then load it at runtime via `pluginCache`. |
| 6 | +
|
| 7 | +--- |
| 8 | + |
| 9 | +## 1 . How the Plugin System Works |
| 10 | + |
| 11 | +`plugin_cache.c` ships with *libCacheSim* and delegates **all policy-specific logic** to a user-supplied shared library (``.so`` / ``.dylib``). At run-time the library is |
| 12 | + |
| 13 | +1. loaded with `dlopen()`; |
| 14 | +2. each required *hook* is resolved with `dlsym()`; and |
| 15 | +3. the hooks are invoked on cache hits, misses, evictions, and removals. |
| 16 | + |
| 17 | +Because the plugin is completely decoupled from core code you can: |
| 18 | +* experiment with new algorithms quickly, |
| 19 | +* write the plugin in **C or C++**, and |
| 20 | +* distribute it independently from *libCacheSim*. |
| 21 | + |
| 22 | +### 1.1 Required Hook Functions |
| 23 | + |
| 24 | +Your library **must** export the following C-symbols: |
| 25 | + |
| 26 | +| Hook | Prototype | Called When | |
| 27 | +|------|-----------|-------------| |
| 28 | +| `cache_init_hook` | `void *cache_init_hook(const common_cache_params_t ccache_params);` | Once at cache creation. Return an opaque pointer to plugin state. | |
| 29 | +| `cache_hit_hook` | `void cache_hit_hook(void *data, const request_t *req);` | A requested object is found in the cache. | |
| 30 | +| `cache_miss_hook` | `void cache_miss_hook(void *data, const request_t *req);` | A requested object is **not** in the cache *after* insertion. | |
| 31 | +| `cache_eviction_hook` | `obj_id_t cache_eviction_hook(void *data, const request_t *req);` | Cache is full – must return the object-ID to evict. | |
| 32 | +| `cache_remove_hook` | `void cache_remove_hook(void *data, const obj_id_t obj_id);` | An object is explicitly removed (not necessarily due to eviction). | |
| 33 | + |
| 34 | +The opaque pointer returned by `cache_init_hook` is passed back to every other hook via the `data` parameter, letting your plugin maintain arbitrary state (linked lists, hash maps, statistics, …). For memory safety, your library can export `cache_free_hook` (`void cache_free_hook(void *data);`) to free the resources used by your cache struct according to your demands. |
| 35 | + |
| 36 | +--- |
| 37 | + |
| 38 | +## 2 . Minimal Plugin Skeleton (C++) |
| 39 | + |
| 40 | +Below is an **abridged** version of the LRU example in `example/plugin_v2/plugin_lru.cpp`. You can copy this as a starting point for your own policy: |
| 41 | + |
| 42 | +```cpp |
| 43 | +#include <libCacheSim.h> // public headers installed by libCacheSim |
| 44 | +#include <unordered_map> |
| 45 | + |
| 46 | +class MyPolicy { |
| 47 | + /* your data structures */ |
| 48 | +public: |
| 49 | + MyPolicy() {/*init*/} |
| 50 | + void on_hit(obj_id_t id) {/*...*/} |
| 51 | + void on_miss(obj_id_t id, uint64_t size) {/*...*/} |
| 52 | + obj_id_t evict() {/* decide victim */} |
| 53 | + void on_remove(obj_id_t id) {/*...*/} |
| 54 | +}; |
| 55 | + |
| 56 | +extern "C" { |
| 57 | +void *cache_init_hook(const common_cache_params_t /*params*/) { |
| 58 | + return new MyPolicy(); |
| 59 | +} |
| 60 | + |
| 61 | +void cache_hit_hook(void *data, const request_t *req) { |
| 62 | + static_cast<MyPolicy *>(data)->on_hit(req->obj_id); |
| 63 | +} |
| 64 | + |
| 65 | +void cache_miss_hook(void *data, const request_t *req) { |
| 66 | + static_cast<MyPolicy *>(data)->on_miss(req->obj_id, req->obj_size); |
| 67 | +} |
| 68 | + |
| 69 | +obj_id_t cache_eviction_hook(void *data, const request_t * /*req*/) { |
| 70 | + return static_cast<MyPolicy *>(data)->evict(); |
| 71 | +} |
| 72 | + |
| 73 | +void cache_remove_hook(void *data, const obj_id_t obj_id) { |
| 74 | + static_cast<MyPolicy *>(data)->on_remove(obj_id); |
| 75 | +} |
| 76 | +} // extern "C" |
| 77 | +``` |
| 78 | +
|
| 79 | +*Notes* |
| 80 | +1. The plugin can allocate dynamic memory; it will live until the cache is destroyed. |
| 81 | +2. Thread safety is up to you – core *libCacheSim* is single-threaded today. |
| 82 | +
|
| 83 | +--- |
| 84 | +
|
| 85 | +## 3 . Building the Plugin |
| 86 | +
|
| 87 | +### 3.1 Dependencies |
| 88 | +
|
| 89 | +* **CMake ≥ 3.12** (recommended) |
| 90 | +* A C/C++ compiler (``gcc``, ``clang``) |
| 91 | +
|
| 92 | +### 3.2 Sample `CMakeLists.txt` |
| 93 | +
|
| 94 | +```cmake |
| 95 | +cmake_minimum_required(VERSION 3.12) |
| 96 | +project(my_cache_plugin CXX C) |
| 97 | +
|
| 98 | +# Tell CMake to create a shared library |
| 99 | +add_library(plugin_my_policy SHARED plugin_my_policy.cpp) |
| 100 | +
|
| 101 | +# Location of libCacheSim headers – adjust if you installed elsewhere |
| 102 | +target_include_directories(plugin_my_policy PRIVATE |
| 103 | + ${CMAKE_CURRENT_SOURCE_DIR}/../../include) |
| 104 | +
|
| 105 | +# Position-independent code is implicit for shared libs but keep for clarity |
| 106 | +set_property(TARGET plugin_my_policy PROPERTY POSITION_INDEPENDENT_CODE ON) |
| 107 | +
|
| 108 | +# Optional: strip symbols & set output name |
| 109 | +set_target_properties(plugin_my_policy PROPERTIES |
| 110 | + OUTPUT_NAME "plugin_my_policy_hooks") |
| 111 | +``` |
| 112 | + |
| 113 | +### 3.3 Build Commands |
| 114 | + |
| 115 | +```bash |
| 116 | +mkdir build && cd build |
| 117 | +cmake -G Ninja .. # or "cmake .. && make" |
| 118 | +ninja # produces libplugin_my_policy_hooks.so |
| 119 | +``` |
| 120 | + |
| 121 | +> On macOS the file extension will be `.dylib` instead of `.so`. |
| 122 | + |
| 123 | +--- |
| 124 | + |
| 125 | +## 4 . Using the Plugin with `cachesim` |
| 126 | + |
| 127 | +1. **Compile** the plugin (`libplugin_my_policy_hooks.so`). |
| 128 | +2. **Run** `cachesim` with `pluginCache` **and** supply `plugin_path=`: |
| 129 | + |
| 130 | +```bash |
| 131 | +./bin/cachesim data/cloudPhysicsIO.vscsi vscsi pluginCache 0.01 \ |
| 132 | + -e "plugin_path=/absolute/path/libplugin_my_policy_hooks.so,cache_name=myPolicy" |
| 133 | +``` |
| 134 | + |
| 135 | +* Keys after `-e` are comma-separated. Supported keys today: |
| 136 | + * `plugin_path` (required) – absolute or relative path to the `.so` / `.dylib`. |
| 137 | + * `cache_name` (optional) – override the cache’s display name. |
| 138 | + * `print` – debug helper: print current parameters and exit. |
| 139 | + |
| 140 | +If you omit `cache_name`, the runtime will default to `pluginCache-<fileName>` for easier identification in logs. |
| 141 | + |
| 142 | +--- |
| 143 | + |
| 144 | +## 5 . A full example |
| 145 | + |
| 146 | +A comprehensive example lives in `example/plugin_v2`. After building the example plugin: |
| 147 | + |
| 148 | +--- |
| 149 | + |
| 150 | +## 6 . Troubleshooting Checklist |
| 151 | + |
| 152 | +* **Plugin not found?** Verify the path passed via `plugin_path=` is correct, you may want to use absolute path. |
| 153 | +* **Missing symbols?** Make sure the function names exactly match the prototypes above and are declared `extern "C"` when compiling as C++. |
| 154 | +* **Link-time errors?** Pass the same architecture flags (`-m64`, etc.) that *libCacheSim* was built with. |
| 155 | +* **Runtime crash inside plugin?** Use `gdb -ex r --args cachesim …` and place breakpoints in your hook functions. |
| 156 | + |
| 157 | +--- |
| 158 | + |
| 159 | + |
| 160 | +Happy caching! |
0 commit comments