1#!/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# 10# SEE ALSO: perf top -e cache-misses -e cache-references -a -ns pid,cpu,comm 11# 12# 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") 33parser.add_argument("--ebpf", action="store_true", 34 help=argparse.SUPPRESS) 35args = parser.parse_args() 36 37# load BPF program 38bpf_text=""" 39#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 61 miss_count.increment(key, ctx->sample_period); 62 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 70 ref_count.increment(key, ctx->sample_period); 71 72 return 0; 73} 74""" 75 76if args.ebpf: 77 print(bpf_text) 78 exit() 79 80b = BPF(text=bpf_text) 81try: 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() 91 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( 116 k.pid, k.name.decode('utf-8', 'replace'), k.cpu, v.value, miss, 117 (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)) 120