AtlatestRepositorysigil-wm

sigil-wm / tree / src / ctrace-records.h

1/* SPDX-License-Identifier: BSD-3-Clause
2 * Bounded diagnostics: neither producers nor the consumer wait for a lock.
3 * The native owner alone owns per-output causal commit associations. */
4#define TRACE_RECORDS 8192
5#define TRACE_CAUSES 64
6#define TRACE_COMMITS 64
7struct trace_record { uint64_t stage, ns, correlation, object, sequence; };
8static struct {
9 atomic_bool enabled;
10 atomic_flag busy;
11 atomic_uint_fast64_t dropped;
12 unsigned read, write;
13 struct trace_record records[TRACE_RECORDS];
14} trace = {.busy=ATOMIC_FLAG_INIT};
15struct trace_commit {
16 uint32_t sequence;
17 unsigned count;
18 uint64_t causes[TRACE_CAUSES];
19};
20struct trace_output {
21 unsigned count;
22 uint64_t causes[TRACE_CAUSES];
23 struct trace_commit commits[TRACE_COMMITS];
24};
25static void trace_drop(uint64_t count) { atomic_fetch_add_explicit(&trace.dropped,count,memory_order_relaxed); }
26static bool trace_record_at(int stage,uint64_t correlation,uint64_t object,uint64_t sequence,
27 const struct timespec *timestamp) {
28 if(!atomic_load_explicit(&trace.enabled,memory_order_relaxed)) return false;
29 if(atomic_flag_test_and_set_explicit(&trace.busy,memory_order_acquire)) {
30 trace_drop(1); return false;
31 }
32 bool written=false;
33 if(trace.write-trace.read<TRACE_RECORDS) {
34 struct timespec now;
35 if(timestamp) now=*timestamp; else clock_gettime(CLOCK_MONOTONIC,&now);
36 trace.records[trace.write++%TRACE_RECORDS]=(struct trace_record){
37 stage,(uint64_t)now.tv_sec*1000000000ULL+now.tv_nsec,correlation,object,sequence};
38 written=true;
39 } else trace_drop(1);
40 atomic_flag_clear_explicit(&trace.busy,memory_order_release);
41 return written;
43static bool trace_next(struct trace_record *record) {
44 if(!atomic_load_explicit(&trace.enabled,memory_order_relaxed)) return false;
45 if(atomic_flag_test_and_set_explicit(&trace.busy,memory_order_acquire)) return false;
46 bool found=trace.read!=trace.write;
47 if(found) *record=trace.records[trace.read++%TRACE_RECORDS];
48 atomic_flag_clear_explicit(&trace.busy,memory_order_release);
49 return found;
51static void trace_output_damage(struct trace_output *output,uint64_t correlation) {
52 if(!atomic_load_explicit(&trace.enabled,memory_order_relaxed)) return;
53 if(!correlation) return;
54 for(unsigned i=0;i<output->count;i++) if(output->causes[i]==correlation) return;
55 if(output->count==TRACE_CAUSES) trace_drop(1);
56 else output->causes[output->count++]=correlation;
58static bool trace_output_commit(struct trace_output *output,uint32_t sequence,uint64_t object,
59 const struct timespec *when) {
60 if(!atomic_load_explicit(&trace.enabled,memory_order_relaxed)) return false;
61 struct trace_commit *commit=&output->commits[sequence%TRACE_COMMITS];
62 if(commit->count) trace_drop(commit->count);
63 commit->sequence=sequence; commit->count=output->count;
64 for(unsigned i=0;i<output->count;i++) {
65 commit->causes[i]=output->causes[i];
66 trace_record_at(8,commit->causes[i],object,sequence,when);
67 }
68 output->count=0;
69 return commit->count>0;
71static bool trace_output_present(struct trace_output *output,uint32_t sequence,uint64_t object,
72 bool presented,const struct timespec *when) {
73 if(!atomic_load_explicit(&trace.enabled,memory_order_relaxed)) return false;
74 struct trace_commit *commit=&output->commits[sequence%TRACE_COMMITS];
75 if(commit->sequence!=sequence) return false;
76 bool recorded=commit->count>0;
77 for(unsigned i=0;i<commit->count;i++)
78 trace_record_at(presented ? 9 : 14,commit->causes[i],object,sequence,when);
79 commit->count=0;
80 return recorded;