1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2020 Wenbo Zhang
3 #include <vmlinux.h>
4 #include <bpf/bpf_helpers.h>
5 #include <bpf/bpf_tracing.h>
6 #include "cpufreq.h"
7 #include "maps.bpf.h"
8
9 __u32 freqs_mhz[MAX_CPU_NR] = {};
10 static struct hist zero;
11 struct hist syswide = {};
12
13 struct {
14 __uint(type, BPF_MAP_TYPE_HASH);
15 __uint(max_entries, MAX_ENTRIES);
16 __type(key, struct hkey);
17 __type(value, struct hist);
18 } hists SEC(".maps");
19
20 #define clamp_umax(VAR, UMAX) \
21 asm volatile ( \
22 "if %0 <= %[max] goto +1\n" \
23 "%0 = %[max]\n" \
24 : "+r"(VAR) \
25 : [max]"i"(UMAX) \
26 )
27
28 SEC("tp_btf/cpu_frequency")
BPF_PROG(cpu_frequency,unsigned int state,unsigned int cpu_id)29 int BPF_PROG(cpu_frequency, unsigned int state, unsigned int cpu_id)
30 {
31 if (cpu_id >= MAX_CPU_NR)
32 return 0;
33
34 clamp_umax(cpu_id, MAX_CPU_NR - 1);
35 freqs_mhz[cpu_id] = state / 1000;
36 return 0;
37 }
38
39 SEC("perf_event")
do_sample(struct bpf_perf_event_data * ctx)40 int do_sample(struct bpf_perf_event_data *ctx)
41 {
42 u32 freq_mhz, pid = bpf_get_current_pid_tgid();
43 u64 slot, cpu = bpf_get_smp_processor_id();
44 struct hist *hist;
45 struct hkey hkey;
46
47 if (cpu >= MAX_CPU_NR)
48 return 0;
49 clamp_umax(cpu, MAX_CPU_NR - 1);
50 freq_mhz = freqs_mhz[cpu];
51 if (!freq_mhz)
52 return 0;
53 /*
54 * The range of the linear histogram is 0 ~ 5000mhz,
55 * and the step size is 200.
56 */
57 slot = freq_mhz / HIST_STEP_SIZE;
58 if (slot >= MAX_SLOTS)
59 slot = MAX_SLOTS - 1;
60 __sync_fetch_and_add(&syswide.slots[slot], 1);
61 if (!pid)
62 return 0;
63 bpf_get_current_comm(&hkey.comm, sizeof(hkey.comm));
64 hist = bpf_map_lookup_or_try_init(&hists, &hkey, &zero);
65 if (!hist)
66 return 0;
67 __sync_fetch_and_add(&hist->slots[slot], 1);
68 return 0;
69 }
70
71 char LICENSE[] SEC("license") = "GPL";
72