Skip to content

Commit 5fdee7e

Browse files
committed
Tool to monitor CPU core frequencies
1 parent dc52163 commit 5fdee7e

File tree

1 file changed

+104
-0
lines changed

1 file changed

+104
-0
lines changed

core_frequency.py

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#!/usr/bin/env python
2+
3+
'''
4+
core_frequency.py - Low overhead BPF Tool to monitor core frequencies.
5+
Author: Saleem Ahmad (saleem.iitg[@]gmail.com)
6+
7+
Usage: ./core_frequency.py [-s 1] [-t 2.5]
8+
9+
NOTE: For Reference TSC Frequency, put the value of frequency in Model Name of
10+
lscpu output, or read 0x16 leaf of CPUID. For more information read about
11+
cpuid instruction in x86
12+
'''
13+
14+
from bcc import BPF, PerfType, PerfHWConfig, utils, PerfSWConfig
15+
from optparse import OptionParser
16+
17+
parser = OptionParser()
18+
parser.add_option('-s', '--sample-freq', dest='sample_freq', help='Frequency Sample Rate in Hz', type=int, default=1)
19+
parser.add_option('-t', '--tsc-freq', dest='tsc_freq', help='Reference Clock Frequency in GHz (see lscpu or cpuid)', type=float, default=2.5)
20+
(option, args) = parser.parse_args()
21+
22+
code = '''
23+
# include <linux/bpf.h>
24+
# include <uapi/linux/bpf_perf_event.h>
25+
# include <uapi/linux/ptrace.h>
26+
27+
/*
28+
- Structure to hold the last sample data as well as to output
29+
differential data via perf event buffer.
30+
*/
31+
struct PerfData {
32+
u64 cycles;
33+
u64 ref_cycles;
34+
};
35+
36+
// Perf Events array
37+
BPF_PERF_ARRAY(cycles, MAX_CPUS);
38+
BPF_PERF_ARRAY(ref_cycles, MAX_CPUS);
39+
40+
// Per CPU array to store the last samples.
41+
BPF_PERCPU_ARRAY(last_sample, struct PerfData, MAX_CPUS);
42+
43+
// Perf Ouptut Buffer
44+
BPF_PERF_OUTPUT(output);
45+
46+
void get_perf_counters(struct bpf_perf_event_data* ctx) {
47+
u32 cpu = bpf_get_smp_processor_id();
48+
/*
49+
NOTE: Use bpf_perf_event_value is recommended over
50+
bpf_perf_event_read or map.perf_read() due to
51+
issues in ABI. map.perf_read_value() need to be
52+
implemented in future.
53+
*/
54+
u64 cyc = cycles.perf_read(cpu);
55+
u64 ref = ref_cycles.perf_read(cpu);
56+
57+
struct PerfData result;
58+
struct PerfData* ptr = last_sample.lookup(&cpu);
59+
60+
if (ptr) {
61+
result.cycles = cyc - ptr->cycles;
62+
result.ref_cycles = ref - ptr->ref_cycles;
63+
ptr->cycles = cyc;
64+
ptr->ref_cycles = ref;
65+
output.perf_submit(ctx, &result, sizeof(struct PerfData));
66+
} else {
67+
result.cycles = cyc;
68+
result.ref_cycles = ref;
69+
last_sample.insert(&cpu, &result);
70+
}
71+
}
72+
'''
73+
74+
max_cpus = len(utils.get_online_cpus())
75+
b = BPF(text=code, cflags=['-DMAX_CPUS=%s' % str(max_cpus)])
76+
77+
# Cycles and Ref Cycles counters are required to measure frequency.
78+
b['cycles'].open_perf_event(PerfType.HARDWARE, PerfHWConfig.CPU_CYCLES)
79+
b['ref_cycles'].open_perf_event(PerfType.HARDWARE, PerfHWConfig.REF_CPU_CYCLES)
80+
81+
# A dummy perf event which will get triggered at every Sample Frequency.
82+
b.attach_perf_event(ev_type=PerfType.SOFTWARE,
83+
ev_config=PerfSWConfig.CPU_CLOCK,
84+
fn_name='get_perf_counters',
85+
sample_freq=option.sample_freq)
86+
87+
88+
def print_data(cpu, data, size):
89+
e = b["output"].event(data)
90+
print "%-4d %-16d %-16d %-16.2f" % (cpu, e.cycles,
91+
e.ref_cycles,
92+
e.cycles * option.tsc_freq / e.ref_cycles)
93+
94+
95+
print "Counters Data"
96+
print "%-4s %-16s %-16s %-16s" % ('CPU', 'CLOCK', 'REF-CYCLES', 'FREQ')
97+
98+
b['output'].open_perf_buffer(print_data)
99+
100+
while True:
101+
try:
102+
b.perf_buffer_poll()
103+
except KeyboardInterrupt:
104+
exit()

0 commit comments

Comments
 (0)