1#!/usr/bin/python 2# @lint-avoid-python-3-compatibility-imports 3# 4# slabratetop Summarize kmem_cache_alloc() calls. 5# For Linux, uses BCC, eBPF. 6# 7# USAGE: slabratetop [-h] [-C] [-r MAXROWS] [interval] [count] 8# 9# This uses in-kernel BPF maps to store cache summaries for efficiency. 10# 11# SEE ALSO: slabtop(1), which shows the cache volumes. 12# 13# Copyright 2016 Netflix, Inc. 14# Licensed under the Apache License, Version 2.0 (the "License") 15# 16# 15-Oct-2016 Brendan Gregg Created this. 17 18from __future__ import print_function 19from bcc import BPF 20from bcc.utils import printb 21from time import sleep, strftime 22import argparse 23import signal 24from subprocess import call 25 26# arguments 27examples = """examples: 28 ./slabratetop # kmem_cache_alloc() top, 1 second refresh 29 ./slabratetop -C # don't clear the screen 30 ./slabratetop 5 # 5 second summaries 31 ./slabratetop 5 10 # 5 second summaries, 10 times only 32""" 33parser = argparse.ArgumentParser( 34 description="Kernel SLAB/SLUB memory cache allocation rate top", 35 formatter_class=argparse.RawDescriptionHelpFormatter, 36 epilog=examples) 37parser.add_argument("-C", "--noclear", action="store_true", 38 help="don't clear the screen") 39parser.add_argument("-r", "--maxrows", default=20, 40 help="maximum rows to print, default 20") 41parser.add_argument("interval", nargs="?", default=1, 42 help="output interval, in seconds") 43parser.add_argument("count", nargs="?", default=99999999, 44 help="number of outputs") 45parser.add_argument("--ebpf", action="store_true", 46 help=argparse.SUPPRESS) 47args = parser.parse_args() 48interval = int(args.interval) 49countdown = int(args.count) 50maxrows = int(args.maxrows) 51clear = not int(args.noclear) 52debug = 0 53 54# linux stats 55loadavg = "/proc/loadavg" 56 57# signal handler 58def signal_ignore(signal, frame): 59 print() 60 61# define BPF program 62bpf_text = """ 63#include <uapi/linux/ptrace.h> 64#include <linux/mm.h> 65#include <linux/slab.h> 66#ifdef CONFIG_SLUB 67#include <linux/slub_def.h> 68#else 69#include <linux/slab_def.h> 70#endif 71 72#define CACHE_NAME_SIZE 32 73 74// the key for the output summary 75struct info_t { 76 char name[CACHE_NAME_SIZE]; 77}; 78 79// the value of the output summary 80struct val_t { 81 u64 count; 82 u64 size; 83}; 84 85BPF_HASH(counts, struct info_t, struct val_t); 86 87int kprobe__kmem_cache_alloc(struct pt_regs *ctx, struct kmem_cache *cachep) 88{ 89 struct info_t info = {}; 90 const char *name = cachep->name; 91 bpf_probe_read(&info.name, sizeof(info.name), name); 92 93 struct val_t *valp, zero = {}; 94 valp = counts.lookup_or_init(&info, &zero); 95 valp->count++; 96 valp->size += cachep->size; 97 98 return 0; 99} 100""" 101if debug or args.ebpf: 102 print(bpf_text) 103 if args.ebpf: 104 exit() 105 106# initialize BPF 107b = BPF(text=bpf_text) 108 109print('Tracing... Output every %d secs. Hit Ctrl-C to end' % interval) 110 111# output 112exiting = 0 113while 1: 114 try: 115 sleep(interval) 116 except KeyboardInterrupt: 117 exiting = 1 118 119 # header 120 if clear: 121 call("clear") 122 else: 123 print() 124 with open(loadavg) as stats: 125 print("%-8s loadavg: %s" % (strftime("%H:%M:%S"), stats.read())) 126 print("%-32s %6s %10s" % ("CACHE", "ALLOCS", "BYTES")) 127 128 # by-TID output 129 counts = b.get_table("counts") 130 line = 0 131 for k, v in reversed(sorted(counts.items(), 132 key=lambda counts: counts[1].size)): 133 printb(b"%-32s %6d %10d" % (k.name, v.count, v.size)) 134 135 line += 1 136 if line >= maxrows: 137 break 138 counts.clear() 139 140 countdown -= 1 141 if exiting or countdown == 0: 142 print("Detaching...") 143 exit() 144