xref: /aosp_15_r20/external/bcc/tools/llcstat.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env python
2*387f9dfdSAndroid Build Coastguard Worker#
3*387f9dfdSAndroid Build Coastguard Worker# llcstat.py Summarize cache references and cache misses by PID.
4*387f9dfdSAndroid Build Coastguard Worker#            Cache reference and cache miss are corresponding events defined in
5*387f9dfdSAndroid Build Coastguard Worker#            uapi/linux/perf_event.h, it varies to different architecture.
6*387f9dfdSAndroid Build Coastguard Worker#            On x86-64, they mean LLC references and LLC misses.
7*387f9dfdSAndroid Build Coastguard Worker#
8*387f9dfdSAndroid Build Coastguard Worker#            For Linux, uses BCC, eBPF. Embedded C.
9*387f9dfdSAndroid Build Coastguard Worker#
10*387f9dfdSAndroid Build Coastguard Worker# SEE ALSO: perf top -e cache-misses -e cache-references -a -ns pid,cpu,comm
11*387f9dfdSAndroid Build Coastguard Worker#
12*387f9dfdSAndroid Build Coastguard Worker# REQUIRES: Linux 4.9+ (BPF_PROG_TYPE_PERF_EVENT support).
13*387f9dfdSAndroid Build Coastguard Worker#
14*387f9dfdSAndroid Build Coastguard Worker# Copyright (c) 2016 Facebook, Inc.
15*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License")
16*387f9dfdSAndroid Build Coastguard Worker#
17*387f9dfdSAndroid Build Coastguard Worker# 19-Oct-2016   Teng Qin   Created this.
18*387f9dfdSAndroid Build Coastguard Worker# 20-Jun-2022   YeZhengMao Added tid info.
19*387f9dfdSAndroid Build Coastguard Worker
20*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function
21*387f9dfdSAndroid Build Coastguard Workerimport argparse
22*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF, PerfType, PerfHWConfig
23*387f9dfdSAndroid Build Coastguard Workerimport signal
24*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep
25*387f9dfdSAndroid Build Coastguard Worker
26*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser(
27*387f9dfdSAndroid Build Coastguard Worker    description="Summarize cache references and misses by PID",
28*387f9dfdSAndroid Build Coastguard Worker    formatter_class=argparse.RawDescriptionHelpFormatter)
29*387f9dfdSAndroid Build Coastguard Workerparser.add_argument(
30*387f9dfdSAndroid Build Coastguard Worker    "-c", "--sample_period", type=int, default=100,
31*387f9dfdSAndroid Build Coastguard Worker    help="Sample one in this many number of cache reference / miss events")
32*387f9dfdSAndroid Build Coastguard Workerparser.add_argument(
33*387f9dfdSAndroid Build Coastguard Worker    "duration", nargs="?", default=10, help="Duration, in seconds, to run")
34*387f9dfdSAndroid Build Coastguard Workerparser.add_argument(
35*387f9dfdSAndroid Build Coastguard Worker    "-t", "--tid", action="store_true",
36*387f9dfdSAndroid Build Coastguard Worker    help="Summarize cache references and misses by PID/TID"
37*387f9dfdSAndroid Build Coastguard Worker)
38*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true",
39*387f9dfdSAndroid Build Coastguard Worker    help=argparse.SUPPRESS)
40*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args()
41*387f9dfdSAndroid Build Coastguard Worker
42*387f9dfdSAndroid Build Coastguard Worker# load BPF program
43*387f9dfdSAndroid Build Coastguard Workerbpf_text="""
44*387f9dfdSAndroid Build Coastguard Worker#include <linux/ptrace.h>
45*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/bpf_perf_event.h>
46*387f9dfdSAndroid Build Coastguard Worker
47*387f9dfdSAndroid Build Coastguard Workerstruct key_t {
48*387f9dfdSAndroid Build Coastguard Worker    int cpu;
49*387f9dfdSAndroid Build Coastguard Worker    u32 pid;
50*387f9dfdSAndroid Build Coastguard Worker    u32 tid;
51*387f9dfdSAndroid Build Coastguard Worker    char name[TASK_COMM_LEN];
52*387f9dfdSAndroid Build Coastguard Worker};
53*387f9dfdSAndroid Build Coastguard Worker
54*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(ref_count, struct key_t);
55*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(miss_count, struct key_t);
56*387f9dfdSAndroid Build Coastguard Worker
57*387f9dfdSAndroid Build Coastguard Workerstatic inline __attribute__((always_inline)) void get_key(struct key_t* key) {
58*387f9dfdSAndroid Build Coastguard Worker    u64 pid_tgid = bpf_get_current_pid_tgid();
59*387f9dfdSAndroid Build Coastguard Worker    key->cpu = bpf_get_smp_processor_id();
60*387f9dfdSAndroid Build Coastguard Worker    key->pid = pid_tgid >> 32;
61*387f9dfdSAndroid Build Coastguard Worker    key->tid = GET_TID ? (u32)pid_tgid : key->pid;
62*387f9dfdSAndroid Build Coastguard Worker    bpf_get_current_comm(&(key->name), sizeof(key->name));
63*387f9dfdSAndroid Build Coastguard Worker}
64*387f9dfdSAndroid Build Coastguard Worker
65*387f9dfdSAndroid Build Coastguard Workerint on_cache_miss(struct bpf_perf_event_data *ctx) {
66*387f9dfdSAndroid Build Coastguard Worker    struct key_t key = {};
67*387f9dfdSAndroid Build Coastguard Worker    get_key(&key);
68*387f9dfdSAndroid Build Coastguard Worker
69*387f9dfdSAndroid Build Coastguard Worker    miss_count.increment(key, ctx->sample_period);
70*387f9dfdSAndroid Build Coastguard Worker
71*387f9dfdSAndroid Build Coastguard Worker    return 0;
72*387f9dfdSAndroid Build Coastguard Worker}
73*387f9dfdSAndroid Build Coastguard Worker
74*387f9dfdSAndroid Build Coastguard Workerint on_cache_ref(struct bpf_perf_event_data *ctx) {
75*387f9dfdSAndroid Build Coastguard Worker    struct key_t key = {};
76*387f9dfdSAndroid Build Coastguard Worker    get_key(&key);
77*387f9dfdSAndroid Build Coastguard Worker
78*387f9dfdSAndroid Build Coastguard Worker    ref_count.increment(key, ctx->sample_period);
79*387f9dfdSAndroid Build Coastguard Worker
80*387f9dfdSAndroid Build Coastguard Worker    return 0;
81*387f9dfdSAndroid Build Coastguard Worker}
82*387f9dfdSAndroid Build Coastguard Worker"""
83*387f9dfdSAndroid Build Coastguard Worker
84*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace("GET_TID", "1" if args.tid else "0")
85*387f9dfdSAndroid Build Coastguard Worker
86*387f9dfdSAndroid Build Coastguard Workerif args.ebpf:
87*387f9dfdSAndroid Build Coastguard Worker    print(bpf_text)
88*387f9dfdSAndroid Build Coastguard Worker    exit()
89*387f9dfdSAndroid Build Coastguard Worker
90*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text)
91*387f9dfdSAndroid Build Coastguard Workertry:
92*387f9dfdSAndroid Build Coastguard Worker    b.attach_perf_event(
93*387f9dfdSAndroid Build Coastguard Worker        ev_type=PerfType.HARDWARE, ev_config=PerfHWConfig.CACHE_MISSES,
94*387f9dfdSAndroid Build Coastguard Worker        fn_name="on_cache_miss", sample_period=args.sample_period)
95*387f9dfdSAndroid Build Coastguard Worker    b.attach_perf_event(
96*387f9dfdSAndroid Build Coastguard Worker        ev_type=PerfType.HARDWARE, ev_config=PerfHWConfig.CACHE_REFERENCES,
97*387f9dfdSAndroid Build Coastguard Worker        fn_name="on_cache_ref", sample_period=args.sample_period)
98*387f9dfdSAndroid Build Coastguard Workerexcept Exception:
99*387f9dfdSAndroid Build Coastguard Worker    print("Failed to attach to a hardware event. Is this a virtual machine?")
100*387f9dfdSAndroid Build Coastguard Worker    exit()
101*387f9dfdSAndroid Build Coastguard Worker
102*387f9dfdSAndroid Build Coastguard Workerprint("Running for {} seconds or hit Ctrl-C to end.".format(args.duration))
103*387f9dfdSAndroid Build Coastguard Worker
104*387f9dfdSAndroid Build Coastguard Workertry:
105*387f9dfdSAndroid Build Coastguard Worker    sleep(float(args.duration))
106*387f9dfdSAndroid Build Coastguard Workerexcept KeyboardInterrupt:
107*387f9dfdSAndroid Build Coastguard Worker    signal.signal(signal.SIGINT, lambda signal, frame: print())
108*387f9dfdSAndroid Build Coastguard Worker
109*387f9dfdSAndroid Build Coastguard Workermiss_count = {}
110*387f9dfdSAndroid Build Coastguard Workerfor (k, v) in b.get_table('miss_count').items():
111*387f9dfdSAndroid Build Coastguard Worker    if args.tid:
112*387f9dfdSAndroid Build Coastguard Worker        miss_count[(k.pid, k.tid, k.cpu, k.name)] = v.value
113*387f9dfdSAndroid Build Coastguard Worker    else:
114*387f9dfdSAndroid Build Coastguard Worker        miss_count[(k.pid, k.cpu, k.name)] = v.value
115*387f9dfdSAndroid Build Coastguard Worker
116*387f9dfdSAndroid Build Coastguard Workerheader_text = 'PID      '
117*387f9dfdSAndroid Build Coastguard Workerformat_text = '{:<8d} '
118*387f9dfdSAndroid Build Coastguard Workerif args.tid:
119*387f9dfdSAndroid Build Coastguard Worker    header_text += 'TID      '
120*387f9dfdSAndroid Build Coastguard Worker    format_text += '{:<8d} '
121*387f9dfdSAndroid Build Coastguard Worker
122*387f9dfdSAndroid Build Coastguard Workerheader_text += 'NAME             CPU     REFERENCE         MISS    HIT%'
123*387f9dfdSAndroid Build Coastguard Workerformat_text += '{:<16s} {:<4d} {:>12d} {:>12d} {:>6.2f}%'
124*387f9dfdSAndroid Build Coastguard Worker
125*387f9dfdSAndroid Build Coastguard Workerprint(header_text)
126*387f9dfdSAndroid Build Coastguard Workertot_ref = 0
127*387f9dfdSAndroid Build Coastguard Workertot_miss = 0
128*387f9dfdSAndroid Build Coastguard Workerfor (k, v) in b.get_table('ref_count').items():
129*387f9dfdSAndroid Build Coastguard Worker    try:
130*387f9dfdSAndroid Build Coastguard Worker        if args.tid:
131*387f9dfdSAndroid Build Coastguard Worker            miss = miss_count[(k.pid, k.tid, k.cpu, k.name)]
132*387f9dfdSAndroid Build Coastguard Worker        else:
133*387f9dfdSAndroid Build Coastguard Worker            miss = miss_count[(k.pid, k.cpu, k.name)]
134*387f9dfdSAndroid Build Coastguard Worker    except KeyError:
135*387f9dfdSAndroid Build Coastguard Worker        miss = 0
136*387f9dfdSAndroid Build Coastguard Worker    tot_ref += v.value
137*387f9dfdSAndroid Build Coastguard Worker    tot_miss += miss
138*387f9dfdSAndroid Build Coastguard Worker    # This happens on some PIDs due to missed counts caused by sampling
139*387f9dfdSAndroid Build Coastguard Worker    hit = (v.value - miss) if (v.value >= miss) else 0
140*387f9dfdSAndroid Build Coastguard Worker    if args.tid:
141*387f9dfdSAndroid Build Coastguard Worker        print(format_text.format(
142*387f9dfdSAndroid Build Coastguard Worker            k.pid, k.tid, k.name.decode('utf-8', 'replace'), k.cpu, v.value, miss,
143*387f9dfdSAndroid Build Coastguard Worker            (float(hit) / float(v.value)) * 100.0))
144*387f9dfdSAndroid Build Coastguard Worker    else:
145*387f9dfdSAndroid Build Coastguard Worker        print(format_text.format(
146*387f9dfdSAndroid Build Coastguard Worker            k.pid, k.name.decode('utf-8', 'replace'), k.cpu, v.value, miss,
147*387f9dfdSAndroid Build Coastguard Worker            (float(hit) / float(v.value)) * 100.0))
148*387f9dfdSAndroid Build Coastguard Workerprint('Total References: {} Total Misses: {} Hit Rate: {:.2f}%'.format(
149*387f9dfdSAndroid Build Coastguard Worker    tot_ref, tot_miss, (float(tot_ref - tot_miss) / float(tot_ref)) * 100.0))
150