1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env python 2*387f9dfdSAndroid Build Coastguard Worker# @lint-avoid-python-3-compatibility-imports 3*387f9dfdSAndroid Build Coastguard Worker# 4*387f9dfdSAndroid Build Coastguard Worker# slabratetop Summarize kmem_cache_alloc() calls. 5*387f9dfdSAndroid Build Coastguard Worker# For Linux, uses BCC, eBPF. 6*387f9dfdSAndroid Build Coastguard Worker# 7*387f9dfdSAndroid Build Coastguard Worker# USAGE: slabratetop [-h] [-C] [-r MAXROWS] [interval] [count] 8*387f9dfdSAndroid Build Coastguard Worker# 9*387f9dfdSAndroid Build Coastguard Worker# This uses in-kernel BPF maps to store cache summaries for efficiency. 10*387f9dfdSAndroid Build Coastguard Worker# 11*387f9dfdSAndroid Build Coastguard Worker# SEE ALSO: slabtop(1), which shows the cache volumes. 12*387f9dfdSAndroid Build Coastguard Worker# 13*387f9dfdSAndroid Build Coastguard Worker# Copyright 2016 Netflix, Inc. 14*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License") 15*387f9dfdSAndroid Build Coastguard Worker# 16*387f9dfdSAndroid Build Coastguard Worker# 15-Oct-2016 Brendan Gregg Created this. 17*387f9dfdSAndroid Build Coastguard Worker# 23-Jan-2023 Rong Tao Introduce kernel internal data structure and 18*387f9dfdSAndroid Build Coastguard Worker# functions to temporarily solve problem for 19*387f9dfdSAndroid Build Coastguard Worker# >=5.16(TODO: fix this workaround) 20*387f9dfdSAndroid Build Coastguard Worker 21*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function 22*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF 23*387f9dfdSAndroid Build Coastguard Workerfrom bcc.utils import printb 24*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep, strftime 25*387f9dfdSAndroid Build Coastguard Workerimport argparse 26*387f9dfdSAndroid Build Coastguard Workerfrom subprocess import call 27*387f9dfdSAndroid Build Coastguard Worker 28*387f9dfdSAndroid Build Coastguard Worker# arguments 29*387f9dfdSAndroid Build Coastguard Workerexamples = """examples: 30*387f9dfdSAndroid Build Coastguard Worker ./slabratetop # kmem_cache_alloc() top, 1 second refresh 31*387f9dfdSAndroid Build Coastguard Worker ./slabratetop -C # don't clear the screen 32*387f9dfdSAndroid Build Coastguard Worker ./slabratetop 5 # 5 second summaries 33*387f9dfdSAndroid Build Coastguard Worker ./slabratetop 5 10 # 5 second summaries, 10 times only 34*387f9dfdSAndroid Build Coastguard Worker""" 35*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser( 36*387f9dfdSAndroid Build Coastguard Worker description="Kernel SLAB/SLUB memory cache allocation rate top", 37*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 38*387f9dfdSAndroid Build Coastguard Worker epilog=examples) 39*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-C", "--noclear", action="store_true", 40*387f9dfdSAndroid Build Coastguard Worker help="don't clear the screen") 41*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-r", "--maxrows", default=20, 42*387f9dfdSAndroid Build Coastguard Worker help="maximum rows to print, default 20") 43*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("interval", nargs="?", default=1, 44*387f9dfdSAndroid Build Coastguard Worker help="output interval, in seconds") 45*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("count", nargs="?", default=99999999, 46*387f9dfdSAndroid Build Coastguard Worker help="number of outputs") 47*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true", 48*387f9dfdSAndroid Build Coastguard Worker help=argparse.SUPPRESS) 49*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args() 50*387f9dfdSAndroid Build Coastguard Workerinterval = int(args.interval) 51*387f9dfdSAndroid Build Coastguard Workercountdown = int(args.count) 52*387f9dfdSAndroid Build Coastguard Workermaxrows = int(args.maxrows) 53*387f9dfdSAndroid Build Coastguard Workerclear = not int(args.noclear) 54*387f9dfdSAndroid Build Coastguard Workerdebug = 0 55*387f9dfdSAndroid Build Coastguard Worker 56*387f9dfdSAndroid Build Coastguard Worker# linux stats 57*387f9dfdSAndroid Build Coastguard Workerloadavg = "/proc/loadavg" 58*387f9dfdSAndroid Build Coastguard Worker 59*387f9dfdSAndroid Build Coastguard Worker# define BPF program 60*387f9dfdSAndroid Build Coastguard Workerbpf_text = """ 61*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h> 62*387f9dfdSAndroid Build Coastguard Worker#include <linux/mm.h> 63*387f9dfdSAndroid Build Coastguard Worker#include <linux/kasan.h> 64*387f9dfdSAndroid Build Coastguard Worker 65*387f9dfdSAndroid Build Coastguard Worker// memcg_cache_params is a part of kmem_cache, but is not publicly exposed in 66*387f9dfdSAndroid Build Coastguard Worker// kernel versions 5.4 to 5.8. Define an empty struct for it here to allow the 67*387f9dfdSAndroid Build Coastguard Worker// bpf program to compile. It has been completely removed in kernel version 68*387f9dfdSAndroid Build Coastguard Worker// 5.9, but it does not hurt to have it here for versions 5.4 to 5.8. 69*387f9dfdSAndroid Build Coastguard Workerstruct memcg_cache_params {}; 70*387f9dfdSAndroid Build Coastguard Worker 71*387f9dfdSAndroid Build Coastguard Worker// introduce kernel interval slab structure and slab_address() function, solved 72*387f9dfdSAndroid Build Coastguard Worker// 'undefined' error for >=5.16. TODO: we should fix this workaround if BCC 73*387f9dfdSAndroid Build Coastguard Worker// framework support BTF/CO-RE. 74*387f9dfdSAndroid Build Coastguard Workerstruct slab { 75*387f9dfdSAndroid Build Coastguard Worker unsigned long __page_flags; 76*387f9dfdSAndroid Build Coastguard Worker 77*387f9dfdSAndroid Build Coastguard Worker#if defined(CONFIG_SLAB) 78*387f9dfdSAndroid Build Coastguard Worker 79*387f9dfdSAndroid Build Coastguard Worker struct kmem_cache *slab_cache; 80*387f9dfdSAndroid Build Coastguard Worker union { 81*387f9dfdSAndroid Build Coastguard Worker struct { 82*387f9dfdSAndroid Build Coastguard Worker struct list_head slab_list; 83*387f9dfdSAndroid Build Coastguard Worker void *freelist; /* array of free object indexes */ 84*387f9dfdSAndroid Build Coastguard Worker void *s_mem; /* first object */ 85*387f9dfdSAndroid Build Coastguard Worker }; 86*387f9dfdSAndroid Build Coastguard Worker struct rcu_head rcu_head; 87*387f9dfdSAndroid Build Coastguard Worker }; 88*387f9dfdSAndroid Build Coastguard Worker unsigned int active; 89*387f9dfdSAndroid Build Coastguard Worker 90*387f9dfdSAndroid Build Coastguard Worker#elif defined(CONFIG_SLUB) 91*387f9dfdSAndroid Build Coastguard Worker 92*387f9dfdSAndroid Build Coastguard Worker struct kmem_cache *slab_cache; 93*387f9dfdSAndroid Build Coastguard Worker union { 94*387f9dfdSAndroid Build Coastguard Worker struct { 95*387f9dfdSAndroid Build Coastguard Worker union { 96*387f9dfdSAndroid Build Coastguard Worker struct list_head slab_list; 97*387f9dfdSAndroid Build Coastguard Worker#ifdef CONFIG_SLUB_CPU_PARTIAL 98*387f9dfdSAndroid Build Coastguard Worker struct { 99*387f9dfdSAndroid Build Coastguard Worker struct slab *next; 100*387f9dfdSAndroid Build Coastguard Worker int slabs; /* Nr of slabs left */ 101*387f9dfdSAndroid Build Coastguard Worker }; 102*387f9dfdSAndroid Build Coastguard Worker#endif 103*387f9dfdSAndroid Build Coastguard Worker }; 104*387f9dfdSAndroid Build Coastguard Worker /* Double-word boundary */ 105*387f9dfdSAndroid Build Coastguard Worker void *freelist; /* first free object */ 106*387f9dfdSAndroid Build Coastguard Worker union { 107*387f9dfdSAndroid Build Coastguard Worker unsigned long counters; 108*387f9dfdSAndroid Build Coastguard Worker struct { 109*387f9dfdSAndroid Build Coastguard Worker unsigned inuse:16; 110*387f9dfdSAndroid Build Coastguard Worker unsigned objects:15; 111*387f9dfdSAndroid Build Coastguard Worker unsigned frozen:1; 112*387f9dfdSAndroid Build Coastguard Worker }; 113*387f9dfdSAndroid Build Coastguard Worker }; 114*387f9dfdSAndroid Build Coastguard Worker }; 115*387f9dfdSAndroid Build Coastguard Worker struct rcu_head rcu_head; 116*387f9dfdSAndroid Build Coastguard Worker }; 117*387f9dfdSAndroid Build Coastguard Worker unsigned int __unused; 118*387f9dfdSAndroid Build Coastguard Worker 119*387f9dfdSAndroid Build Coastguard Worker#elif defined(CONFIG_SLOB) 120*387f9dfdSAndroid Build Coastguard Worker 121*387f9dfdSAndroid Build Coastguard Worker struct list_head slab_list; 122*387f9dfdSAndroid Build Coastguard Worker void *__unused_1; 123*387f9dfdSAndroid Build Coastguard Worker void *freelist; /* first free block */ 124*387f9dfdSAndroid Build Coastguard Worker long units; 125*387f9dfdSAndroid Build Coastguard Worker unsigned int __unused_2; 126*387f9dfdSAndroid Build Coastguard Worker 127*387f9dfdSAndroid Build Coastguard Worker#else 128*387f9dfdSAndroid Build Coastguard Worker#error "Unexpected slab allocator configured" 129*387f9dfdSAndroid Build Coastguard Worker#endif 130*387f9dfdSAndroid Build Coastguard Worker 131*387f9dfdSAndroid Build Coastguard Worker atomic_t __page_refcount; 132*387f9dfdSAndroid Build Coastguard Worker#ifdef CONFIG_MEMCG 133*387f9dfdSAndroid Build Coastguard Worker unsigned long memcg_data; 134*387f9dfdSAndroid Build Coastguard Worker#endif 135*387f9dfdSAndroid Build Coastguard Worker}; 136*387f9dfdSAndroid Build Coastguard Worker 137*387f9dfdSAndroid Build Coastguard Worker// slab_address() will not be used, and NULL will be returned directly, which 138*387f9dfdSAndroid Build Coastguard Worker// can avoid adaptation of different kernel versions 139*387f9dfdSAndroid Build Coastguard Workerstatic inline void *slab_address(const struct slab *slab) 140*387f9dfdSAndroid Build Coastguard Worker{ 141*387f9dfdSAndroid Build Coastguard Worker return NULL; 142*387f9dfdSAndroid Build Coastguard Worker} 143*387f9dfdSAndroid Build Coastguard Worker 144*387f9dfdSAndroid Build Coastguard Worker#ifdef CONFIG_64BIT 145*387f9dfdSAndroid Build Coastguard Workertypedef __uint128_t freelist_full_t; 146*387f9dfdSAndroid Build Coastguard Worker#else 147*387f9dfdSAndroid Build Coastguard Workertypedef u64 freelist_full_t; 148*387f9dfdSAndroid Build Coastguard Worker#endif 149*387f9dfdSAndroid Build Coastguard Worker 150*387f9dfdSAndroid Build Coastguard Workertypedef union { 151*387f9dfdSAndroid Build Coastguard Worker struct { 152*387f9dfdSAndroid Build Coastguard Worker void *freelist; 153*387f9dfdSAndroid Build Coastguard Worker unsigned long counter; 154*387f9dfdSAndroid Build Coastguard Worker }; 155*387f9dfdSAndroid Build Coastguard Worker freelist_full_t full; 156*387f9dfdSAndroid Build Coastguard Worker} freelist_aba_t; 157*387f9dfdSAndroid Build Coastguard Worker 158*387f9dfdSAndroid Build Coastguard Worker#ifdef CONFIG_SLUB 159*387f9dfdSAndroid Build Coastguard Worker#include <linux/slub_def.h> 160*387f9dfdSAndroid Build Coastguard Worker#else 161*387f9dfdSAndroid Build Coastguard Worker#include <linux/slab_def.h> 162*387f9dfdSAndroid Build Coastguard Worker#endif 163*387f9dfdSAndroid Build Coastguard Worker 164*387f9dfdSAndroid Build Coastguard Worker#define CACHE_NAME_SIZE 32 165*387f9dfdSAndroid Build Coastguard Worker 166*387f9dfdSAndroid Build Coastguard Worker// the key for the output summary 167*387f9dfdSAndroid Build Coastguard Workerstruct info_t { 168*387f9dfdSAndroid Build Coastguard Worker char name[CACHE_NAME_SIZE]; 169*387f9dfdSAndroid Build Coastguard Worker}; 170*387f9dfdSAndroid Build Coastguard Worker 171*387f9dfdSAndroid Build Coastguard Worker// the value of the output summary 172*387f9dfdSAndroid Build Coastguard Workerstruct val_t { 173*387f9dfdSAndroid Build Coastguard Worker u64 count; 174*387f9dfdSAndroid Build Coastguard Worker u64 size; 175*387f9dfdSAndroid Build Coastguard Worker}; 176*387f9dfdSAndroid Build Coastguard Worker 177*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(counts, struct info_t, struct val_t); 178*387f9dfdSAndroid Build Coastguard Worker 179*387f9dfdSAndroid Build Coastguard Workerint kprobe__kmem_cache_alloc(struct pt_regs *ctx, struct kmem_cache *cachep) 180*387f9dfdSAndroid Build Coastguard Worker{ 181*387f9dfdSAndroid Build Coastguard Worker struct info_t info = {}; 182*387f9dfdSAndroid Build Coastguard Worker const char *name = cachep->name; 183*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&info.name, sizeof(info.name), name); 184*387f9dfdSAndroid Build Coastguard Worker 185*387f9dfdSAndroid Build Coastguard Worker struct val_t *valp, zero = {}; 186*387f9dfdSAndroid Build Coastguard Worker valp = counts.lookup_or_try_init(&info, &zero); 187*387f9dfdSAndroid Build Coastguard Worker if (valp) { 188*387f9dfdSAndroid Build Coastguard Worker valp->count++; 189*387f9dfdSAndroid Build Coastguard Worker valp->size += cachep->size; 190*387f9dfdSAndroid Build Coastguard Worker } 191*387f9dfdSAndroid Build Coastguard Worker 192*387f9dfdSAndroid Build Coastguard Worker return 0; 193*387f9dfdSAndroid Build Coastguard Worker} 194*387f9dfdSAndroid Build Coastguard Worker""" 195*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf: 196*387f9dfdSAndroid Build Coastguard Worker print(bpf_text) 197*387f9dfdSAndroid Build Coastguard Worker if args.ebpf: 198*387f9dfdSAndroid Build Coastguard Worker exit() 199*387f9dfdSAndroid Build Coastguard Worker 200*387f9dfdSAndroid Build Coastguard Worker# initialize BPF 201*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text) 202*387f9dfdSAndroid Build Coastguard Worker 203*387f9dfdSAndroid Build Coastguard Workerprint('Tracing... Output every %d secs. Hit Ctrl-C to end' % interval) 204*387f9dfdSAndroid Build Coastguard Worker 205*387f9dfdSAndroid Build Coastguard Worker# output 206*387f9dfdSAndroid Build Coastguard Workerexiting = 0 207*387f9dfdSAndroid Build Coastguard Workerwhile 1: 208*387f9dfdSAndroid Build Coastguard Worker try: 209*387f9dfdSAndroid Build Coastguard Worker sleep(interval) 210*387f9dfdSAndroid Build Coastguard Worker except KeyboardInterrupt: 211*387f9dfdSAndroid Build Coastguard Worker exiting = 1 212*387f9dfdSAndroid Build Coastguard Worker 213*387f9dfdSAndroid Build Coastguard Worker # header 214*387f9dfdSAndroid Build Coastguard Worker if clear: 215*387f9dfdSAndroid Build Coastguard Worker call("clear") 216*387f9dfdSAndroid Build Coastguard Worker else: 217*387f9dfdSAndroid Build Coastguard Worker print() 218*387f9dfdSAndroid Build Coastguard Worker with open(loadavg) as stats: 219*387f9dfdSAndroid Build Coastguard Worker print("%-8s loadavg: %s" % (strftime("%H:%M:%S"), stats.read())) 220*387f9dfdSAndroid Build Coastguard Worker print("%-32s %6s %10s" % ("CACHE", "ALLOCS", "BYTES")) 221*387f9dfdSAndroid Build Coastguard Worker 222*387f9dfdSAndroid Build Coastguard Worker # by-TID output 223*387f9dfdSAndroid Build Coastguard Worker counts = b.get_table("counts") 224*387f9dfdSAndroid Build Coastguard Worker line = 0 225*387f9dfdSAndroid Build Coastguard Worker for k, v in reversed(sorted(counts.items(), 226*387f9dfdSAndroid Build Coastguard Worker key=lambda counts: counts[1].size)): 227*387f9dfdSAndroid Build Coastguard Worker printb(b"%-32s %6d %10d" % (k.name, v.count, v.size)) 228*387f9dfdSAndroid Build Coastguard Worker 229*387f9dfdSAndroid Build Coastguard Worker line += 1 230*387f9dfdSAndroid Build Coastguard Worker if line >= maxrows: 231*387f9dfdSAndroid Build Coastguard Worker break 232*387f9dfdSAndroid Build Coastguard Worker counts.clear() 233*387f9dfdSAndroid Build Coastguard Worker 234*387f9dfdSAndroid Build Coastguard Worker countdown -= 1 235*387f9dfdSAndroid Build Coastguard Worker if exiting or countdown == 0: 236*387f9dfdSAndroid Build Coastguard Worker print("Detaching...") 237*387f9dfdSAndroid Build Coastguard Worker exit() 238