blob: ec2c1f8aaa5c4630822fad4a70b159e1543493e3 [file] [log] [blame]
Teng Qine960eb72016-10-18 17:22:27 -07001#!/usr/bin/python
2#
3# llcstat.py Summarize cache references and cache misses by PID.
4# Cache reference and cache miss are corresponding events defined in
5# uapi/linux/perf_event.h, it varies to different architecture.
6# On x86-64, they mean LLC references and LLC misses.
7#
8# For Linux, uses BCC, eBPF. Embedded C.
9#
Ivan Babrou41d462b2018-07-08 13:09:35 -070010# SEE ALSO: perf top -e cache-misses -e cache-references -a -ns pid,cpu,comm
11#
Teng Qine960eb72016-10-18 17:22:27 -070012# REQUIRES: Linux 4.9+ (BPF_PROG_TYPE_PERF_EVENT support).
13#
14# Copyright (c) 2016 Facebook, Inc.
15# Licensed under the Apache License, Version 2.0 (the "License")
16#
17# 19-Oct-2016 Teng Qin Created this.
18
19from __future__ import print_function
20import argparse
21from bcc import BPF, PerfType, PerfHWConfig
22import signal
23from time import sleep
24
25parser = argparse.ArgumentParser(
26 description="Summarize cache references and misses by PID",
27 formatter_class=argparse.RawDescriptionHelpFormatter)
28parser.add_argument(
29 "-c", "--sample_period", type=int, default=100,
30 help="Sample one in this many number of cache reference / miss events")
31parser.add_argument(
32 "duration", nargs="?", default=10, help="Duration, in seconds, to run")
Nathan Scottcf0792f2018-02-02 16:56:50 +110033parser.add_argument("--ebpf", action="store_true",
34 help=argparse.SUPPRESS)
Teng Qine960eb72016-10-18 17:22:27 -070035args = parser.parse_args()
36
37# load BPF program
Nathan Scottcf0792f2018-02-02 16:56:50 +110038bpf_text="""
Teng Qine960eb72016-10-18 17:22:27 -070039#include <linux/ptrace.h>
40#include <uapi/linux/bpf_perf_event.h>
41
42struct key_t {
43 int cpu;
44 int pid;
45 char name[TASK_COMM_LEN];
46};
47
48BPF_HASH(ref_count, struct key_t);
49BPF_HASH(miss_count, struct key_t);
50
51static inline __attribute__((always_inline)) void get_key(struct key_t* key) {
52 key->cpu = bpf_get_smp_processor_id();
53 key->pid = bpf_get_current_pid_tgid();
54 bpf_get_current_comm(&(key->name), sizeof(key->name));
55}
56
57int on_cache_miss(struct bpf_perf_event_data *ctx) {
58 struct key_t key = {};
59 get_key(&key);
60
Javier Honduvilla Coto64bf9652018-08-01 06:50:19 +020061 miss_count.increment(key, ctx->sample_period);
Teng Qine960eb72016-10-18 17:22:27 -070062
63 return 0;
64}
65
66int on_cache_ref(struct bpf_perf_event_data *ctx) {
67 struct key_t key = {};
68 get_key(&key);
69
Javier Honduvilla Coto64bf9652018-08-01 06:50:19 +020070 ref_count.increment(key, ctx->sample_period);
Teng Qine960eb72016-10-18 17:22:27 -070071
72 return 0;
73}
Nathan Scottcf0792f2018-02-02 16:56:50 +110074"""
Teng Qine960eb72016-10-18 17:22:27 -070075
Nathan Scottcf0792f2018-02-02 16:56:50 +110076if args.ebpf:
77 print(bpf_text)
78 exit()
79
80b = BPF(text=bpf_text)
Jerome Marchandd274b662018-08-07 17:24:31 +020081try:
82 b.attach_perf_event(
83 ev_type=PerfType.HARDWARE, ev_config=PerfHWConfig.CACHE_MISSES,
84 fn_name="on_cache_miss", sample_period=args.sample_period)
85 b.attach_perf_event(
86 ev_type=PerfType.HARDWARE, ev_config=PerfHWConfig.CACHE_REFERENCES,
87 fn_name="on_cache_ref", sample_period=args.sample_period)
88except:
89 print("Failed to attach to a hardware event. Is this a virtual machine?")
90 exit()
Teng Qine960eb72016-10-18 17:22:27 -070091
92print("Running for {} seconds or hit Ctrl-C to end.".format(args.duration))
93
94try:
95 sleep(float(args.duration))
96except KeyboardInterrupt:
97 signal.signal(signal.SIGINT, lambda signal, frame: print())
98
99miss_count = {}
100for (k, v) in b.get_table('miss_count').items():
101 miss_count[(k.pid, k.cpu, k.name)] = v.value
102
103print('PID NAME CPU REFERENCE MISS HIT%')
104tot_ref = 0
105tot_miss = 0
106for (k, v) in b.get_table('ref_count').items():
107 try:
108 miss = miss_count[(k.pid, k.cpu, k.name)]
109 except KeyError:
110 miss = 0
111 tot_ref += v.value
112 tot_miss += miss
113 # This happens on some PIDs due to missed counts caused by sampling
114 hit = (v.value - miss) if (v.value >= miss) else 0
115 print('{:<8d} {:<16s} {:<4d} {:>12d} {:>12d} {:>6.2f}%'.format(
jeromemarchandb96ebcd2018-10-10 01:58:15 +0200116 k.pid, k.name.decode('utf-8', 'replace'), k.cpu, v.value, miss,
Teng Qine960eb72016-10-18 17:22:27 -0700117 (float(hit) / float(v.value)) * 100.0))
118print('Total References: {} Total Misses: {} Hit Rate: {:.2f}%'.format(
119 tot_ref, tot_miss, (float(tot_ref - tot_miss) / float(tot_ref)) * 100.0))