AtlatestRepositorysigil-wm
1
/* SPDX-License-Identifier: BSD-3-Clause2
* 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 81925
#define TRACE_CAUSES 646
#define TRACE_COMMITS 647
struct trace_record { uint64_t stage, ns, correlation, object, sequence; };8
static 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};15
struct trace_commit {16
uint32_t sequence;17
unsigned count;18
uint64_t causes[TRACE_CAUSES];19
};20
struct trace_output {21
unsigned count;22
uint64_t causes[TRACE_CAUSES];23
struct trace_commit commits[TRACE_COMMITS];24
};25
static void trace_drop(uint64_t count) { atomic_fetch_add_explicit(&trace.dropped,count,memory_order_relaxed); }26
static 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;42
}43
static 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;50
}51
static 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;57
}58
static 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;70
}71
static 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;81
}