102 lines
2.6 KiB
C
102 lines
2.6 KiB
C
|
#include "cache.h"
|
||
|
#include "thread-utils.h"
|
||
|
#include "trace2/tr2_tgt.h"
|
||
|
#include "trace2/tr2_tls.h"
|
||
|
#include "trace2/tr2_ctr.h"
|
||
|
|
||
|
/*
|
||
|
* A global counter block to aggregrate values from the partial sums
|
||
|
* from each thread.
|
||
|
*/
|
||
|
static struct tr2_counter_block final_counter_block; /* access under tr2tls_mutex */
|
||
|
|
||
|
/*
|
||
|
* Define metadata for each global counter.
|
||
|
*
|
||
|
* This array must match the "enum trace2_counter_id" and the values
|
||
|
* in "struct tr2_counter_block.counter[*]".
|
||
|
*/
|
||
|
static struct tr2_counter_metadata tr2_counter_metadata[TRACE2_NUMBER_OF_COUNTERS] = {
|
||
|
[TRACE2_COUNTER_ID_TEST1] = {
|
||
|
.category = "test",
|
||
|
.name = "test1",
|
||
|
.want_per_thread_events = 0,
|
||
|
},
|
||
|
[TRACE2_COUNTER_ID_TEST2] = {
|
||
|
.category = "test",
|
||
|
.name = "test2",
|
||
|
.want_per_thread_events = 1,
|
||
|
},
|
||
|
|
||
|
/* Add additional metadata before here. */
|
||
|
};
|
||
|
|
||
|
void tr2_counter_increment(enum trace2_counter_id cid, uint64_t value)
|
||
|
{
|
||
|
struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
|
||
|
struct tr2_counter *c = &ctx->counter_block.counter[cid];
|
||
|
|
||
|
c->value += value;
|
||
|
|
||
|
ctx->used_any_counter = 1;
|
||
|
if (tr2_counter_metadata[cid].want_per_thread_events)
|
||
|
ctx->used_any_per_thread_counter = 1;
|
||
|
}
|
||
|
|
||
|
void tr2_update_final_counters(void)
|
||
|
{
|
||
|
struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
|
||
|
enum trace2_counter_id cid;
|
||
|
|
||
|
if (!ctx->used_any_counter)
|
||
|
return;
|
||
|
|
||
|
/*
|
||
|
* Access `final_counter_block` requires holding `tr2tls_mutex`.
|
||
|
* We assume that our caller is holding the lock.
|
||
|
*/
|
||
|
|
||
|
for (cid = 0; cid < TRACE2_NUMBER_OF_COUNTERS; cid++) {
|
||
|
struct tr2_counter *c_final = &final_counter_block.counter[cid];
|
||
|
const struct tr2_counter *c = &ctx->counter_block.counter[cid];
|
||
|
|
||
|
c_final->value += c->value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void tr2_emit_per_thread_counters(tr2_tgt_evt_counter_t *fn_apply)
|
||
|
{
|
||
|
struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
|
||
|
enum trace2_counter_id cid;
|
||
|
|
||
|
if (!ctx->used_any_per_thread_counter)
|
||
|
return;
|
||
|
|
||
|
/*
|
||
|
* For each counter, if the counter wants per-thread events
|
||
|
* and this thread used it (the value is non-zero), emit it.
|
||
|
*/
|
||
|
for (cid = 0; cid < TRACE2_NUMBER_OF_COUNTERS; cid++)
|
||
|
if (tr2_counter_metadata[cid].want_per_thread_events &&
|
||
|
ctx->counter_block.counter[cid].value)
|
||
|
fn_apply(&tr2_counter_metadata[cid],
|
||
|
&ctx->counter_block.counter[cid],
|
||
|
0);
|
||
|
}
|
||
|
|
||
|
void tr2_emit_final_counters(tr2_tgt_evt_counter_t *fn_apply)
|
||
|
{
|
||
|
enum trace2_counter_id cid;
|
||
|
|
||
|
/*
|
||
|
* Access `final_counter_block` requires holding `tr2tls_mutex`.
|
||
|
* We assume that our caller is holding the lock.
|
||
|
*/
|
||
|
|
||
|
for (cid = 0; cid < TRACE2_NUMBER_OF_COUNTERS; cid++)
|
||
|
if (final_counter_block.counter[cid].value)
|
||
|
fn_apply(&tr2_counter_metadata[cid],
|
||
|
&final_counter_block.counter[cid],
|
||
|
1);
|
||
|
}
|