|
CCTLib
Calling-context and data-object attribution library for Intel Pin
|
CCTLib is a library that ubiquitously collects calling contexts for every instruction executed by an application, and attributes costs to the specific data objects those instructions touch. It runs on top of Intel Pin as a runtime library and turns any Pin tool into a context-aware profiler with a few lines of glue code.
Doxygen API reference: https://cctlib.github.io/cctlib/
Install these before building:
g++ >= 10 (Pin 4.x recommends this)autoconf, automake, libtoolunzip, tar, curl (for the bundled build.sh dependency setup)build.sh unpacks externals/{libelf-0.8.9,sparsehash-2.0.3-95e5e93,json-v3.7.3}, configures, and runs make -j followed by make check. It produces:
src/obj-intel64/libcctlib.a — shadow-memory-based data-centric attribution.src/obj-intel64/libcctlib_tree_based.a — balanced-binary-tree-based attribution.src/obj-intel64/libcctlib_metric.a — per-IPNode custom metric slots.Refer to Chabbi, Liu & Mellor-Crummey (CGO 2014) for the algorithmic details.
Actively maintained. Recent work covers a clean C++-exception unwind implementation (Itanium ABI landing-pad re-anchor), a direct-self- recursion collapse for the CCT, a shape-inspection pintool (clients/cct_shape_check.cpp) plus 22 gtest-driven shape victims, and continuous integration for clang-format + clang-tidy.
There is also a successor project, DrCCTProf, built on top of DynamoRIO with broader platform coverage. CCTLib remains the reference implementation on Pin and stays maintained for that use case.
Full API documentation is generated by Doxygen (make docs, or the auto-published copy linked above). The load-bearing entry points:
INTERESTING_INS_ALL is a predefined callback that returns true for every instruction. Alternatives:
INTERESTING_INS_MEMORY_ACCESS — only load/store instructions.INTERESTING_INS_NONE — only function and call-site granularity.BOOL (*)(INS) predicate for finer selection.Full working code lives in tests/cct_client.cpp and the many clients/*.cpp tools.
tests/ — minimal examples:
| File | What it does |
|---|---|
cct_client.cpp | Gather calling context on every instruction. |
cct_client_mem_only.cpp | Gather calling context on every memory access. |
cct_data_centric_client.cpp | Data-centric attribution via shadow memory. |
cct_data_centric_client_tree_based.cpp | Data-centric attribution via balanced BST. |
clients/ — production-scale tools:
| File | What it does |
|---|---|
deadspy_client.cpp | DeadSpy: pinpoint dead writes with full context. |
redspy_client.cpp | RedSpy: value-locality-based redundancy detection. |
loadspy_client.cpp | LoadSpy: redundant loads. |
zerospy_client.cpp | ZeroSpy: redundant zeros in loads. |
footprint_client.cpp | Memory footprint by call context. |
cache_client.cpp | Simulated cache miss attribution. |
ins_reuse_client.cpp | Instruction reuse distance. |
omp_datarace_client.cpp | OpenMP data-race detection. |
runtime_value_numbering_client.cpp | Runtime value numbering for redundant computation. |
cct_metric_client.cpp | Per-IPNode custom-metric skeleton. |
cctlib_reader.cpp | Read serialized CCT for postmortem analysis. |
cct_shape_check.cpp | CCT-shape assertion tool for the gtest suites. |
CCTLib carries an extensive gtest suite in tests/gtest/:
Includes:
cct_shape_check.cpp assert on structural CCT invariants (marker attribution under landing-pad re-anchor, direct-self-recursion collapse under nested throw+rethrow, no throw-machinery ancestors under catch/try markers).Set CCTLIB_EXPENSIVE_SHAPE=1 to include the four stress victims (high-iteration throw loops).
The tree uses .clang-format (LLVM base, 4-space indent, attached braces, no reflow) and .clang-tidy (bugprone-*, performance-*, readability-*, modernize-* families with a documented exclude list for invasive checks).
make format — reformat all C/C++ sources in place.make format-check — fail if any file would change (used by CI).make lint — run clang-tidy on the full source set; requires a compile_commands.json produced by bear -- make.Opt-in per clone:
This sets core.hooksPath to .githooks/, so every git commit runs clang-format-15 on the staged C/C++ files and auto-re-stages what it changes. See .githooks/README.md. Bypass with git commit --no-verify. Uninstall with git config --unset core.hooksPath.
.github/workflows/lint.yml runs on every push to master and every PR:
clang-format --dry-run --Werror on all C/C++ sources.clang-tidy on the full source set (with Pin installed via the cached Intel tarball)..github/workflows/docs.yml builds the Doxygen output on every push to master and publishes it to the gh-pages branch.
MAX_IPNODES — maximum number of call-path handles (default 1 << 32). Virtual address space is reserved eagerly; physical memory is committed on demand. Lower it with -DMAX_IPNODES=<num> if you run into VM limits.MAX_STRING_POOL_NODES — maximum number of distinct variable names in data-centric analysis (default 1 << 30). Same eager-reserve / lazy-commit story; lower with -DMAX_STRING_POOL_NODES=<num>.How do I build for CCTLib development? Pass --enable-develop to ./configure (or edit build.sh to add the flag before it runs ./configure).
How do I cite CCTLib? Chabbi, Liu, Mellor-Crummey. Call Paths for Pin Tools. CGO 2014. DOI: 10.1145/2544137.2544164.