162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
262306a36Sopenharmony_ci// Copyright (c) 2021 Facebook
362306a36Sopenharmony_ci#include "vmlinux.h"
462306a36Sopenharmony_ci#include <bpf/bpf_helpers.h>
562306a36Sopenharmony_ci#include <bpf/bpf_tracing.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_cistruct {
862306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
962306a36Sopenharmony_ci	__uint(key_size, sizeof(__u32));
1062306a36Sopenharmony_ci	__uint(value_size, sizeof(int));
1162306a36Sopenharmony_ci	__uint(map_flags, BPF_F_PRESERVE_ELEMS);
1262306a36Sopenharmony_ci} events SEC(".maps");
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistruct {
1562306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
1662306a36Sopenharmony_ci	__uint(key_size, sizeof(__u32));
1762306a36Sopenharmony_ci	__uint(value_size, sizeof(struct bpf_perf_event_value));
1862306a36Sopenharmony_ci	__uint(max_entries, 1);
1962306a36Sopenharmony_ci} prev_readings SEC(".maps");
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistruct {
2262306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
2362306a36Sopenharmony_ci	__uint(key_size, sizeof(__u32));
2462306a36Sopenharmony_ci	__uint(value_size, sizeof(struct bpf_perf_event_value));
2562306a36Sopenharmony_ci	__uint(max_entries, 1);
2662306a36Sopenharmony_ci} diff_readings SEC(".maps");
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ciSEC("raw_tp/sched_switch")
2962306a36Sopenharmony_ciint BPF_PROG(on_switch)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	struct bpf_perf_event_value val, *prev_val, *diff_val;
3262306a36Sopenharmony_ci	__u32 key = bpf_get_smp_processor_id();
3362306a36Sopenharmony_ci	__u32 zero = 0;
3462306a36Sopenharmony_ci	long err;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	prev_val = bpf_map_lookup_elem(&prev_readings, &zero);
3762306a36Sopenharmony_ci	if (!prev_val)
3862306a36Sopenharmony_ci		return 0;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	diff_val = bpf_map_lookup_elem(&diff_readings, &zero);
4162306a36Sopenharmony_ci	if (!diff_val)
4262306a36Sopenharmony_ci		return 0;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	err = bpf_perf_event_read_value(&events, key, &val, sizeof(val));
4562306a36Sopenharmony_ci	if (err)
4662306a36Sopenharmony_ci		return 0;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	diff_val->counter = val.counter - prev_val->counter;
4962306a36Sopenharmony_ci	diff_val->enabled = val.enabled - prev_val->enabled;
5062306a36Sopenharmony_ci	diff_val->running = val.running - prev_val->running;
5162306a36Sopenharmony_ci	*prev_val = val;
5262306a36Sopenharmony_ci	return 0;
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cichar LICENSE[] SEC("license") = "Dual BSD/GPL";
56