18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
28c2ecf20Sopenharmony_ci// Copyright (c) 2020 Facebook
38c2ecf20Sopenharmony_ci#include <vmlinux.h>
48c2ecf20Sopenharmony_ci#include <bpf/bpf_helpers.h>
58c2ecf20Sopenharmony_ci#include <bpf/bpf_tracing.h>
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_cistruct bpf_perf_event_value___local {
88c2ecf20Sopenharmony_ci	__u64 counter;
98c2ecf20Sopenharmony_ci	__u64 enabled;
108c2ecf20Sopenharmony_ci	__u64 running;
118c2ecf20Sopenharmony_ci} __attribute__((preserve_access_index));
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci/* map of perf event fds, num_cpu * num_metric entries */
148c2ecf20Sopenharmony_cistruct {
158c2ecf20Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
168c2ecf20Sopenharmony_ci	__uint(key_size, sizeof(u32));
178c2ecf20Sopenharmony_ci	__uint(value_size, sizeof(int));
188c2ecf20Sopenharmony_ci} events SEC(".maps");
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/* readings at fentry */
218c2ecf20Sopenharmony_cistruct {
228c2ecf20Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
238c2ecf20Sopenharmony_ci	__uint(key_size, sizeof(u32));
248c2ecf20Sopenharmony_ci	__uint(value_size, sizeof(struct bpf_perf_event_value___local));
258c2ecf20Sopenharmony_ci} fentry_readings SEC(".maps");
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci/* accumulated readings */
288c2ecf20Sopenharmony_cistruct {
298c2ecf20Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
308c2ecf20Sopenharmony_ci	__uint(key_size, sizeof(u32));
318c2ecf20Sopenharmony_ci	__uint(value_size, sizeof(struct bpf_perf_event_value___local));
328c2ecf20Sopenharmony_ci} accum_readings SEC(".maps");
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/* sample counts, one per cpu */
358c2ecf20Sopenharmony_cistruct {
368c2ecf20Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
378c2ecf20Sopenharmony_ci	__uint(key_size, sizeof(u32));
388c2ecf20Sopenharmony_ci	__uint(value_size, sizeof(u64));
398c2ecf20Sopenharmony_ci} counts SEC(".maps");
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ciconst volatile __u32 num_cpu = 1;
428c2ecf20Sopenharmony_ciconst volatile __u32 num_metric = 1;
438c2ecf20Sopenharmony_ci#define MAX_NUM_MATRICS 4
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ciSEC("fentry/XXX")
468c2ecf20Sopenharmony_ciint BPF_PROG(fentry_XXX)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	struct bpf_perf_event_value___local *ptrs[MAX_NUM_MATRICS];
498c2ecf20Sopenharmony_ci	u32 key = bpf_get_smp_processor_id();
508c2ecf20Sopenharmony_ci	u32 i;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	/* look up before reading, to reduce error */
538c2ecf20Sopenharmony_ci	for (i = 0; i < num_metric && i < MAX_NUM_MATRICS; i++) {
548c2ecf20Sopenharmony_ci		u32 flag = i;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci		ptrs[i] = bpf_map_lookup_elem(&fentry_readings, &flag);
578c2ecf20Sopenharmony_ci		if (!ptrs[i])
588c2ecf20Sopenharmony_ci			return 0;
598c2ecf20Sopenharmony_ci	}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	for (i = 0; i < num_metric && i < MAX_NUM_MATRICS; i++) {
628c2ecf20Sopenharmony_ci		struct bpf_perf_event_value___local reading;
638c2ecf20Sopenharmony_ci		int err;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci		err = bpf_perf_event_read_value(&events, key, (void *)&reading,
668c2ecf20Sopenharmony_ci						sizeof(reading));
678c2ecf20Sopenharmony_ci		if (err)
688c2ecf20Sopenharmony_ci			return 0;
698c2ecf20Sopenharmony_ci		*(ptrs[i]) = reading;
708c2ecf20Sopenharmony_ci		key += num_cpu;
718c2ecf20Sopenharmony_ci	}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	return 0;
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic inline void
778c2ecf20Sopenharmony_cifexit_update_maps(u32 id, struct bpf_perf_event_value___local *after)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	struct bpf_perf_event_value___local *before, diff;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	before = bpf_map_lookup_elem(&fentry_readings, &id);
828c2ecf20Sopenharmony_ci	/* only account samples with a valid fentry_reading */
838c2ecf20Sopenharmony_ci	if (before && before->counter) {
848c2ecf20Sopenharmony_ci		struct bpf_perf_event_value___local *accum;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci		diff.counter = after->counter - before->counter;
878c2ecf20Sopenharmony_ci		diff.enabled = after->enabled - before->enabled;
888c2ecf20Sopenharmony_ci		diff.running = after->running - before->running;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci		accum = bpf_map_lookup_elem(&accum_readings, &id);
918c2ecf20Sopenharmony_ci		if (accum) {
928c2ecf20Sopenharmony_ci			accum->counter += diff.counter;
938c2ecf20Sopenharmony_ci			accum->enabled += diff.enabled;
948c2ecf20Sopenharmony_ci			accum->running += diff.running;
958c2ecf20Sopenharmony_ci		}
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ciSEC("fexit/XXX")
1008c2ecf20Sopenharmony_ciint BPF_PROG(fexit_XXX)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	struct bpf_perf_event_value___local readings[MAX_NUM_MATRICS];
1038c2ecf20Sopenharmony_ci	u32 cpu = bpf_get_smp_processor_id();
1048c2ecf20Sopenharmony_ci	u32 i, zero = 0;
1058c2ecf20Sopenharmony_ci	int err;
1068c2ecf20Sopenharmony_ci	u64 *count;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	/* read all events before updating the maps, to reduce error */
1098c2ecf20Sopenharmony_ci	for (i = 0; i < num_metric && i < MAX_NUM_MATRICS; i++) {
1108c2ecf20Sopenharmony_ci		err = bpf_perf_event_read_value(&events, cpu + i * num_cpu,
1118c2ecf20Sopenharmony_ci						(void *)(readings + i),
1128c2ecf20Sopenharmony_ci						sizeof(*readings));
1138c2ecf20Sopenharmony_ci		if (err)
1148c2ecf20Sopenharmony_ci			return 0;
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci	count = bpf_map_lookup_elem(&counts, &zero);
1178c2ecf20Sopenharmony_ci	if (count) {
1188c2ecf20Sopenharmony_ci		*count += 1;
1198c2ecf20Sopenharmony_ci		for (i = 0; i < num_metric && i < MAX_NUM_MATRICS; i++)
1208c2ecf20Sopenharmony_ci			fexit_update_maps(i, &readings[i]);
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci	return 0;
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cichar LICENSE[] SEC("license") = "Dual BSD/GPL";
126