Skip to content

Commit d6e67e7

Browse files
committed
fix outdated doc
1 parent c0522ed commit d6e67e7

10 files changed

Lines changed: 128 additions & 29 deletions

File tree

‎.gitignore‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,4 +233,5 @@ sftp-config.json
233233
CMakeFiles/*
234234
*.pyc
235235
!scripts/smart_build.py
236-
uv.lock
236+
uv.lock
237+
.claude/

‎docs/src/en/api.md‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@ Request(
4040

4141
### `CacheObject`
4242

43-
Returned by `Cache.find`, `insert`, `evict`, and `to_evict`. Exposes read-only `obj_id` and
44-
`obj_size`.
43+
Returned by `Cache.find`, `insert`, and `to_evict`. Exposes read-only `obj_id` and
44+
`obj_size`. Note that `evict` returns `None` — it delegates to the cache's `void` eviction
45+
callback, so use `to_evict` if you need to inspect the victim before it is removed.
4546

4647
## Enumerations
4748

@@ -210,7 +211,7 @@ PluginCache(
210211
```
211212

212213
Hook signatures are documented in [Plugin System](examples/plugins.md#plugincache).
213-
`set_hooks(...)` replaces the hooks on an existing instance.
214+
Hooks are fixed at construction time; build a new `PluginCache` to change them.
214215

215216
## Admission policies
216217

@@ -320,7 +321,10 @@ create_uniform_requests(num_objects, num_requests, obj_size=4000,
320321
time_span=604800, start_obj_id=0, seed=None) -> Iterator[Request]
321322
```
322323

323-
Both return an **iterator**, not a list; wrap in `list(...)` if you need to replay them twice.
324+
Both return a **re-iterable** generator object, not a list: each `for` loop over it starts a
325+
fresh pass, and with a fixed `seed` every pass yields the same sequence. There is no need to
326+
wrap them in `list(...)` to replay them, and for large workloads you should not — that
327+
materialises every `Request` at once.
324328

325329
## `TraceAnalyzer`
326330

‎docs/src/en/examples/analysis.md‎

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,32 @@ The constructor arguments are:
3636
!!! important
3737
The analyzer runs entirely in the C++ backend, so it only accepts a C-backed reader — in
3838
practice, [`TraceReader`](reader.md). Passing a `SyntheticReader` raises
39-
`ReaderException: Only C/C++ reader is supported`. To analyse a synthetic workload, write it
40-
out first with `Util.convert_to_oracleGeneral` and reopen it with `TraceReader`.
39+
`ReaderException: Only C/C++ reader is supported`. `Util.convert_to_oracleGeneral` cannot
40+
bridge the gap either — it takes a native reader, so handing it a `SyntheticReader` raises
41+
`TypeError`. To analyse a synthetic workload, write its requests out as a trace file and
42+
reopen that with `TraceReader`:
43+
44+
```py
45+
import libcachesim as lcs
46+
47+
synthetic = lcs.SyntheticReader(num_of_req=10000, obj_size=100, dist="zipf",
48+
alpha=1.0, num_objects=1000, seed=42)
49+
50+
with open("synthetic.csv", "w") as f:
51+
for req in synthetic:
52+
if not req.valid:
53+
break
54+
f.write(f"{req.clock_time},{req.obj_id},{req.obj_size}\n")
55+
56+
init_params = lcs.ReaderInitParam(has_header=False, delimiter=",", obj_id_is_num=True)
57+
init_params.time_field = 1
58+
init_params.obj_id_field = 2
59+
init_params.obj_size_field = 3
60+
61+
reader = lcs.TraceReader("synthetic.csv", lcs.TraceType.CSV_TRACE, init_params)
62+
analyzer = lcs.TraceAnalyzer(reader, "synthetic_analysis")
63+
analyzer.run()
64+
```
4165

4266
## Selecting analyses
4367

‎docs/src/en/getting_started/installation.md‎

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,16 +60,26 @@ bash scripts/install_deps.sh
6060
bash scripts/install_deps_user.sh
6161
```
6262

63-
Then reinstall, passing the options through `CMAKE_ARGS`. Add `--no-cache-dir` to force a
64-
rebuild rather than reusing a cached wheel:
63+
Then reinstall, passing the options through `CMAKE_ARGS`. The flags only take effect during a
64+
*source* build, so the install has to be forced to run one: `--no-cache-dir` on its own is not
65+
enough, because pip may report `Requirement already satisfied` or install a prebuilt wheel, and
66+
in either case `CMAKE_ARGS` is silently ignored. Build from the checkout instead:
6567

6668
```bash
6769
# Enable one algorithm
68-
CMAKE_ARGS="-DENABLE_LRB=ON" pip install libcachesim --no-cache-dir
70+
CMAKE_ARGS="-DENABLE_LRB=ON" pip install --force-reinstall .
6971

7072
# Or enable all three
7173
CMAKE_ARGS="-DENABLE_LRB=ON -DENABLE_3L_CACHE=ON -DENABLE_GLCACHE=ON" \
72-
pip install libcachesim --no-cache-dir
74+
pip install --force-reinstall .
75+
```
76+
77+
To build from PyPI rather than a checkout, also disable wheels so that a source build actually
78+
happens:
79+
80+
```bash
81+
CMAKE_ARGS="-DENABLE_LRB=ON" \
82+
pip install --force-reinstall --no-binary libcachesim libcachesim
7383
```
7484

7585
!!! important
@@ -101,10 +111,27 @@ bash scripts/install.sh
101111
bash scripts/install.sh --all
102112
```
103113

104-
Building the extension requires a C++17 compiler, CMake ≥ 3.15, and Ninja. The build is driven
105-
by [scikit-build-core](https://scikit-build-core.readthedocs.io/), which configures and builds
106-
the bundled C library before compiling the [pybind11](https://pybind11.readthedocs.io/)
107-
bindings.
114+
Building the extension requires a C++17 compiler, CMake ≥ 3.15, and Ninja, plus three native
115+
dependencies that CMake looks for at configure time: **pkg-config**, **GLib 2.0** and
116+
**Zstandard**. All three are mandatory — `CMakeLists.txt` declares them with
117+
`find_package(PkgConfig REQUIRED)`, `pkg_check_modules(GLib REQUIRED glib-2.0)` and
118+
`find_package(ZSTD REQUIRED)` — and a missing one aborts configuration before any code is
119+
compiled, with an error such as `No package 'glib-2.0' found`.
120+
121+
The dependency scripts above install them on the platforms they cover (`install_deps.sh` targets
122+
yum-based distributions and macOS). On Debian/Ubuntu, use the submodule's script or install them
123+
directly:
124+
125+
```bash
126+
bash src/libCacheSim/scripts/install_dependency.sh
127+
128+
# or, the minimum needed to configure the build
129+
sudo apt install -y pkg-config libglib2.0-dev libzstd-dev
130+
```
131+
132+
The build itself is driven by [scikit-build-core](https://scikit-build-core.readthedocs.io/),
133+
which configures and builds the bundled C library before compiling the
134+
[pybind11](https://pybind11.readthedocs.io/) bindings.
108135

109136
## Troubleshooting
110137

‎docs/src/zh/api.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ Request(
3838

3939
### `CacheObject`
4040

41-
由 `Cache.find`、`insert`、`evict` 和 `to_evict` 返回,暴露只读的 `obj_id` 和 `obj_size`。
41+
由 `Cache.find`、`insert` 和 `to_evict` 返回,暴露只读的 `obj_id` 和 `obj_size`。注意 `evict` 返回的是 `None`——它转发到缓存的 `void` 淘汰回调;若需要在对象被移除前查看淘汰候选,请使用 `to_evict`。
4242

4343
## 枚举类型
4444

@@ -192,7 +192,7 @@ PluginCache(
192192
)
193193
```
194194

195-
各 hook 的签名见[插件系统](examples/plugins.md#plugincache)。`set_hooks(...)` 可以替换已有实例上的 hook。
195+
各 hook 的签名见[插件系统](examples/plugins.md#plugincache)。hook 在构造时固定,如需更换请新建一个 `PluginCache`。
196196

197197
## 准入策略
198198

@@ -289,7 +289,7 @@ create_uniform_requests(num_objects, num_requests, obj_size=4000,
289289
time_span=604800, start_obj_id=0, seed=None) -> Iterator[Request]
290290
```
291291

292-
两者返回的都是**迭代器**而非列表;如果需要重复回放,请用 `list(...)` 包一层。
292+
两者返回的都是**可重复迭代**的生成器对象而非列表:每次 `for` 循环都会重新开始一轮,且在固定 `seed` 下每轮产生的序列完全相同。因此无需用 `list(...)` 包一层来重复回放;对于大规模负载更不应这样做,否则会一次性把所有 `Request` materialize 到内存中。
293293

294294
## `TraceAnalyzer`
295295

‎docs/src/zh/examples/analysis.md‎

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,29 @@ analyzer.run()
3030
- `analysis_param: AnalysisParam`(可选)——这些分析的调节参数。默认为 `AnalysisParam()`。
3131

3232
!!! important
33-
分析器完全运行在 C++ 后端,因此只接受由 C 实现的 reader——实际上就是 [`TraceReader`](reader.md)。传入 `SyntheticReader` 会抛出 `ReaderException: Only C/C++ reader is supported`。若要分析合成负载,请先用 `Util.convert_to_oracleGeneral` 将其写出,再用 `TraceReader` 重新打开。
33+
分析器完全运行在 C++ 后端,因此只接受由 C 实现的 reader——实际上就是 [`TraceReader`](reader.md)。传入 `SyntheticReader` 会抛出 `ReaderException: Only C/C++ reader is supported`。`Util.convert_to_oracleGeneral` 也无法作为桥梁——它接受的是原生 reader,传入 `SyntheticReader` 会抛出 `TypeError`。若要分析合成负载,请先把它的请求写成 trace 文件,再用 `TraceReader` 打开:
34+
35+
```py
36+
import libcachesim as lcs
37+
38+
synthetic = lcs.SyntheticReader(num_of_req=10000, obj_size=100, dist="zipf",
39+
alpha=1.0, num_objects=1000, seed=42)
40+
41+
with open("synthetic.csv", "w") as f:
42+
for req in synthetic:
43+
if not req.valid:
44+
break
45+
f.write(f"{req.clock_time},{req.obj_id},{req.obj_size}\n")
46+
47+
init_params = lcs.ReaderInitParam(has_header=False, delimiter=",", obj_id_is_num=True)
48+
init_params.time_field = 1
49+
init_params.obj_id_field = 2
50+
init_params.obj_size_field = 3
51+
52+
reader = lcs.TraceReader("synthetic.csv", lcs.TraceType.CSV_TRACE, init_params)
53+
analyzer = lcs.TraceAnalyzer(reader, "synthetic_analysis")
54+
analyzer.run()
55+
```
3456

3557
## 选择分析项 {#selecting-analyses}
3658

‎docs/src/zh/getting_started/installation.md‎

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,22 @@ bash scripts/install_deps.sh
5656
bash scripts/install_deps_user.sh
5757
```
5858

59-
然后通过 `CMAKE_ARGS` 传入选项重新安装。加上 `--no-cache-dir` 可以强制重新构建,而不是复用缓存的 wheel:
59+
然后通过 `CMAKE_ARGS` 传入选项重新安装。这些选项只在**源码构建**时生效,因此必须强制走源码构建:仅加 `--no-cache-dir` 是不够的,pip 仍可能提示 `Requirement already satisfied` 或直接安装预编译 wheel,这两种情况下 `CMAKE_ARGS` 都会被静默忽略。请改为从当前 checkout 构建:
6060

6161
```bash
6262
# 启用单个算法
63-
CMAKE_ARGS="-DENABLE_LRB=ON" pip install libcachesim --no-cache-dir
63+
CMAKE_ARGS="-DENABLE_LRB=ON" pip install --force-reinstall .
6464

6565
# 或者三个全部启用
6666
CMAKE_ARGS="-DENABLE_LRB=ON -DENABLE_3L_CACHE=ON -DENABLE_GLCACHE=ON" \
67-
pip install libcachesim --no-cache-dir
67+
pip install --force-reinstall .
68+
```
69+
70+
若要从 PyPI 而不是 checkout 构建,还需要禁用 wheel,确保真正执行源码构建:
71+
72+
```bash
73+
CMAKE_ARGS="-DENABLE_LRB=ON" \
74+
pip install --force-reinstall --no-binary libcachesim libcachesim
6875
```
6976

7077
!!! important
@@ -90,7 +97,18 @@ bash scripts/install.sh
9097
bash scripts/install.sh --all
9198
```
9299

93-
构建扩展需要支持 C++17 的编译器、CMake ≥ 3.15 以及 Ninja。构建过程由 [scikit-build-core](https://scikit-build-core.readthedocs.io/) 驱动,它会先配置并构建内置的 C 库,再编译 [pybind11](https://pybind11.readthedocs.io/) 绑定。
100+
构建扩展需要支持 C++17 的编译器、CMake ≥ 3.15 以及 Ninja,另外还需要三个在 configure 阶段查找的原生依赖:**pkg-config**、**GLib 2.0** 和 **Zstandard**。这三者都是必需的——`CMakeLists.txt` 中分别以 `find_package(PkgConfig REQUIRED)`、`pkg_check_modules(GLib REQUIRED glib-2.0)` 和 `find_package(ZSTD REQUIRED)` 声明——缺少任意一个都会在编译任何代码之前中断配置,并报出类似 `No package 'glib-2.0' found` 的错误。
101+
102+
上文的依赖脚本会在其支持的平台上安装它们(`install_deps.sh` 面向基于 yum 的发行版和 macOS)。在 Debian/Ubuntu 上,请使用子模块提供的脚本,或直接安装:
103+
104+
```bash
105+
bash src/libCacheSim/scripts/install_dependency.sh
106+
107+
# 或者只装配置构建所需的最小集合
108+
sudo apt install -y pkg-config libglib2.0-dev libzstd-dev
109+
```
110+
111+
构建本身由 [scikit-build-core](https://scikit-build-core.readthedocs.io/) 驱动,它会先配置并构建内置的 C 库,再编译 [pybind11](https://pybind11.readthedocs.io/) 绑定。
94112

95113
## 疑难排查
96114

‎libcachesim/__init__.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from .libcachesim_python import (
66
Cache,
7+
CacheObject,
78
Request,
89
ReqOp,
910
ReaderInitParam,
@@ -77,6 +78,7 @@
7778
__all__ = [
7879
# Core classes
7980
"Cache",
81+
"CacheObject",
8082
"Request",
8183
"ReqOp",
8284
"ReaderInitParam",

‎libcachesim/__init__.pyi‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ from __future__ import annotations
22
from typing import Optional, Callable, Any
33
from collections.abc import Iterator
44

5-
from .libcachesim_python import ReqOp, TraceType, SamplerType
5+
from .libcachesim_python import Reader, ReqOp, TraceType, SamplerType
66
from .protocols import ReaderProtocol
77

88
class Request:
@@ -131,7 +131,7 @@ class Cache:
131131
def can_insert(self, req: Request) -> bool: ...
132132
def insert(self, req: Request) -> CacheObject: ...
133133
def need_eviction(self, req: Request) -> bool: ...
134-
def evict(self, req: Request) -> CacheObject: ...
134+
def evict(self, req: Request) -> None: ...
135135
def remove(self, obj_id: int) -> bool: ...
136136
def to_evict(self, req: Request) -> CacheObject: ...
137137
def get_occupied_byte(self) -> int: ...
@@ -146,7 +146,7 @@ class CacheBase:
146146
def can_insert(self, req: Request) -> bool: ...
147147
def insert(self, req: Request) -> CacheObject: ...
148148
def need_eviction(self, req: Request) -> bool: ...
149-
def evict(self, req: Request) -> CacheObject: ...
149+
def evict(self, req: Request) -> None: ...
150150
def remove(self, obj_id: int) -> bool: ...
151151
def to_evict(self, req: Request) -> CacheObject: ...
152152
def get_occupied_byte(self) -> int: ...
@@ -334,14 +334,13 @@ class PluginCache(CacheBase):
334334
admissioner: Optional["AdmissionerBase"] = None,
335335
reader: Optional[ReaderProtocol] = None,
336336
): ...
337-
def set_hooks(self, init_hook, hit_hook, miss_hook, eviction_hook, remove_hook, free_hook=None): ...
338337

339338
# Readers
340339
class TraceReader(ReaderProtocol):
341340
c_reader: bool
342341
def __init__(
343342
self,
344-
trace: str,
343+
trace: Reader | str,
345344
trace_type: TraceType = TraceType.UNKNOWN_TRACE,
346345
reader_init_params: Optional[ReaderInitParam] = None,
347346
): ...

‎libcachesim/cache.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ def insert(self, req: Request) -> CacheObject:
7777
def need_eviction(self, req: Request) -> bool:
7878
return self._cache.need_eviction(req)
7979

80-
def evict(self, req: Request) -> CacheObject:
80+
def evict(self, req: Request) -> None:
81+
# The C eviction callback returns void, so this is always None; use
82+
# to_evict() to inspect the victim before it is removed.
8183
return self._cache.evict(req)
8284

8385
def remove(self, obj_id: int) -> bool:

0 commit comments

Comments
 (0)