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# runqlen Summarize scheduler run queue length as a histogram. 5*387f9dfdSAndroid Build Coastguard Worker# For Linux, uses BCC, eBPF. 6*387f9dfdSAndroid Build Coastguard Worker# 7*387f9dfdSAndroid Build Coastguard Worker# This counts the length of the run queue, excluding the currently running 8*387f9dfdSAndroid Build Coastguard Worker# thread, and shows it as a histogram. 9*387f9dfdSAndroid Build Coastguard Worker# 10*387f9dfdSAndroid Build Coastguard Worker# Also answers run queue occupancy. 11*387f9dfdSAndroid Build Coastguard Worker# 12*387f9dfdSAndroid Build Coastguard Worker# USAGE: runqlen [-h] [-T] [-Q] [-m] [-D] [interval] [count] 13*387f9dfdSAndroid Build Coastguard Worker# 14*387f9dfdSAndroid Build Coastguard Worker# REQUIRES: Linux 4.9+ (BPF_PROG_TYPE_PERF_EVENT support). Under tools/old is 15*387f9dfdSAndroid Build Coastguard Worker# a version of this tool that may work on Linux 4.6 - 4.8. 16*387f9dfdSAndroid Build Coastguard Worker# 17*387f9dfdSAndroid Build Coastguard Worker# Copyright 2016 Netflix, Inc. 18*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License") 19*387f9dfdSAndroid Build Coastguard Worker# 20*387f9dfdSAndroid Build Coastguard Worker# 12-Dec-2016 Brendan Gregg Created this. 21*387f9dfdSAndroid Build Coastguard Worker 22*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function 23*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF, PerfType, PerfSWConfig, utils 24*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep, strftime 25*387f9dfdSAndroid Build Coastguard Workerfrom tempfile import NamedTemporaryFile 26*387f9dfdSAndroid Build Coastguard Workerfrom os import open, close, dup, unlink, O_WRONLY 27*387f9dfdSAndroid Build Coastguard Workerimport argparse 28*387f9dfdSAndroid Build Coastguard Worker 29*387f9dfdSAndroid Build Coastguard Worker# arguments 30*387f9dfdSAndroid Build Coastguard Workerexamples = """examples: 31*387f9dfdSAndroid Build Coastguard Worker ./runqlen # summarize run queue length as a histogram 32*387f9dfdSAndroid Build Coastguard Worker ./runqlen 1 10 # print 1 second summaries, 10 times 33*387f9dfdSAndroid Build Coastguard Worker ./runqlen -T 1 # 1s summaries and timestamps 34*387f9dfdSAndroid Build Coastguard Worker ./runqlen -O # report run queue occupancy 35*387f9dfdSAndroid Build Coastguard Worker ./runqlen -C # show each CPU separately 36*387f9dfdSAndroid Build Coastguard Worker""" 37*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser( 38*387f9dfdSAndroid Build Coastguard Worker description="Summarize scheduler run queue length as a histogram", 39*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 40*387f9dfdSAndroid Build Coastguard Worker epilog=examples) 41*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-T", "--timestamp", action="store_true", 42*387f9dfdSAndroid Build Coastguard Worker help="include timestamp on output") 43*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-O", "--runqocc", action="store_true", 44*387f9dfdSAndroid Build Coastguard Worker help="report run queue occupancy") 45*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-C", "--cpus", action="store_true", 46*387f9dfdSAndroid Build Coastguard Worker help="print output for each CPU separately") 47*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("interval", nargs="?", default=99999999, 48*387f9dfdSAndroid Build Coastguard Worker help="output interval, in seconds") 49*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("count", nargs="?", default=99999999, 50*387f9dfdSAndroid Build Coastguard Worker help="number of outputs") 51*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true", 52*387f9dfdSAndroid Build Coastguard Worker help=argparse.SUPPRESS) 53*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args() 54*387f9dfdSAndroid Build Coastguard Workercountdown = int(args.count) 55*387f9dfdSAndroid Build Coastguard Workerdebug = 0 56*387f9dfdSAndroid Build Coastguard Workerfrequency = 99 57*387f9dfdSAndroid Build Coastguard Worker 58*387f9dfdSAndroid Build Coastguard Worker# Linux 4.15 introduced a new field runnable_weight 59*387f9dfdSAndroid Build Coastguard Worker# in linux_src:kernel/sched/sched.h as 60*387f9dfdSAndroid Build Coastguard Worker# struct cfs_rq { 61*387f9dfdSAndroid Build Coastguard Worker# struct load_weight load; 62*387f9dfdSAndroid Build Coastguard Worker# unsigned long runnable_weight; 63*387f9dfdSAndroid Build Coastguard Worker# unsigned int nr_running, h_nr_running; 64*387f9dfdSAndroid Build Coastguard Worker# ...... 65*387f9dfdSAndroid Build Coastguard Worker# } 66*387f9dfdSAndroid Build Coastguard Worker# and this tool requires to access nr_running to get 67*387f9dfdSAndroid Build Coastguard Worker# runqueue len information. 68*387f9dfdSAndroid Build Coastguard Worker# 69*387f9dfdSAndroid Build Coastguard Worker# The commit which introduces cfs_rq->runnable_weight 70*387f9dfdSAndroid Build Coastguard Worker# field also introduces the field sched_entity->runnable_weight 71*387f9dfdSAndroid Build Coastguard Worker# where sched_entity is defined in linux_src:include/linux/sched.h. 72*387f9dfdSAndroid Build Coastguard Worker# 73*387f9dfdSAndroid Build Coastguard Worker# To cope with pre-4.15 and 4.15/post-4.15 releases, 74*387f9dfdSAndroid Build Coastguard Worker# we run a simple BPF program to detect whether 75*387f9dfdSAndroid Build Coastguard Worker# field sched_entity->runnable_weight exists. The existence of 76*387f9dfdSAndroid Build Coastguard Worker# this field should infer the existence of cfs_rq->runnable_weight. 77*387f9dfdSAndroid Build Coastguard Worker# 78*387f9dfdSAndroid Build Coastguard Worker# This will need maintenance as the relationship between these 79*387f9dfdSAndroid Build Coastguard Worker# two fields may change in the future. 80*387f9dfdSAndroid Build Coastguard Worker# 81*387f9dfdSAndroid Build Coastguard Workerdef check_runnable_weight_field(): 82*387f9dfdSAndroid Build Coastguard Worker # Define the bpf program for checking purpose 83*387f9dfdSAndroid Build Coastguard Worker bpf_check_text = """ 84*387f9dfdSAndroid Build Coastguard Worker#include <linux/sched.h> 85*387f9dfdSAndroid Build Coastguard Workerunsigned long dummy(struct sched_entity *entity) 86*387f9dfdSAndroid Build Coastguard Worker{ 87*387f9dfdSAndroid Build Coastguard Worker return entity->runnable_weight; 88*387f9dfdSAndroid Build Coastguard Worker} 89*387f9dfdSAndroid Build Coastguard Worker""" 90*387f9dfdSAndroid Build Coastguard Worker 91*387f9dfdSAndroid Build Coastguard Worker # Get a temporary file name 92*387f9dfdSAndroid Build Coastguard Worker tmp_file = NamedTemporaryFile(delete=False) 93*387f9dfdSAndroid Build Coastguard Worker tmp_file.close() 94*387f9dfdSAndroid Build Coastguard Worker 95*387f9dfdSAndroid Build Coastguard Worker # Duplicate and close stderr (fd = 2) 96*387f9dfdSAndroid Build Coastguard Worker old_stderr = dup(2) 97*387f9dfdSAndroid Build Coastguard Worker close(2) 98*387f9dfdSAndroid Build Coastguard Worker 99*387f9dfdSAndroid Build Coastguard Worker # Open a new file, should get fd number 2 100*387f9dfdSAndroid Build Coastguard Worker # This will avoid printing llvm errors on the screen 101*387f9dfdSAndroid Build Coastguard Worker fd = open(tmp_file.name, O_WRONLY) 102*387f9dfdSAndroid Build Coastguard Worker try: 103*387f9dfdSAndroid Build Coastguard Worker t = BPF(text=bpf_check_text) 104*387f9dfdSAndroid Build Coastguard Worker success_compile = True 105*387f9dfdSAndroid Build Coastguard Worker except: 106*387f9dfdSAndroid Build Coastguard Worker success_compile = False 107*387f9dfdSAndroid Build Coastguard Worker 108*387f9dfdSAndroid Build Coastguard Worker # Release the fd 2, and next dup should restore old stderr 109*387f9dfdSAndroid Build Coastguard Worker close(fd) 110*387f9dfdSAndroid Build Coastguard Worker dup(old_stderr) 111*387f9dfdSAndroid Build Coastguard Worker close(old_stderr) 112*387f9dfdSAndroid Build Coastguard Worker 113*387f9dfdSAndroid Build Coastguard Worker # remove the temporary file and return 114*387f9dfdSAndroid Build Coastguard Worker unlink(tmp_file.name) 115*387f9dfdSAndroid Build Coastguard Worker return success_compile 116*387f9dfdSAndroid Build Coastguard Worker 117*387f9dfdSAndroid Build Coastguard Worker 118*387f9dfdSAndroid Build Coastguard Worker# define BPF program 119*387f9dfdSAndroid Build Coastguard Workerbpf_text = """ 120*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h> 121*387f9dfdSAndroid Build Coastguard Worker#include <linux/sched.h> 122*387f9dfdSAndroid Build Coastguard Worker 123*387f9dfdSAndroid Build Coastguard Worker// Declare enough of cfs_rq to find nr_running, since we can't #import the 124*387f9dfdSAndroid Build Coastguard Worker// header. This will need maintenance. It is from kernel/sched/sched.h: 125*387f9dfdSAndroid Build Coastguard Worker// The runnable_weight field is removed from Linux 5.7.0 126*387f9dfdSAndroid Build Coastguard Workerstruct cfs_rq_partial { 127*387f9dfdSAndroid Build Coastguard Worker struct load_weight load; 128*387f9dfdSAndroid Build Coastguard Worker#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 7, 0) 129*387f9dfdSAndroid Build Coastguard Worker RUNNABLE_WEIGHT_FIELD 130*387f9dfdSAndroid Build Coastguard Worker#endif 131*387f9dfdSAndroid Build Coastguard Worker unsigned int nr_running, h_nr_running; 132*387f9dfdSAndroid Build Coastguard Worker}; 133*387f9dfdSAndroid Build Coastguard Worker 134*387f9dfdSAndroid Build Coastguard Workertypedef struct cpu_key { 135*387f9dfdSAndroid Build Coastguard Worker int cpu; 136*387f9dfdSAndroid Build Coastguard Worker unsigned int slot; 137*387f9dfdSAndroid Build Coastguard Worker} cpu_key_t; 138*387f9dfdSAndroid Build Coastguard WorkerSTORAGE 139*387f9dfdSAndroid Build Coastguard Worker 140*387f9dfdSAndroid Build Coastguard Workerint do_perf_event() 141*387f9dfdSAndroid Build Coastguard Worker{ 142*387f9dfdSAndroid Build Coastguard Worker unsigned int len = 0; 143*387f9dfdSAndroid Build Coastguard Worker pid_t pid = 0; 144*387f9dfdSAndroid Build Coastguard Worker struct task_struct *task = NULL; 145*387f9dfdSAndroid Build Coastguard Worker struct cfs_rq_partial *my_q = NULL; 146*387f9dfdSAndroid Build Coastguard Worker 147*387f9dfdSAndroid Build Coastguard Worker // Fetch the run queue length from task->se.cfs_rq->nr_running. This is an 148*387f9dfdSAndroid Build Coastguard Worker // unstable interface and may need maintenance. Perhaps a future version 149*387f9dfdSAndroid Build Coastguard Worker // of BPF will support task_rq(p) or something similar as a more reliable 150*387f9dfdSAndroid Build Coastguard Worker // interface. 151*387f9dfdSAndroid Build Coastguard Worker task = (struct task_struct *)bpf_get_current_task(); 152*387f9dfdSAndroid Build Coastguard Worker my_q = (struct cfs_rq_partial *)task->se.cfs_rq; 153*387f9dfdSAndroid Build Coastguard Worker len = my_q->nr_running; 154*387f9dfdSAndroid Build Coastguard Worker 155*387f9dfdSAndroid Build Coastguard Worker // Calculate run queue length by subtracting the currently running task, 156*387f9dfdSAndroid Build Coastguard Worker // if present. len 0 == idle, len 1 == one running task. 157*387f9dfdSAndroid Build Coastguard Worker if (len > 0) 158*387f9dfdSAndroid Build Coastguard Worker len--; 159*387f9dfdSAndroid Build Coastguard Worker 160*387f9dfdSAndroid Build Coastguard Worker STORE 161*387f9dfdSAndroid Build Coastguard Worker 162*387f9dfdSAndroid Build Coastguard Worker return 0; 163*387f9dfdSAndroid Build Coastguard Worker} 164*387f9dfdSAndroid Build Coastguard Worker""" 165*387f9dfdSAndroid Build Coastguard Worker 166*387f9dfdSAndroid Build Coastguard Worker# code substitutions 167*387f9dfdSAndroid Build Coastguard Workerif args.cpus: 168*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('STORAGE', 169*387f9dfdSAndroid Build Coastguard Worker 'BPF_HISTOGRAM(dist, cpu_key_t, MAX_CPUS);') 170*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('STORE', 'cpu_key_t key = {.slot = len}; ' + 171*387f9dfdSAndroid Build Coastguard Worker 'key.cpu = bpf_get_smp_processor_id(); ' + 172*387f9dfdSAndroid Build Coastguard Worker 'dist.increment(key);') 173*387f9dfdSAndroid Build Coastguard Workerelse: 174*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('STORAGE', 175*387f9dfdSAndroid Build Coastguard Worker 'BPF_HISTOGRAM(dist, unsigned int);') 176*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('STORE', 'dist.atomic_increment(len);') 177*387f9dfdSAndroid Build Coastguard Worker 178*387f9dfdSAndroid Build Coastguard Worker# If target has BTF enabled, use BTF to check runnable_weight field exists in 179*387f9dfdSAndroid Build Coastguard Worker# cfs_rq first, otherwise fallback to use check_runnable_weight_field(). 180*387f9dfdSAndroid Build Coastguard Workerif BPF.kernel_struct_has_field(b'cfs_rq', b'runnable_weight') == 1 \ 181*387f9dfdSAndroid Build Coastguard Worker or check_runnable_weight_field(): 182*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('RUNNABLE_WEIGHT_FIELD', 'unsigned long runnable_weight;') 183*387f9dfdSAndroid Build Coastguard Workerelse: 184*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('RUNNABLE_WEIGHT_FIELD', '') 185*387f9dfdSAndroid Build Coastguard Worker 186*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf: 187*387f9dfdSAndroid Build Coastguard Worker print(bpf_text) 188*387f9dfdSAndroid Build Coastguard Worker if args.ebpf: 189*387f9dfdSAndroid Build Coastguard Worker exit() 190*387f9dfdSAndroid Build Coastguard Worker 191*387f9dfdSAndroid Build Coastguard Workernum_cpus = len(utils.get_online_cpus()) 192*387f9dfdSAndroid Build Coastguard Worker 193*387f9dfdSAndroid Build Coastguard Worker# initialize BPF & perf_events 194*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text, cflags=['-DMAX_CPUS=%s' % str(num_cpus)]) 195*387f9dfdSAndroid Build Coastguard Workerb.attach_perf_event(ev_type=PerfType.SOFTWARE, 196*387f9dfdSAndroid Build Coastguard Worker ev_config=PerfSWConfig.CPU_CLOCK, fn_name="do_perf_event", 197*387f9dfdSAndroid Build Coastguard Worker sample_period=0, sample_freq=frequency) 198*387f9dfdSAndroid Build Coastguard Worker 199*387f9dfdSAndroid Build Coastguard Workerprint("Sampling run queue length... Hit Ctrl-C to end.") 200*387f9dfdSAndroid Build Coastguard Worker 201*387f9dfdSAndroid Build Coastguard Worker# output 202*387f9dfdSAndroid Build Coastguard Workerexiting = 0 if args.interval else 1 203*387f9dfdSAndroid Build Coastguard Workerdist = b.get_table("dist") 204*387f9dfdSAndroid Build Coastguard Workerwhile (1): 205*387f9dfdSAndroid Build Coastguard Worker try: 206*387f9dfdSAndroid Build Coastguard Worker sleep(int(args.interval)) 207*387f9dfdSAndroid Build Coastguard Worker except KeyboardInterrupt: 208*387f9dfdSAndroid Build Coastguard Worker exiting = 1 209*387f9dfdSAndroid Build Coastguard Worker 210*387f9dfdSAndroid Build Coastguard Worker print() 211*387f9dfdSAndroid Build Coastguard Worker if args.timestamp: 212*387f9dfdSAndroid Build Coastguard Worker print("%-8s\n" % strftime("%H:%M:%S"), end="") 213*387f9dfdSAndroid Build Coastguard Worker 214*387f9dfdSAndroid Build Coastguard Worker if args.runqocc: 215*387f9dfdSAndroid Build Coastguard Worker if args.cpus: 216*387f9dfdSAndroid Build Coastguard Worker # run queue occupancy, per-CPU summary 217*387f9dfdSAndroid Build Coastguard Worker idle = {} 218*387f9dfdSAndroid Build Coastguard Worker queued = {} 219*387f9dfdSAndroid Build Coastguard Worker cpumax = 0 220*387f9dfdSAndroid Build Coastguard Worker for k, v in dist.items(): 221*387f9dfdSAndroid Build Coastguard Worker if k.cpu > cpumax: 222*387f9dfdSAndroid Build Coastguard Worker cpumax = k.cpu 223*387f9dfdSAndroid Build Coastguard Worker for c in range(0, cpumax + 1): 224*387f9dfdSAndroid Build Coastguard Worker idle[c] = 0 225*387f9dfdSAndroid Build Coastguard Worker queued[c] = 0 226*387f9dfdSAndroid Build Coastguard Worker for k, v in dist.items(): 227*387f9dfdSAndroid Build Coastguard Worker if k.slot == 0: 228*387f9dfdSAndroid Build Coastguard Worker idle[k.cpu] += v.value 229*387f9dfdSAndroid Build Coastguard Worker else: 230*387f9dfdSAndroid Build Coastguard Worker queued[k.cpu] += v.value 231*387f9dfdSAndroid Build Coastguard Worker for c in range(0, cpumax + 1): 232*387f9dfdSAndroid Build Coastguard Worker samples = idle[c] + queued[c] 233*387f9dfdSAndroid Build Coastguard Worker if samples: 234*387f9dfdSAndroid Build Coastguard Worker runqocc = float(queued[c]) / samples 235*387f9dfdSAndroid Build Coastguard Worker else: 236*387f9dfdSAndroid Build Coastguard Worker runqocc = 0 237*387f9dfdSAndroid Build Coastguard Worker print("runqocc, CPU %-3d %6.2f%%" % (c, 100 * runqocc)) 238*387f9dfdSAndroid Build Coastguard Worker 239*387f9dfdSAndroid Build Coastguard Worker else: 240*387f9dfdSAndroid Build Coastguard Worker # run queue occupancy, system-wide summary 241*387f9dfdSAndroid Build Coastguard Worker idle = 0 242*387f9dfdSAndroid Build Coastguard Worker queued = 0 243*387f9dfdSAndroid Build Coastguard Worker for k, v in dist.items(): 244*387f9dfdSAndroid Build Coastguard Worker if k.value == 0: 245*387f9dfdSAndroid Build Coastguard Worker idle += v.value 246*387f9dfdSAndroid Build Coastguard Worker else: 247*387f9dfdSAndroid Build Coastguard Worker queued += v.value 248*387f9dfdSAndroid Build Coastguard Worker samples = idle + queued 249*387f9dfdSAndroid Build Coastguard Worker if samples: 250*387f9dfdSAndroid Build Coastguard Worker runqocc = float(queued) / samples 251*387f9dfdSAndroid Build Coastguard Worker else: 252*387f9dfdSAndroid Build Coastguard Worker runqocc = 0 253*387f9dfdSAndroid Build Coastguard Worker print("runqocc: %0.2f%%" % (100 * runqocc)) 254*387f9dfdSAndroid Build Coastguard Worker 255*387f9dfdSAndroid Build Coastguard Worker else: 256*387f9dfdSAndroid Build Coastguard Worker # run queue length histograms 257*387f9dfdSAndroid Build Coastguard Worker dist.print_linear_hist("runqlen", "cpu") 258*387f9dfdSAndroid Build Coastguard Worker 259*387f9dfdSAndroid Build Coastguard Worker dist.clear() 260*387f9dfdSAndroid Build Coastguard Worker 261*387f9dfdSAndroid Build Coastguard Worker countdown -= 1 262*387f9dfdSAndroid Build Coastguard Worker if exiting or countdown == 0: 263*387f9dfdSAndroid Build Coastguard Worker exit() 264