Skip to content

[Feat] Support LHD #38

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/basic_usage.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@
move_to_main_threshold=2,
)
req_miss_ratio, byte_miss_ratio = cache.process_trace(reader, start_req=0, max_req=1000)
print(f"Request miss ratio: {req_miss_ratio:.4f}, Byte miss ratio: {byte_miss_ratio:.4f}")
print(f"Request miss ratio: {req_miss_ratio:.4f}, Byte miss ratio: {byte_miss_ratio:.4f}")
2 changes: 2 additions & 0 deletions libcachesim/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from .cache import (
CacheBase,
# Core algorithms
LHD,
LRU,
FIFO,
LFU,
Expand Down Expand Up @@ -74,6 +75,7 @@
# Cache base class
"CacheBase",
# Core cache algorithms
"LHD",
"LRU",
"FIFO",
"LFU",
Expand Down
12 changes: 12 additions & 0 deletions libcachesim/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
CacheObject,
Cache,
# Core cache algorithms
LHD_init,
LRU_init,
FIFO_init,
LFU_init,
Expand Down Expand Up @@ -152,6 +153,17 @@ def _create_common_params(
# ------------------------------------------------------------------------------------------------
# Core cache algorithms
# ------------------------------------------------------------------------------------------------
class LHD(CacheBase):
"""Least Hit Density cache (no special parameters)"""

def __init__(
self, cache_size: int, default_ttl: int = 86400 * 300, hashpower: int = 24, consider_obj_metadata: bool = False
):
super().__init__(
_cache=LHD_init(_create_common_params(cache_size, default_ttl, hashpower, consider_obj_metadata))
)


class LRU(CacheBase):
"""Least Recently Used cache (no special parameters)"""

Expand Down
126 changes: 0 additions & 126 deletions scripts/smart_build.py

This file was deleted.

17 changes: 15 additions & 2 deletions src/export_cache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ namespace libcachesim {

namespace py = pybind11;

const cache_obj_t* LHD_HIT_MARKER = reinterpret_cast<cache_obj_t *>(0x1);

// Custom deleters for smart pointers
struct CacheDeleter {
void operator()(cache_t* ptr) const {
Expand Down Expand Up @@ -279,9 +281,20 @@ void export_cache(py::module& m) {
"req"_a)
.def(
"find",
[](cache_t& self, const request_t& req, const bool update_cache) {
[](cache_t& self, const request_t& req, const bool update_cache) -> py::object {
cache_obj_t* obj = self.find(&self, &req, update_cache);
return obj ? py::cast(obj, py::return_value_policy::reference) : py::none();
// Return None if obj is null (not found)
if (obj == nullptr) {
return py::none();
}
// NOTE(haocheng): For LHD only, return a dummy object for hit
if (obj == LHD_HIT_MARKER) {
cache_obj_t* dummy_obj = static_cast<cache_obj_t*>(calloc(1, sizeof(cache_obj_t)));
dummy_obj->obj_id = req.obj_id;
dummy_obj->obj_size = req.obj_size;
return py::cast(std::unique_ptr<cache_obj_t, CacheObjectDeleter>(dummy_obj));
}
return py::cast(obj, py::return_value_policy::reference);
},
"req"_a, "update_cache"_a = true)
.def(
Expand Down
2 changes: 1 addition & 1 deletion src/libCacheSim
11 changes: 10 additions & 1 deletion tests/test_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import os
from libcachesim import (
# Basic algorithms
LHD,
LRU,
FIFO,
LFU,
Expand Down Expand Up @@ -71,6 +72,7 @@ class TestCacheBasicFunctionality:
@pytest.mark.parametrize(
"cache_class",
[
LHD,
LRU,
FIFO,
LFU,
Expand Down Expand Up @@ -109,10 +111,14 @@ def test_cache_initialization(self, cache_class):
pytest.skip(f"Cache {cache_class.__name__} failed to initialize: {e}")

@pytest.mark.parametrize(
"cache_class", [LRU, FIFO, LFU, ARC, Clock, Random, S3FIFO, Sieve, LIRS, TwoQ, SLRU, WTinyLFU]
"cache_class", [LHD, LRU, FIFO, LFU, ARC, Clock, Random, S3FIFO, Sieve, LIRS, TwoQ, SLRU, WTinyLFU]
)
def test_basic_get_and_insert(self, cache_class):
"""Test basic get and insert operations"""
if cache_class == LHD:
pytest.skip("LHD's insert always returns None")


cache = cache_class(1024 * 1024) # 1MB cache

# Create a request
Expand Down Expand Up @@ -141,6 +147,7 @@ def test_basic_get_and_insert(self, cache_class):
@pytest.mark.parametrize(
"cache_class",
[
LHD,
LRU,
FIFO,
LFU,
Expand Down Expand Up @@ -192,6 +199,7 @@ def test_cache_eviction(self, cache_class):
@pytest.mark.parametrize(
"cache_class",
[
LHD,
LRU,
FIFO,
LFU,
Expand Down Expand Up @@ -239,6 +247,7 @@ def test_cache_find_method(self, cache_class):
@pytest.mark.parametrize(
"cache_class",
[
LHD,
LRU,
FIFO,
LFU,
Expand Down
Loading
Loading