blob: d61d2798f3d03604845672b6ce8411b6c6d6a61f [file] [log] [blame]
Joel Fernandesc5c05162018-10-16 13:26:56 -07001/*
2 * time_in_state eBPF program
3 *
4 * Copyright (C) 2018 Google
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include "helpers.h"
18
19struct time_key {
20 uint32_t uid;
21 uint32_t freq;
22};
23
24struct bpf_map_def SEC("maps") uid_times = {
25 .type = BPF_MAP_TYPE_PERCPU_HASH,
26 .key_size = sizeof(struct time_key),
27 .value_size = sizeof(uint64_t),
28 .max_entries = 10240,
29};
30
31struct bpf_map_def SEC("maps") cpu_last_update = {
32 .type = BPF_MAP_TYPE_PERCPU_ARRAY,
33 .key_size = sizeof(int),
34 .value_size = sizeof(uint64_t),
35 .max_entries = 1,
36};
37
38struct bpf_map_def SEC("maps") cpu_freq = {
39 .type = BPF_MAP_TYPE_ARRAY,
40 .key_size = sizeof(int),
41 .value_size = sizeof(uint32_t),
42 /* Assume max of 1024 CPUs */
43 .max_entries = 1024,
44};
45
46struct switch_args {
47 unsigned long long ignore;
48 char prev_comm[16];
49 int prev_pid;
50 int prev_prio;
51 long long prev_state;
52 char next_comm[16];
53 int next_pid;
54 int next_prio;
55};
56
57SEC("tracepoint/sched/sched_switch")
58int tp_sched_switch(struct switch_args* args) {
59 uint32_t zero = 0;
60 uint64_t* last = bpf_map_lookup_elem(&cpu_last_update, &zero);
61 if (!last) return 0;
62 uint64_t old_last = *last;
63 uint64_t time = bpf_ktime_get_ns();
64 *last = time;
65 uint32_t cpu = bpf_get_smp_processor_id();
66 uint32_t* freq = bpf_map_lookup_elem(&cpu_freq, &cpu);
67 if (args->prev_pid && old_last && freq && *freq) {
68 uint32_t uid = bpf_get_current_uid_gid();
69 struct time_key key = {.uid = uid, .freq = *freq};
70 uint64_t* tot_time = bpf_map_lookup_elem(&uid_times, &key);
71 uint64_t delta = time - old_last;
72 if (!tot_time)
73 bpf_map_update_elem(&uid_times, &key, &delta, BPF_ANY);
74 else
75 *tot_time += delta;
76 }
77 return 0;
78}
79
80struct cpufreq_args {
81 unsigned long long ignore;
82 unsigned int state;
83 unsigned int cpu_id;
84};
85
86SEC("tracepoint/power/cpu_frequency")
87int tp_cpufreq(struct cpufreq_args* args) {
88 unsigned int cpu = args->cpu_id;
89 unsigned int new = args->state;
90 bpf_map_update_elem(&cpu_freq, &cpu, &new, BPF_ANY);
91 return 0;
92}
93
94char _license[] SEC("license") = "GPL";