一键导入
dftracer-annotate-general
Language-agnostic dftracer annotation rules — Rule 0 (what to skip), coverage, error paths, backend priority order, and wrapper handling
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Language-agnostic dftracer annotation rules — Rule 0 (what to skip), coverage, error paths, backend priority order, and wrapper handling
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Communication-component (MPI/collective/network) bottleneck-to-optimization mappings, papers, and L1/L2/L3 strategies for the dftracer optimization pipeline
Compute-component bottleneck-to-optimization mappings, papers, and L1/L2/L3 strategies for the dftracer optimization pipeline
Key literature, bottleneck-to-optimization mappings, and strategies for the dftracer I/O optimization pipeline
Memory-component bottleneck-to-optimization mappings, papers, and L1/L2/L3 strategies for the dftracer optimization pipeline
VPIC-Kokkos-specific knowledge: build/annotation quirks, the two-stage deck-compile pattern, deck sizing for smoke vs validation runs, and the measured MPI-communication-bound diagnosis on Tuolumne. Load this skill whenever working with vpic-kokkos (github.com/lanl/vpic-kokkos).
Install and build dftracer into the session using the MCP install tool and record tool pitfalls early.
| name | dftracer-annotate-general |
| description | Language-agnostic dftracer annotation rules — Rule 0 (what to skip), coverage, error paths, backend priority order, and wrapper handling |
These rules apply whenever you manually annotate C, C++, or Python source files. Violating any rule will cause build failures or missing trace data.
Annotate a function if it:
open, read, write, close, fread, fwrite,
mmap, send, recv, MPI_File_*, MPI_Send, MPI_Recv, …)malloc/free of buffers > a few KB)main, run_test, benchmark_*)Skip a function if it:
Always annotate, even if they look small:
*_init, *_final, *_initialize, *_finalize,
*_open_backend, *_close_backend) — Never apply Rule 0 to lifecycle functions.*_Fsync, *_Sync, *_Flush)*_Delete, *_Rename, *_Mknod, *_GetFileSize)gpfs_*, beegfs_*, lustre_*, hdfs_*,
ceph_*, daos_*) — annotate as comp="io"After annotating the public API, always scan the whole file for unannotated helpers.
Syscall triggers — if a function body contains any of these, it is an I/O function:
| Trigger call | Category |
|---|---|
open(), read(), write(), close(), stat() | POSIX syscall |
mknod(), mkstemp(), unlink(), rename() | File lifecycle |
ioctl(), fcntl() | Kernel I/O control |
gpfs_fcntl(), beegfs_getStripeInfo(), llapi_*() | Vendor FS |
cuFileHandleRegister(), cuFileRead(), cuFileWrite() | GPU Direct |
MPI_File_*() | MPI-IO |
Workflow:
# Step 1 — list definitions
grep -n "^[a-zA-Z_].*(.*)$" src/foo.c | grep -v ";"
# Step 2 — cross-reference against annotated list
awk '/^[a-zA-Z_].*\(/ {func=NR": "$0} /DFTRACER_C_FUNCTION_START/ {print func}' annotated/src/foo.c
# Step 3 — for any definition not in Step 2, check body for syscall triggers
The default is to annotate. Skip requires justification.
Permanent skip conditions (Rule 0):
After annotating a file, verify coverage:
grep -c "^[a-zA-Z].*(.*)$\|^[a-zA-Z].* (\*" src/foo.c # rough definition count
grep -c "DFTRACER_C_FUNCTION_START" annotated/src/foo.c # START count
clang_annotate_file now writes its result to disk immediately by
default (write_immediately=True, the default — do not pass
write_immediately=False unless you are deliberately doing a multi-step
add-braces → annotate → syntax-check → write compose pipeline). A single
call is sufficient: the response includes written_to_disk: true,
bytes_written, and disk_mtime_ns confirming real bytes landed on disk.
This is the primary, structural fix for the failure mode where an agent
called the tool, got a plausible "N insertions" response, and reported full
success to the orchestrator without anything ever being written to disk
(because the old version only mutated an in-memory cache and required a
separate, easily-forgotten clang_write_annotated_file call). That failure
mode is now closed at the tool level, not by agent discipline.
Two things remain worth checking as defense-in-depth, not as the primary safeguard:
Check written_to_disk in the response. If it is false, you (or a
prior step) explicitly passed write_immediately=False — you MUST still
call clang_write_annotated_file before moving on, or the change is lost.
already_annotated: true ground-truthing. clang_annotate_file keeps
an in-memory file cache (keyed by run_id + relative path) so multiple
tool calls can collaborate on one file without extra disk round-trips. The
cache is invalidated whenever the file's on-disk mtime changes underneath
it, but there is one situation this cannot fully protect against: if a
source tree is deleted and re-copied mid-session at the same path fast
enough, or via a path the MCP process never directly stat()s between
calls, a stale cache entry can still cause the tool to report
already_annotated: true (0 insertions) even though the file on disk
currently has zero dftracer macros. This happened during an h5bench
session where the source tree was reset mid-pipeline — the tool silently
no-op'd an entire annotation stage.
After ANY response that reports already_annotated: true (or a
suspiciously low insertion count), ground-truth it before trusting it:
# C — expect at least one hit per already-annotated file
grep -rl "DFTRACER_C_INIT" annotated/
# C++
grep -rl "DFTRACER_CPP_INIT\|DFTRACER_CPP_FUNCTION" annotated/
# Python
grep -rl "DFTRACER_PY_INIT\|dftracer" annotated/*.py
If grep finds zero matches despite already_annotated: true, the
cache is stale — re-run the annotation call. This is especially important
immediately after any source tree reset/re-copy/re-clone mid-session (e.g.
after a build failure recovery that wipes source/ or annotated/ and
repopulates it from scratch).
// ✅ Correct — END before the explicit return you can see
int my_fn(const char *path) {
DFTRACER_C_FUNCTION_START();
int fd = open(path, O_RDONLY);
if (fd < 0) {
DFTRACER_C_FUNCTION_END(); // ← explicit return you can see
return -1;
}
DFTRACER_C_FUNCTION_END();
return 0;
}
// ✅ Correct — don't add END before macro; the macro's internal return is invisible
int mpi_fn(MPI_File *fh, const char *path) {
DFTRACER_C_FUNCTION_START();
MPI_CHECK(MPI_File_open(...), "open failed"); // ← no END here
DFTRACER_C_FUNCTION_END();
return 0;
}
// ✅ Correct — goto pattern: single END at the label covers all paths
int hdf5_fn(const char *path) {
DFTRACER_C_FUNCTION_START();
if ((fid = H5Fopen(...)) < 0) goto done;
done:
DFTRACER_C_FUNCTION_END(); // ← one END at label covers all goto paths
return ret;
}
When a higher-level function delegates to a lower-level annotated function, annotate BOTH:
MMAP_Xfer() ← annotate (captures MMAP-level intent)
└─ POSIX_Xfer() ← also annotated (captures syscall-level detail)
Build and run a smoke test for each backend immediately after annotating it.
Fortran codes (e.g. Flash-X, many HPC multiphysics codes) have a Fortran program
entry point, not a C main(). This means DFTRACER_C_INIT/DFTRACER_C_FINI cannot be
placed in the application source.
Solution for FUNCTION/HYBRID mode: Create a separate C wrapper file with constructor/destructor attributes:
#include <stddef.h>
#include <dftracer/dftracer.h>
__attribute__((constructor)) static void dftracer_init(void) {
DFTRACER_C_INIT(NULL, NULL, NULL);
}
__attribute__((destructor)) static void dftracer_fini(void) {
DFTRACER_C_FINI();
}
Compile to .o and link it into the final binary (e.g. add to ALL_OBJ_FILES in
GNU Make, or to the link line). The constructor runs before program starts; the
destructor runs after exit.
Fallback: Some Fortran linkers (observed: CCE crayftn) do not reliably fire
constructor attributes. If FUNCTION mode produces empty traces despite the wrapper
being linked, pivot to PRELOAD mode — it captures HDF5/POSIX/MPI I/O at the
library level without requiring INIT/FINI in the application. See
[[dftracer-preload-run]] and [[dftracer-annotation-lessons]] PF1.
gpfs_*, beegfs_*, lustre_*) included as comp="io"