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# vfsstat Count some VFS calls. 5*387f9dfdSAndroid Build Coastguard Worker# For Linux, uses BCC, eBPF. Embedded C. 6*387f9dfdSAndroid Build Coastguard Worker# 7*387f9dfdSAndroid Build Coastguard Worker# Written as a basic example of counting multiple events as a stat tool. 8*387f9dfdSAndroid Build Coastguard Worker# 9*387f9dfdSAndroid Build Coastguard Worker# USAGE: vfsstat [-h] [-p PID] [interval] [count] 10*387f9dfdSAndroid Build Coastguard Worker# 11*387f9dfdSAndroid Build Coastguard Worker# Copyright (c) 2015 Brendan Gregg. 12*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License") 13*387f9dfdSAndroid Build Coastguard Worker# 14*387f9dfdSAndroid Build Coastguard Worker# 14-Aug-2015 Brendan Gregg Created this. 15*387f9dfdSAndroid Build Coastguard Worker# 12-Oct-2022 Rocky Xing Added PID filter support. 16*387f9dfdSAndroid Build Coastguard Worker 17*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function 18*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF 19*387f9dfdSAndroid Build Coastguard Workerfrom ctypes import c_int 20*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep, strftime 21*387f9dfdSAndroid Build Coastguard Workerfrom sys import argv 22*387f9dfdSAndroid Build Coastguard Workerimport argparse 23*387f9dfdSAndroid Build Coastguard Worker 24*387f9dfdSAndroid Build Coastguard Worker# arguments 25*387f9dfdSAndroid Build Coastguard Workerexamples = """examples: 26*387f9dfdSAndroid Build Coastguard Worker ./vfsstat # count some VFS calls per second 27*387f9dfdSAndroid Build Coastguard Worker ./vfsstat -p 185 # trace PID 185 only 28*387f9dfdSAndroid Build Coastguard Worker ./vfsstat 2 5 # print 2 second summaries, 5 times 29*387f9dfdSAndroid Build Coastguard Worker""" 30*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser( 31*387f9dfdSAndroid Build Coastguard Worker description="Count some VFS calls.", 32*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 33*387f9dfdSAndroid Build Coastguard Worker epilog=examples) 34*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-p", "--pid", 35*387f9dfdSAndroid Build Coastguard Worker help="trace this PID only") 36*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("interval", nargs="?", default=1, 37*387f9dfdSAndroid Build Coastguard Worker help="output interval, in seconds") 38*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("count", nargs="?", default=99999999, 39*387f9dfdSAndroid Build Coastguard Worker help="number of outputs") 40*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true", 41*387f9dfdSAndroid Build Coastguard Worker help=argparse.SUPPRESS) 42*387f9dfdSAndroid Build Coastguard Worker 43*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args() 44*387f9dfdSAndroid Build Coastguard Workercountdown = int(args.count) 45*387f9dfdSAndroid Build Coastguard Workerdebug = 0 46*387f9dfdSAndroid Build Coastguard Worker 47*387f9dfdSAndroid Build Coastguard Worker# load BPF program 48*387f9dfdSAndroid Build Coastguard Workerbpf_text = """ 49*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h> 50*387f9dfdSAndroid Build Coastguard Worker 51*387f9dfdSAndroid Build Coastguard Workerenum stat_types { 52*387f9dfdSAndroid Build Coastguard Worker S_READ = 1, 53*387f9dfdSAndroid Build Coastguard Worker S_WRITE, 54*387f9dfdSAndroid Build Coastguard Worker S_FSYNC, 55*387f9dfdSAndroid Build Coastguard Worker S_OPEN, 56*387f9dfdSAndroid Build Coastguard Worker S_CREATE, 57*387f9dfdSAndroid Build Coastguard Worker S_MAXSTAT 58*387f9dfdSAndroid Build Coastguard Worker}; 59*387f9dfdSAndroid Build Coastguard Worker 60*387f9dfdSAndroid Build Coastguard WorkerBPF_ARRAY(stats, u64, S_MAXSTAT); 61*387f9dfdSAndroid Build Coastguard Worker 62*387f9dfdSAndroid Build Coastguard Workerstatic void stats_try_increment(int key) { 63*387f9dfdSAndroid Build Coastguard Worker PID_FILTER 64*387f9dfdSAndroid Build Coastguard Worker stats.atomic_increment(key); 65*387f9dfdSAndroid Build Coastguard Worker} 66*387f9dfdSAndroid Build Coastguard Worker""" 67*387f9dfdSAndroid Build Coastguard Worker 68*387f9dfdSAndroid Build Coastguard Workerbpf_text_kprobe = """ 69*387f9dfdSAndroid Build Coastguard Workervoid do_read(struct pt_regs *ctx) { stats_try_increment(S_READ); } 70*387f9dfdSAndroid Build Coastguard Workervoid do_write(struct pt_regs *ctx) { stats_try_increment(S_WRITE); } 71*387f9dfdSAndroid Build Coastguard Workervoid do_fsync(struct pt_regs *ctx) { stats_try_increment(S_FSYNC); } 72*387f9dfdSAndroid Build Coastguard Workervoid do_open(struct pt_regs *ctx) { stats_try_increment(S_OPEN); } 73*387f9dfdSAndroid Build Coastguard Workervoid do_create(struct pt_regs *ctx) { stats_try_increment(S_CREATE); } 74*387f9dfdSAndroid Build Coastguard Worker""" 75*387f9dfdSAndroid Build Coastguard Worker 76*387f9dfdSAndroid Build Coastguard Workerbpf_text_kfunc = """ 77*387f9dfdSAndroid Build Coastguard WorkerKFUNC_PROBE(vfs_read) { stats_try_increment(S_READ); return 0; } 78*387f9dfdSAndroid Build Coastguard WorkerKFUNC_PROBE(vfs_write) { stats_try_increment(S_WRITE); return 0; } 79*387f9dfdSAndroid Build Coastguard WorkerKFUNC_PROBE(vfs_fsync_range) { stats_try_increment(S_FSYNC); return 0; } 80*387f9dfdSAndroid Build Coastguard WorkerKFUNC_PROBE(vfs_open) { stats_try_increment(S_OPEN); return 0; } 81*387f9dfdSAndroid Build Coastguard WorkerKFUNC_PROBE(vfs_create) { stats_try_increment(S_CREATE); return 0; } 82*387f9dfdSAndroid Build Coastguard Worker""" 83*387f9dfdSAndroid Build Coastguard Worker 84*387f9dfdSAndroid Build Coastguard Workeris_support_kfunc = BPF.support_kfunc() 85*387f9dfdSAndroid Build Coastguard Workerif is_support_kfunc: 86*387f9dfdSAndroid Build Coastguard Worker bpf_text += bpf_text_kfunc 87*387f9dfdSAndroid Build Coastguard Workerelse: 88*387f9dfdSAndroid Build Coastguard Worker bpf_text += bpf_text_kprobe 89*387f9dfdSAndroid Build Coastguard Worker 90*387f9dfdSAndroid Build Coastguard Workerif args.pid: 91*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('PID_FILTER', """ 92*387f9dfdSAndroid Build Coastguard Worker u32 pid = bpf_get_current_pid_tgid() >> 32; 93*387f9dfdSAndroid Build Coastguard Worker if (pid != %s) { 94*387f9dfdSAndroid Build Coastguard Worker return; 95*387f9dfdSAndroid Build Coastguard Worker } 96*387f9dfdSAndroid Build Coastguard Worker """ % args.pid) 97*387f9dfdSAndroid Build Coastguard Workerelse: 98*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('PID_FILTER', '') 99*387f9dfdSAndroid Build Coastguard Worker 100*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf: 101*387f9dfdSAndroid Build Coastguard Worker print(bpf_text) 102*387f9dfdSAndroid Build Coastguard Worker if args.ebpf: 103*387f9dfdSAndroid Build Coastguard Worker exit() 104*387f9dfdSAndroid Build Coastguard Worker 105*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text) 106*387f9dfdSAndroid Build Coastguard Workerif not is_support_kfunc: 107*387f9dfdSAndroid Build Coastguard Worker b.attach_kprobe(event="vfs_read", fn_name="do_read") 108*387f9dfdSAndroid Build Coastguard Worker b.attach_kprobe(event="vfs_write", fn_name="do_write") 109*387f9dfdSAndroid Build Coastguard Worker b.attach_kprobe(event="vfs_fsync_range", fn_name="do_fsync") 110*387f9dfdSAndroid Build Coastguard Worker b.attach_kprobe(event="vfs_open", fn_name="do_open") 111*387f9dfdSAndroid Build Coastguard Worker b.attach_kprobe(event="vfs_create", fn_name="do_create") 112*387f9dfdSAndroid Build Coastguard Worker 113*387f9dfdSAndroid Build Coastguard Worker# stat column labels and indexes 114*387f9dfdSAndroid Build Coastguard Workerstat_types = { 115*387f9dfdSAndroid Build Coastguard Worker "READ": 1, 116*387f9dfdSAndroid Build Coastguard Worker "WRITE": 2, 117*387f9dfdSAndroid Build Coastguard Worker "FSYNC": 3, 118*387f9dfdSAndroid Build Coastguard Worker "OPEN": 4, 119*387f9dfdSAndroid Build Coastguard Worker "CREATE": 5 120*387f9dfdSAndroid Build Coastguard Worker} 121*387f9dfdSAndroid Build Coastguard Worker 122*387f9dfdSAndroid Build Coastguard Worker# header 123*387f9dfdSAndroid Build Coastguard Workerprint("%-8s " % "TIME", end="") 124*387f9dfdSAndroid Build Coastguard Workerfor stype in stat_types.keys(): 125*387f9dfdSAndroid Build Coastguard Worker print(" %8s" % (stype + "/s"), end="") 126*387f9dfdSAndroid Build Coastguard Worker idx = stat_types[stype] 127*387f9dfdSAndroid Build Coastguard Workerprint("") 128*387f9dfdSAndroid Build Coastguard Worker 129*387f9dfdSAndroid Build Coastguard Worker# output 130*387f9dfdSAndroid Build Coastguard Workerexiting = 0 if args.interval else 1 131*387f9dfdSAndroid Build Coastguard Workerwhile (1): 132*387f9dfdSAndroid Build Coastguard Worker try: 133*387f9dfdSAndroid Build Coastguard Worker sleep(int(args.interval)) 134*387f9dfdSAndroid Build Coastguard Worker except KeyboardInterrupt: 135*387f9dfdSAndroid Build Coastguard Worker exiting = 1 136*387f9dfdSAndroid Build Coastguard Worker 137*387f9dfdSAndroid Build Coastguard Worker print("%-8s: " % strftime("%H:%M:%S"), end="") 138*387f9dfdSAndroid Build Coastguard Worker # print each statistic as a column 139*387f9dfdSAndroid Build Coastguard Worker for stype in stat_types.keys(): 140*387f9dfdSAndroid Build Coastguard Worker idx = stat_types[stype] 141*387f9dfdSAndroid Build Coastguard Worker try: 142*387f9dfdSAndroid Build Coastguard Worker val = b["stats"][c_int(idx)].value / int(args.interval) 143*387f9dfdSAndroid Build Coastguard Worker print(" %8d" % val, end="") 144*387f9dfdSAndroid Build Coastguard Worker except: 145*387f9dfdSAndroid Build Coastguard Worker print(" %8d" % 0, end="") 146*387f9dfdSAndroid Build Coastguard Worker b["stats"].clear() 147*387f9dfdSAndroid Build Coastguard Worker print("") 148*387f9dfdSAndroid Build Coastguard Worker 149*387f9dfdSAndroid Build Coastguard Worker countdown -= 1 150*387f9dfdSAndroid Build Coastguard Worker if exiting or countdown == 0: 151*387f9dfdSAndroid Build Coastguard Worker exit() 152