• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_init(&key, &zero);
46     (*val) += ctx->sample_period;
47 
48     return 0;
49 }
50 
51 int on_cache_ref(struct bpf_perf_event_data *ctx) {
52     struct event_t key = {};
53     get_key(&key);
54 
55     u64 zero = 0, *val;
56     val = ref_count.lookup_or_init(&key, &zero);
57     (*val) += ctx->sample_period;
58 
59     return 0;
60 }
61 )";
62 
63 struct event_t {
64   int cpu;
65   int pid;
66   char name[16];
67 };
68 
main(int argc,char ** argv)69 int main(int argc, char** argv) {
70   ebpf::BPF bpf;
71   auto init_res = bpf.init(BPF_PROGRAM);
72   if (init_res.code() != 0) {
73     std::cerr << init_res.msg() << std::endl;
74     return 1;
75   }
76 
77   auto attach_ref_res =
78       bpf.attach_perf_event(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES,
79                             "on_cache_ref", 100, 0);
80   if (attach_ref_res.code() != 0) {
81     std::cerr << attach_ref_res.msg() << std::endl;
82     return 1;
83   }
84   auto attach_miss_res = bpf.attach_perf_event(
85       PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES, "on_cache_miss", 100, 0);
86   if (attach_miss_res.code() != 0) {
87     std::cerr << attach_miss_res.msg() << std::endl;
88     return 1;
89   }
90 
91   int probe_time = 10;
92   if (argc == 2) {
93     probe_time = atoi(argv[1]);
94   }
95   std::cout << "Probing for " << probe_time << " seconds" << std::endl;
96   sleep(probe_time);
97   bpf.detach_perf_event(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES);
98   bpf.detach_perf_event(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES);
99 
100   auto refs = bpf.get_hash_table<event_t, uint64_t>("ref_count");
101   auto misses = bpf.get_hash_table<event_t, uint64_t>("miss_count");
102   for (auto it : refs.get_table_offline()) {
103     uint64_t hit;
104     try {
105       auto miss = misses[it.first];
106       hit = miss <= it.second ? it.second - miss : 0;
107     } catch (...) {
108       hit = it.second;
109     }
110     double ratio = (double(hit) / double(it.second)) * 100.0;
111     std::cout << "PID " << std::setw(8) << std::setfill(' ') << it.first.pid;
112     std::cout << std::setw(20) << std::setfill(' ') << std::left
113               << " (" + std::string(it.first.name) + ") " << std::right;
114     std::cout << "on CPU " << std::setw(2) << std::setfill(' ') << it.first.cpu;
115     std::cout << " Hit Rate " << std::setprecision(4) << ratio << "% ";
116     std::cout << "(" << hit << "/" << it.second << ")" << std::endl;
117   }
118   return 0;
119 }
120