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