Directives
One directive per line. # starts a comment; blank lines are ignored. With
no directives at all, everything is instrumented.
| Directive | Effect |
|---|---|
include <pattern> |
Only instrument matching sources. With no include line, every source is included. |
exclude <pattern> |
Never instrument matching sources — or headers: the compiler matches the file a function is defined in, so a header path silences its inline/static helpers. Exclude always wins over include. |
exclude-func <name> |
Never instrument functions whose (mangled) name contains <name> — the compiler's match is a substring match, so be specific. |
include-func <name> [depth] |
Instrument <name> and its whole call subtree, resolved statically from your sources. Optional depth: 0 = just that function, 1 = direct callees, default = the full subtree. |
counter <events> |
Hardware events to count, comma-separated — at most three. See hardware counters. |
counter-func <name> [depth] |
Count <name>, and optionally its call subtree — the same walk include-func uses. Only instrumented functions can be counted. |
counter-file <pattern> |
Count every instrumented function defined in matching files. |
counter-min auto|<ns>|0 |
Skip counting functions shorter than this. auto (the default) derives it from the measured cost of one counter read; 0 disables the guard. |
counter ones
decide what gets read from those hooks, which is resolved after the
link and needs no rebuild at all — so you can re-point counters at different functions
and just run again.
Pattern matching
A pattern matches a source path when it matches the full path or any trailing part
of it — so src/utils/rng.c also matches
../project/src/utils/rng.c, whatever path your build passes to the
compiler.
| Kind | Examples |
|---|---|
| glob | src/net/** · *test*.c · rng.c |
| exact path | src/utils/rng.c |
| directory prefix | src/sort · src/sort/ |
Three levels of selection
From coarsest to finest. The first two are compile-time and therefore free at runtime; the third is a runtime filter that needs no rebuild.
1 · File and folder
include / exclude patterns. The bluntest and cheapest
instrument: whole translation units are compiled with or without hooks.
include src/network/
exclude src/network/crc.c
2 · Function and call subtree
include-func names an entry point — a task, a request handler, a
workload — and callsight parses your sources, builds a static call graph, and instruments
exactly the reachable subtree. Everything else defined in those files, including helpers
defined in headers, is excluded by name at compile time.
$ callsight select src/ --function workload_sort
workload_sort: 31 functions across 6 files (full depth)
heapsort
mergesort
qs_partition
qs_swap
…
# add to trace.config:
include-func workload_sort
Explore before committing: --depth 1 to see just the direct callees,
--list to dump every function callsight can see.
3 · Thread
A runtime filter, matched against the thread name set with
pthread_setname_np. No rebuild required.
$ TRACE_THREADS="sort-*,worker-1" TRACE_ENABLE=1 ./yourapp.instr
The name is checked at the thread's first hook call and re-checked periodically, since
threads commonly set their name after starting. Expect a handful of
unmatched_exits at activation for late-named threads — the events from before
the thread matched are absent by design.
Strategy at scale
Event volume is the main cost. A call-heavy program easily generates millions of events per second, and the analyzer's job gets harder the more noise you feed it. The levers, cheapest first:
- Compile-time excludes. Run wide once, sort the report by
calls, exclude the chatty leaf helpers, rebuild. Typically cuts volume 10–100× while keeping the structural picture intact. includedirectives. Instrument only the subsystem under investigation —include src/network/.include-func. One entry point, its exact call subtree, nothing else.- Runtime gating.
TRACE_ENABLEandTRACE_MAXcontrol when and how much you pay;TRACE_THREADSnarrows to the threads that matter. - Source opt-out (the only one that touches your code):
__attribute__((no_instrument_function))on a single function.
Preview any config without building:
$ callsight scan src/ --config trace.config
35 sources: 34 instrumented, 1 excluded (config: trace.config)
excluded: src/utils/rng.c
Runtime knobs
Environment variables read once, at the first hook call.
| Variable | Default | Meaning |
|---|---|---|
TRACE_ENABLE | off | 1 enables collection; hooks are inert otherwise |
TRACE_DIR | ./traces | Output directory (file mode) |
TRACE_MAX | 0 (unlimited) | Global event cap — always set one for long runs |
TRACE_THREADS | unset (all) | Comma-separated globs on thread names, e.g. sort-* |
TRACE_SHM | unset | Streaming mode: POSIX shm ring name, e.g. /callsight0 |
TRACE_SHM_SIZE | 16 MiB | Ring capacity in bytes |
A worked example
The selection used by the bundled matrixlab fixture — three lines that cut
a noisy trace down to a readable one:
# trace.config
exclude src/utils/rng.c # RNG helpers dominate call volume: pure noise
exclude src/signal/fft.h # header-inline helpers defined in fft.h
exclude-func crc32_update # one hot function, by name
# Exact instruction counts for the matrix work, and nothing too short
# to measure honestly.
counter instructions
counter-file src/matrix/**
counter-min auto
Which becomes, at build time:
-finstrument-functions
-finstrument-functions-exclude-file-list=src/utils/rng.c,src/signal/fft.h
-finstrument-functions-exclude-function-list=crc32_update
Generate it by clicking
If you'd rather not write patterns by hand, the web UI's config builder enumerates every source file and function in the project and writes the config from your checkboxes — see the Web UI page.