blob: a819f9c7424ec47e8644b115ac508ff9437a3397 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
// hsdbg function-trace runtime.
//
// Build your program with -finstrument-functions and link this in; the compiler
// then calls the enter/exit hooks below on every function, and they append a
// timestamped record to a fixed ring buffer. hsdbg reads that buffer straight
// out of the live process and turns it into the flame-chart timeline, so no
// breakpoints and no hand-picking of functions are needed.
//
// clang -finstrument-functions -g your_prog.c hsdbg_trace.c -o your_prog
//
// The record layout and the three exported symbols are the contract hsdbg reads
// against; keep them in sync with the reader on the debugger side.
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C"
{
#endif
enum
{
HSDBG_TRACE_ENTER = 0,
HSDBG_TRACE_EXIT = 1,
// 1,048,576 records ~= 32 MB; plenty for a short profiled run
HSDBG_TRACE_CAPACITY = 1u << 20,
};
// 32 bytes, naturally aligned so hsdbg can read the array with one memory
// fetch and cast without worrying about padding differences
struct HsdbgTraceRecord
{
uint64_t timestamp_ns; // CLOCK_MONOTONIC nanoseconds
uint64_t function; // address of the entered/exited function
uint64_t thread_id; // pthread_threadid_np of the running thread
uint32_t kind; // HSDBG_TRACE_ENTER or HSDBG_TRACE_EXIT
uint32_t reserved;
};
// the ring buffer and how far it has been filled. hsdbg reads hsdbg_trace_head
// first, then the records below it; head is published only after a record's
// fields are fully written
extern struct HsdbgTraceRecord hsdbg_trace_records[HSDBG_TRACE_CAPACITY];
extern const uint64_t hsdbg_trace_capacity;
extern uint64_t hsdbg_trace_head; // total records ever written (monotonic)
#ifdef __cplusplus
}
#endif
|