/*
|
* time_in_state eBPF program
|
*
|
* Copyright (C) 2018 Google
|
*
|
* This program is free software; you can redistribute it and/or
|
* modify it under the terms of the GNU General Public License version
|
* 2 as published by the Free Software Foundation.
|
*
|
* This program is distributed in the hope that it will be useful,
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* GNU General Public License for more details.
|
*
|
*/
|
|
#include <bpf_helpers.h>
|
|
typedef struct {
|
uint32_t uid;
|
uint32_t freq;
|
} time_key;
|
|
DEFINE_BPF_MAP(uid_times_map, PERCPU_HASH, time_key, uint64_t, 10240)
|
DEFINE_BPF_MAP(cpu_last_update_map, PERCPU_ARRAY, uint32_t, uint64_t, 1)
|
|
/* Assume max of 1024 CPUs */
|
DEFINE_BPF_MAP(cpu_freq_map, ARRAY, uint32_t, uint32_t, 1024)
|
|
struct switch_args {
|
unsigned long long ignore;
|
char prev_comm[16];
|
int prev_pid;
|
int prev_prio;
|
long long prev_state;
|
char next_comm[16];
|
int next_pid;
|
int next_prio;
|
};
|
|
SEC("tracepoint/sched/sched_switch")
|
int tp_sched_switch(struct switch_args* args) {
|
uint32_t zero = 0;
|
uint64_t* last = bpf_cpu_last_update_map_lookup_elem(&zero);
|
if (!last) return 0;
|
uint64_t old_last = *last;
|
uint64_t time = bpf_ktime_get_ns();
|
*last = time;
|
uint32_t cpu = bpf_get_smp_processor_id();
|
uint32_t* freq = bpf_cpu_freq_map_lookup_elem(&cpu);
|
if (args->prev_pid && old_last && freq && *freq) {
|
uint32_t uid = bpf_get_current_uid_gid();
|
time_key key = {.uid = uid, .freq = *freq};
|
uint64_t* tot_time = bpf_uid_times_map_lookup_elem(&key);
|
uint64_t delta = time - old_last;
|
if (!tot_time)
|
bpf_uid_times_map_update_elem(&key, &delta, BPF_ANY);
|
else
|
*tot_time += delta;
|
}
|
return 0;
|
}
|
|
struct cpufreq_args {
|
unsigned long long ignore;
|
unsigned int state;
|
unsigned int cpu_id;
|
};
|
|
SEC("tracepoint/power/cpu_frequency")
|
int tp_cpufreq(struct cpufreq_args* args) {
|
uint32_t cpu = args->cpu_id;
|
unsigned int new = args->state;
|
bpf_cpu_freq_map_update_elem(&cpu, &new, BPF_ANY);
|
return 0;
|
}
|
|
char _license[] SEC("license") = "GPL";
|