// SPDX-License-Identifier: GPL-2.0
#include <stdio.h>
#include "evsel.h"
#include "stat.h"
#include "color.h"
#include "pmu.h"
#include "rblist.h"
#include "evlist.h"
#include "expr.h"
#include "metricgroup.h"
/*
* AGGR_GLOBAL: Use CPU 0
* AGGR_SOCKET: Use first CPU of socket
* AGGR_DIE: Use first CPU of die
* AGGR_CORE: Use first CPU of core
* AGGR_NONE: Use matching CPU
* AGGR_THREAD: Not supported?
*/
static bool have_frontend_stalled;
struct runtime_stat rt_stat;
struct stats walltime_nsecs_stats;
struct saved_value {
struct rb_node rb_node;
struct perf_evsel *evsel;
enum stat_type type;
int ctx;
int cpu;
struct runtime_stat *stat;
struct stats stats;
};
static int saved_value_cmp(struct rb_node *rb_node, const void *entry)
{
struct saved_value *a = container_of(rb_node,
struct saved_value,
rb_node);
const struct saved_value *b = entry;
if (a->cpu != b->cpu)
return a->cpu - b->cpu;
/*
* Previously the rbtree was used to link generic metrics.
* The keys were evsel/cpu. Now the rbtree is extended to support
* per-thread shadow stats. For shadow stats case, the keys
* are cpu/type/ctx/stat (evsel is NULL). For generic metrics
* case, the keys are still evsel/cpu (type/ctx/stat are 0 or NULL).
*/
if (a->type != b->type)
return a->type - b->type;
if (a->ctx != b->ctx)
return a->ctx - b->ctx;
if (a->evsel == NULL && b->evsel == NULL) {
if (a->stat == b->stat)
return 0;
if ((char *)a->stat < (char *)b->stat)
return -1;
return 1;
}
if (a->evsel == b->evsel)
return 0;
if ((char *)a->evsel < (char *)b->evsel)
return -1;
return +1;
}
static struct rb_node *saved_value_new(struct rblist *rblist __maybe_unused,
const void *entry)
{
struct saved_value *nd = malloc(sizeof(struct saved_value));
if (!nd)
return NULL;
memcpy(nd, entry, sizeof(struct saved_value));
return &nd->rb_node;
}
static void saved_value_delete(struct rblist *rblist __maybe_unused,
struct rb_node *rb_node)
{
struct saved_value *v;
BUG_ON(!rb_node);
v = container_of(rb_node, struct saved_value, rb_node);
free(v);
}
static struct saved_value *saved_value_lookup(struct perf_evsel *evsel,
int cpu,
bool create,
enum stat_type type,
int ctx,
struct runtime_stat *st)
{
struct rblist *rblist;
struct rb_node *nd;
struct saved_value dm = {
.cpu = cpu,
.evsel = evsel,
.type = type,
.ctx = ctx,
.stat = st,
};
rblist = &st->value_list;
nd = rblist__find(rblist, &dm);
if (nd)
return container_of(nd, struct saved_value, rb_node);
if (create) {
rblist__add_node(rblist, &dm);
nd = rblist__find(rblist, &dm);
if (nd)
return container_of(nd, struct saved_value, rb_node);
}
return NULL;
}
void runtime_stat__init(struct runtime_stat *st)
{
struct rblist *rblist = &st->value_list;
rblist__init(rblist);
rblist->node_cmp = saved_value_cmp;
rblist->node_new = saved_value_new;
rblist->node_delete = saved_value_delete;
}
void