tools/perf/util/bpf-trace-summary.c

Source file repositories/reference/linux-study-clean/tools/perf/util/bpf-trace-summary.c

File Facts

System
Linux kernel
Corpus path
tools/perf/util/bpf-trace-summary.c
Extension
.c
Size
12382 bytes
Lines
466
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

struct syscall_node {
	int syscall_nr;
	struct syscall_stats stats;
};

static double rel_stddev(struct syscall_stats *stat)
{
	double variance, average;

	if (stat->count < 2)
		return 0;

	average = (double)stat->total_time / stat->count;

	variance = stat->squared_sum;
	variance -= (stat->total_time * stat->total_time) / stat->count;
	variance /= stat->count - 1;

	return 100 * sqrt(variance / stat->count) / average;
}

/*
 * The syscall_data is to maintain syscall stats ordered by total time.
 * It supports different summary modes like per-thread or global.
 *
 * For per-thread stats, it uses two-level data strurcture -
 * syscall_data is keyed by TID and has an array of nodes which
 * represents each syscall for the thread.
 *
 * For global stats, it's still two-level technically but we don't need
 * per-cpu analysis so it's keyed by the syscall number to combine stats
 * from different CPUs.  And syscall_data always has a syscall_node so
 * it can effectively work as flat hierarchy.
 *
 * For per-cgroup stats, it uses two-level data structure like thread
 * syscall_data is keyed by CGROUP and has an array of node which
 * represents each syscall for the cgroup.
 */
struct syscall_data {
	u64 key; /* tid if AGGR_THREAD, syscall-nr if AGGR_CPU, cgroup if AGGR_CGROUP */
	int nr_events;
	int nr_nodes;
	u64 total_time;
	struct syscall_node *nodes;
};

static int datacmp(const void *a, const void *b)
{
	const struct syscall_data * const *sa = a;
	const struct syscall_data * const *sb = b;

	return (*sa)->total_time > (*sb)->total_time ? -1 : 1;
}

static int nodecmp(const void *a, const void *b)
{
	const struct syscall_node *na = a;
	const struct syscall_node *nb = b;

	return na->stats.total_time > nb->stats.total_time ? -1 : 1;
}

static size_t sc_node_hash(long key, void *ctx __maybe_unused)
{
	return key;
}

static bool sc_node_equal(long key1, long key2, void *ctx __maybe_unused)
{
	return key1 == key2;
}

static int print_common_stats(struct syscall_data *data, int max_summary, FILE *fp)
{
	int printed = 0;

	if (max_summary == 0 || max_summary > data->nr_nodes)
		max_summary = data->nr_nodes;

	for (int i = 0; i < max_summary; i++) {
		struct syscall_node *node = &data->nodes[i];
		struct syscall_stats *stat = &node->stats;
		double total = (double)(stat->total_time) / NSEC_PER_MSEC;
		double min = (double)(stat->min_time) / NSEC_PER_MSEC;
		double max = (double)(stat->max_time) / NSEC_PER_MSEC;
		double avg = total / stat->count;
		const char *name;

		/* TODO: support other ABIs */
		name = syscalltbl__name(EM_HOST, node->syscall_nr);

Annotation

Implementation Notes