xref: /aosp_15_r20/external/bcc/examples/cpp/LLCStat.cc (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
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