1 /*
2 * CPUDistribution Show load distribution across CPU cores during a period of
3 * time. For Linux, uses BCC, eBPF. Embedded C.
4 *
5 * Basic example of BCC and kprobes.
6 *
7 * USAGE: CPUDistribution [duration]
8 *
9 * Copyright (c) Facebook, Inc.
10 * Licensed under the Apache License, Version 2.0 (the "License")
11 */
12
13 #include <unistd.h>
14 #include <cstdlib>
15 #include <iomanip>
16 #include <iostream>
17 #include <string>
18
19 #include "BPF.h"
20
21 const std::string BPF_PROGRAM = R"(
22 #include <linux/sched.h>
23 #include <uapi/linux/ptrace.h>
24
25 BPF_HASH(pid_to_cpu, pid_t, int);
26 BPF_HASH(pid_to_ts, pid_t, uint64_t);
27 BPF_HASH(cpu_time, int, uint64_t);
28
29 int task_switch_event(struct pt_regs *ctx, struct task_struct *prev) {
30 pid_t prev_pid = prev->pid;
31 int* prev_cpu = pid_to_cpu.lookup(&prev_pid);
32 uint64_t* prev_ts = pid_to_ts.lookup(&prev_pid);
33
34 pid_t cur_pid = bpf_get_current_pid_tgid();
35 int cur_cpu = bpf_get_smp_processor_id();
36 uint64_t cur_ts = bpf_ktime_get_ns();
37
38 uint64_t this_cpu_time = 0;
39 if (prev_ts) {
40 pid_to_ts.delete(&prev_pid);
41 this_cpu_time = (cur_ts - *prev_ts);
42 }
43 if (prev_cpu) {
44 pid_to_cpu.delete(&prev_pid);
45 if (this_cpu_time > 0) {
46 int cpu_key = *prev_cpu;
47 uint64_t* history_time = cpu_time.lookup(&cpu_key);
48 if (history_time)
49 this_cpu_time += *history_time;
50 cpu_time.update(&cpu_key, &this_cpu_time);
51 }
52 }
53
54 pid_to_cpu.update(&cur_pid, &cur_cpu);
55 pid_to_ts.update(&cur_pid, &cur_ts);
56
57 return 0;
58 }
59 )";
60
main(int argc,char ** argv)61 int main(int argc, char** argv) {
62 ebpf::BPF bpf;
63 auto init_res = bpf.init(BPF_PROGRAM);
64 if (!init_res.ok()) {
65 std::cerr << init_res.msg() << std::endl;
66 return 1;
67 }
68
69 auto attach_res =
70 bpf.attach_kprobe("finish_task_switch", "task_switch_event");
71 if (!attach_res.ok()) {
72 std::cerr << attach_res.msg() << std::endl;
73 return 1;
74 }
75
76 int probe_time = 10;
77 if (argc == 2) {
78 probe_time = atoi(argv[1]);
79 }
80 std::cout << "Probing for " << probe_time << " seconds" << std::endl;
81 sleep(probe_time);
82
83 auto table = bpf.get_hash_table<int, uint64_t>("cpu_time");
84 auto num_cores = sysconf(_SC_NPROCESSORS_ONLN);
85 for (int i = 0; i < num_cores; i++) {
86 std::cout << "CPU " << std::setw(2) << i << " worked for ";
87 std::cout << (table[i] / 1000000.0) << " ms." << std::endl;
88 }
89
90 auto detach_res = bpf.detach_kprobe("finish_task_switch");
91 if (!detach_res.ok()) {
92 std::cerr << detach_res.msg() << std::endl;
93 return 1;
94 }
95
96 return 0;
97 }
98