^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <linux/version.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/ptrace.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <uapi/linux/bpf.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <bpf/bpf_helpers.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * The CPU number, cstate number and pstate number are based
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * on 96boards Hikey with octa CA53 CPUs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * Every CPU have three idle states for cstate:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * WFI, CPU_OFF, CLUSTER_OFF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * Every CPU have 5 operating points:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * 208MHz, 432MHz, 729MHz, 960MHz, 1200MHz
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * This code is based on these assumption and other platforms
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * need to adjust these definitions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define MAX_CPU 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define MAX_PSTATE_ENTRIES 5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define MAX_CSTATE_ENTRIES 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static int cpu_opps[] = { 208000, 432000, 729000, 960000, 1200000 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * my_map structure is used to record cstate and pstate index and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * timestamp (Idx, Ts), when new event incoming we need to update
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * combination for new state index and timestamp (Idx`, Ts`).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * Based on (Idx, Ts) and (Idx`, Ts`) we can calculate the time
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * interval for the previous state: Duration(Idx) = Ts` - Ts.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * Every CPU has one below array for recording state index and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * timestamp, and record for cstate and pstate saperately:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * +--------------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * | cstate timestamp |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * +--------------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * | cstate index |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * +--------------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * | pstate timestamp |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * +--------------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * | pstate index |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * +--------------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define MAP_OFF_CSTATE_TIME 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define MAP_OFF_CSTATE_IDX 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define MAP_OFF_PSTATE_TIME 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define MAP_OFF_PSTATE_IDX 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define MAP_OFF_NUM 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) __uint(type, BPF_MAP_TYPE_ARRAY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) __type(key, u32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) __type(value, u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) __uint(max_entries, MAX_CPU * MAP_OFF_NUM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) } my_map SEC(".maps");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) /* cstate_duration records duration time for every idle state per CPU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) __uint(type, BPF_MAP_TYPE_ARRAY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) __type(key, u32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) __type(value, u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) __uint(max_entries, MAX_CPU * MAX_CSTATE_ENTRIES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) } cstate_duration SEC(".maps");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) /* pstate_duration records duration time for every operating point per CPU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) __uint(type, BPF_MAP_TYPE_ARRAY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) __type(key, u32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) __type(value, u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) __uint(max_entries, MAX_CPU * MAX_PSTATE_ENTRIES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) } pstate_duration SEC(".maps");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * The trace events for cpu_idle and cpu_frequency are taken from:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * /sys/kernel/debug/tracing/events/power/cpu_idle/format
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * /sys/kernel/debug/tracing/events/power/cpu_frequency/format
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * These two events have same format, so define one common structure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) struct cpu_args {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) u64 pad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) u32 state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) u32 cpu_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) /* calculate pstate index, returns MAX_PSTATE_ENTRIES for failure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) static u32 find_cpu_pstate_idx(u32 frequency)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) u32 i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) for (i = 0; i < sizeof(cpu_opps) / sizeof(u32); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (frequency == cpu_opps[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) SEC("tracepoint/power/cpu_idle")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) int bpf_prog1(struct cpu_args *ctx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) u64 *cts, *pts, *cstate, *pstate, prev_state, cur_ts, delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) u32 key, cpu, pstate_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) u64 *val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (ctx->cpu_id > MAX_CPU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) cpu = ctx->cpu_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) key = cpu * MAP_OFF_NUM + MAP_OFF_CSTATE_TIME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) cts = bpf_map_lookup_elem(&my_map, &key);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if (!cts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) key = cpu * MAP_OFF_NUM + MAP_OFF_CSTATE_IDX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) cstate = bpf_map_lookup_elem(&my_map, &key);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (!cstate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) key = cpu * MAP_OFF_NUM + MAP_OFF_PSTATE_TIME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) pts = bpf_map_lookup_elem(&my_map, &key);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) if (!pts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) key = cpu * MAP_OFF_NUM + MAP_OFF_PSTATE_IDX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) pstate = bpf_map_lookup_elem(&my_map, &key);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (!pstate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) prev_state = *cstate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) *cstate = ctx->state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (!*cts) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) *cts = bpf_ktime_get_ns();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) cur_ts = bpf_ktime_get_ns();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) delta = cur_ts - *cts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) *cts = cur_ts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) * When state doesn't equal to (u32)-1, the cpu will enter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) * one idle state; for this case we need to record interval
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) * for the pstate.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) * OPP2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) * +---------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) * OPP1 | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) * ---------+ |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) * | Idle state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * +---------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) * |<- pstate duration ->|
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) * ^ ^
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) * pts cur_ts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if (ctx->state != (u32)-1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) /* record pstate after have first cpu_frequency event */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) if (!*pts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) delta = cur_ts - *pts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) pstate_idx = find_cpu_pstate_idx(*pstate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) if (pstate_idx >= MAX_PSTATE_ENTRIES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) key = cpu * MAX_PSTATE_ENTRIES + pstate_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) val = bpf_map_lookup_elem(&pstate_duration, &key);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) if (val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) __sync_fetch_and_add((long *)val, delta);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) * When state equal to (u32)-1, the cpu just exits from one
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) * specific idle state; for this case we need to record
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) * interval for the pstate.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) * OPP2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * -----------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) * | OPP1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * | +-----------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * | Idle state |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) * +---------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) * |<- cstate duration ->|
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) * ^ ^
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) * cts cur_ts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) key = cpu * MAX_CSTATE_ENTRIES + prev_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) val = bpf_map_lookup_elem(&cstate_duration, &key);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) if (val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) __sync_fetch_and_add((long *)val, delta);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) /* Update timestamp for pstate as new start time */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) if (*pts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) *pts = cur_ts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) SEC("tracepoint/power/cpu_frequency")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) int bpf_prog2(struct cpu_args *ctx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) u64 *pts, *cstate, *pstate, prev_state, cur_ts, delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) u32 key, cpu, pstate_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) u64 *val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) cpu = ctx->cpu_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) key = cpu * MAP_OFF_NUM + MAP_OFF_PSTATE_TIME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) pts = bpf_map_lookup_elem(&my_map, &key);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) if (!pts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) key = cpu * MAP_OFF_NUM + MAP_OFF_PSTATE_IDX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) pstate = bpf_map_lookup_elem(&my_map, &key);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (!pstate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) key = cpu * MAP_OFF_NUM + MAP_OFF_CSTATE_IDX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) cstate = bpf_map_lookup_elem(&my_map, &key);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) if (!cstate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) prev_state = *pstate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) *pstate = ctx->state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) if (!*pts) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) *pts = bpf_ktime_get_ns();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) cur_ts = bpf_ktime_get_ns();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) delta = cur_ts - *pts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) *pts = cur_ts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) /* When CPU is in idle, bail out to skip pstate statistics */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (*cstate != (u32)(-1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) * The cpu changes to another different OPP (in below diagram
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) * change frequency from OPP3 to OPP1), need recording interval
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) * for previous frequency OPP3 and update timestamp as start
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) * time for new frequency OPP1.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) * OPP3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) * +---------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) * OPP2 | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) * ---------+ |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) * | OPP1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) * +---------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) * |<- pstate duration ->|
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) * ^ ^
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) * pts cur_ts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) pstate_idx = find_cpu_pstate_idx(*pstate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) if (pstate_idx >= MAX_PSTATE_ENTRIES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) key = cpu * MAX_PSTATE_ENTRIES + pstate_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) val = bpf_map_lookup_elem(&pstate_duration, &key);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) if (val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) __sync_fetch_and_add((long *)val, delta);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) char _license[] SEC("license") = "GPL";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) u32 _version SEC("version") = LINUX_VERSION_CODE;