1 /*
2 * LLCStat Show LLC hit ratio for each process on each CPU core.
3 * For Linux, uses BCC, eBPF. Embedded C.
4 *
5 * Basic example of BCC timed sampling perf event.
6 *
7 * USAGE: LLCStat [duration]
8 *
9 * Copyright (c) Facebook, Inc.
10 * Licensed under the Apache License, Version 2.0 (the "License")
11 */
12
13 #include <linux/perf_event.h>
14 #include <unistd.h>
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/ptrace.h>
23 #include <uapi/linux/bpf_perf_event.h>
24
25 struct event_t {
26 int cpu;
27 int pid;
28 char name[16];
29 };
30
31 BPF_HASH(ref_count, struct event_t);
32 BPF_HASH(miss_count, struct event_t);
33
34 static inline __attribute__((always_inline)) void get_key(struct event_t* key) {
35 key->cpu = bpf_get_smp_processor_id();
36 key->pid = bpf_get_current_pid_tgid();
37 bpf_get_current_comm(&(key->name), sizeof(key->name));
38 }
39
40 int on_cache_miss(struct bpf_perf_event_data *ctx) {
41 struct event_t key = {};
42 get_key(&key);
43
44 u64 zero = 0, *val;
45 val = miss_count.lookup_or_try_init(&key, &zero);
46 if (val) {
47 (*val) += ctx->sample_period;
48 }
49
50 return 0;
51 }
52
53 int on_cache_ref(struct bpf_perf_event_data *ctx) {
54 struct event_t key = {};
55 get_key(&key);
56
57 u64 zero = 0, *val;
58 val = ref_count.lookup_or_try_init(&key, &zero);
59 if (val) {
60 (*val) += ctx->sample_period;
61 }
62
63 return 0;
64 }
65 )";
66
67 struct event_t {
68 int cpu;
69 int pid;
70 char name[16];
71 };
72
main(int argc,char ** argv)73 int main(int argc, char** argv) {
74 ebpf::BPF bpf;
75 auto init_res = bpf.init(BPF_PROGRAM);
76 if (!init_res.ok()) {
77 std::cerr << init_res.msg() << std::endl;
78 return 1;
79 }
80
81 auto attach_ref_res =
82 bpf.attach_perf_event(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES,
83 "on_cache_ref", 100, 0);
84 if (!attach_ref_res.ok()) {
85 std::cerr << attach_ref_res.msg() << std::endl;
86 return 1;
87 }
88 auto attach_miss_res = bpf.attach_perf_event(
89 PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES, "on_cache_miss", 100, 0);
90 if (!attach_miss_res.ok()) {
91 std::cerr << attach_miss_res.msg() << std::endl;
92 return 1;
93 }
94
95 int probe_time = 10;
96 if (argc == 2) {
97 probe_time = atoi(argv[1]);
98 }
99 std::cout << "Probing for " << probe_time << " seconds" << std::endl;
100 sleep(probe_time);
101 bpf.detach_perf_event(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES);
102 bpf.detach_perf_event(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES);
103
104 auto refs = bpf.get_hash_table<event_t, uint64_t>("ref_count");
105 auto misses = bpf.get_hash_table<event_t, uint64_t>("miss_count");
106 for (auto it : refs.get_table_offline()) {
107 uint64_t hit;
108 try {
109 auto miss = misses[it.first];
110 hit = miss <= it.second ? it.second - miss : 0;
111 } catch (...) {
112 hit = it.second;
113 }
114 double ratio = (double(hit) / double(it.second)) * 100.0;
115 std::cout << "PID " << std::setw(8) << std::setfill(' ') << it.first.pid;
116 std::cout << std::setw(20) << std::setfill(' ') << std::left
117 << " (" + std::string(it.first.name) + ") " << std::right;
118 std::cout << "on CPU " << std::setw(2) << std::setfill(' ') << it.first.cpu;
119 std::cout << " Hit Rate " << std::setprecision(4) << ratio << "% ";
120 std::cout << "(" << hit << "/" << it.second << ")" << std::endl;
121 }
122 return 0;
123 }
124