Files
hakmem/core/ptr_trace.h
Moe Charm (CI) 002a9a7d57 Debug-only pointer tracing macros (PTR_NEXT_READ/WRITE) + integration in TLS-SLL box
- Add core/ptr_trace.h (ring buffer, env-controlled dump)
- Use macros in box/tls_sll_box.h push/pop/splice
- Default: enabled for debug builds, zero-overhead in release
- How to use: build debug and run with HAKMEM_PTR_TRACE_DUMP=1
2025-11-10 18:25:05 +09:00

94 lines
3.4 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ptr_trace.h - Pointer link read/write tracing (Debug-only, macro-replaceable)
//
// Purpose:
// - Centrally instrument single-linked list next pointer reads/writes
// - Zero overhead in release builds (macros devolve to raw ops)
// - Compact TLS ring for triage; optional dump at exit via env
//
// Usage:
// - Replace direct next ops with PTR_NEXT_WRITE / PTR_NEXT_READ
// - Tag with a short literal (e.g., "tls_push", "tls_pop", "splice")
// - Offsets should be header-aware (C0C6: +1, C7: +0)
//
// Control:
// - Compile-time: HAKMEM_PTR_TRACE (default: 1 for debug, 0 for release)
// - Runtime dump: HAKMEM_PTR_TRACE_DUMP=1 (prints ring at exit)
#pragma once
#include <stdint.h>
#include <stddef.h>
#ifndef HAKMEM_PTR_TRACE
# if !HAKMEM_BUILD_RELEASE
# define HAKMEM_PTR_TRACE 1
# else
# define HAKMEM_PTR_TRACE 0
# endif
#endif
#if HAKMEM_PTR_TRACE
#include <stdio.h>
typedef struct {
const char* tag; // literal tag
int class_idx; // tiny class (0..7)
void* node; // node address (base)
void* val; // written/read value
size_t off; // offset used for access
} ptr_trace_ev_t;
#ifndef PTR_TRACE_CAP
# define PTR_TRACE_CAP 256
#endif
static __thread ptr_trace_ev_t g_ptr_trace_ring[PTR_TRACE_CAP];
static __thread uint32_t g_ptr_trace_idx = 0;
static __thread int g_ptr_trace_dump_registered = 0;
static inline void ptr_trace_record(const char* tag, int cls, void* node, void* val, size_t off) {
uint32_t i = g_ptr_trace_idx++;
g_ptr_trace_ring[i & (PTR_TRACE_CAP - 1)] = (ptr_trace_ev_t){ tag, cls, node, val, off };
}
static inline void ptr_trace_try_register_dump(void) {
if (g_ptr_trace_dump_registered) return;
g_ptr_trace_dump_registered = 1;
const char* env = getenv("HAKMEM_PTR_TRACE_DUMP");
if (!(env && *env && *env != '0')) return;
static void __attribute__((destructor)) ptr_trace_dump(void) {
fprintf(stderr, "\n[PTR_TRACE_DUMP] last=%u (cap=%u)\n", g_ptr_trace_idx, (unsigned)PTR_TRACE_CAP);
uint32_t n = (g_ptr_trace_idx < PTR_TRACE_CAP) ? g_ptr_trace_idx : PTR_TRACE_CAP;
for (uint32_t k = 0; k < n; k++) {
const ptr_trace_ev_t* e = &g_ptr_trace_ring[(g_ptr_trace_idx - n + k) & (PTR_TRACE_CAP - 1)];
fprintf(stderr, "[%3u] tag=%s cls=%d node=%p val=%p off=%zu\n",
k, e->tag ? e->tag : "?", e->class_idx, e->node, e->val, e->off);
}
}
}
#define PTR_NEXT_WRITE(tag, cls, node, off, value) do { \
void** __p = (void**)((uint8_t*)(node) + (off)); \
*__p = (value); \
ptr_trace_record((tag), (cls), (node), (value), (off)); \
ptr_trace_try_register_dump(); \
} while(0)
#define PTR_NEXT_READ(tag, cls, node, off, out_var) do { \
void** __p = (void**)((uint8_t*)(node) + (off)); \
(out_var) = *__p; \
ptr_trace_record((tag), (cls), (node), (out_var), (off)); \
ptr_trace_try_register_dump(); \
} while(0)
#else // HAKMEM_PTR_TRACE == 0
#define PTR_NEXT_WRITE(tag, cls, node, off, value) \
(*(void**)((uint8_t*)(node) + (off)) = (value))
#define PTR_NEXT_READ(tag, cls, node, off, out_var) \
((out_var) = *(void**)((uint8_t*)(node) + (off)))
#endif // HAKMEM_PTR_TRACE