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