1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env bcc-lua 2*387f9dfdSAndroid Build Coastguard Worker--[[ 3*387f9dfdSAndroid Build Coastguard WorkerCopyright 2016 GitHub, Inc 4*387f9dfdSAndroid Build Coastguard Worker 5*387f9dfdSAndroid Build Coastguard WorkerLicensed under the Apache License, Version 2.0 (the "License"); 6*387f9dfdSAndroid Build Coastguard Workeryou may not use this file except in compliance with the License. 7*387f9dfdSAndroid Build Coastguard WorkerYou may obtain a copy of the License at 8*387f9dfdSAndroid Build Coastguard Worker 9*387f9dfdSAndroid Build Coastguard Workerhttp://www.apache.org/licenses/LICENSE-2.0 10*387f9dfdSAndroid Build Coastguard Worker 11*387f9dfdSAndroid Build Coastguard WorkerUnless required by applicable law or agreed to in writing, software 12*387f9dfdSAndroid Build Coastguard Workerdistributed under the License is distributed on an "AS IS" BASIS, 13*387f9dfdSAndroid Build Coastguard WorkerWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*387f9dfdSAndroid Build Coastguard WorkerSee the License for the specific language governing permissions and 15*387f9dfdSAndroid Build Coastguard Workerlimitations under the License. 16*387f9dfdSAndroid Build Coastguard Worker]] 17*387f9dfdSAndroid Build Coastguard Worker 18*387f9dfdSAndroid Build Coastguard Workerlocal program = [[ 19*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h> 20*387f9dfdSAndroid Build Coastguard Worker#include <linux/sched.h> 21*387f9dfdSAndroid Build Coastguard Worker 22*387f9dfdSAndroid Build Coastguard Worker#define MINBLOCK_US 1 23*387f9dfdSAndroid Build Coastguard Worker 24*387f9dfdSAndroid Build Coastguard Workerstruct key_t { 25*387f9dfdSAndroid Build Coastguard Worker char name[TASK_COMM_LEN]; 26*387f9dfdSAndroid Build Coastguard Worker int stack_id; 27*387f9dfdSAndroid Build Coastguard Worker}; 28*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(counts, struct key_t); 29*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(start, u32); 30*387f9dfdSAndroid Build Coastguard WorkerBPF_STACK_TRACE(stack_traces, 10240); 31*387f9dfdSAndroid Build Coastguard Worker 32*387f9dfdSAndroid Build Coastguard Workerint oncpu(struct pt_regs *ctx, struct task_struct *prev) { 33*387f9dfdSAndroid Build Coastguard Worker u32 pid; 34*387f9dfdSAndroid Build Coastguard Worker u64 ts, *tsp; 35*387f9dfdSAndroid Build Coastguard Worker 36*387f9dfdSAndroid Build Coastguard Worker // record previous thread sleep time 37*387f9dfdSAndroid Build Coastguard Worker if (FILTER) { 38*387f9dfdSAndroid Build Coastguard Worker pid = prev->pid; 39*387f9dfdSAndroid Build Coastguard Worker ts = bpf_ktime_get_ns(); 40*387f9dfdSAndroid Build Coastguard Worker start.update(&pid, &ts); 41*387f9dfdSAndroid Build Coastguard Worker } 42*387f9dfdSAndroid Build Coastguard Worker 43*387f9dfdSAndroid Build Coastguard Worker // calculate current thread's delta time 44*387f9dfdSAndroid Build Coastguard Worker pid = bpf_get_current_pid_tgid(); 45*387f9dfdSAndroid Build Coastguard Worker tsp = start.lookup(&pid); 46*387f9dfdSAndroid Build Coastguard Worker if (tsp == 0) 47*387f9dfdSAndroid Build Coastguard Worker return 0; // missed start or filtered 48*387f9dfdSAndroid Build Coastguard Worker u64 delta = bpf_ktime_get_ns() - *tsp; 49*387f9dfdSAndroid Build Coastguard Worker start.delete(&pid); 50*387f9dfdSAndroid Build Coastguard Worker delta = delta / 1000; 51*387f9dfdSAndroid Build Coastguard Worker if (delta < MINBLOCK_US) 52*387f9dfdSAndroid Build Coastguard Worker return 0; 53*387f9dfdSAndroid Build Coastguard Worker 54*387f9dfdSAndroid Build Coastguard Worker // create map key 55*387f9dfdSAndroid Build Coastguard Worker u64 zero = 0, *val; 56*387f9dfdSAndroid Build Coastguard Worker struct key_t key = {}; 57*387f9dfdSAndroid Build Coastguard Worker int stack_flags = 0; 58*387f9dfdSAndroid Build Coastguard Worker 59*387f9dfdSAndroid Build Coastguard Worker /* 60*387f9dfdSAndroid Build Coastguard Worker if (!(prev->flags & PF_KTHREAD)) 61*387f9dfdSAndroid Build Coastguard Worker stack_flags |= BPF_F_USER_STACK; 62*387f9dfdSAndroid Build Coastguard Worker */ 63*387f9dfdSAndroid Build Coastguard Worker 64*387f9dfdSAndroid Build Coastguard Worker bpf_get_current_comm(&key.name, sizeof(key.name)); 65*387f9dfdSAndroid Build Coastguard Worker key.stack_id = stack_traces.get_stackid(ctx, stack_flags); 66*387f9dfdSAndroid Build Coastguard Worker 67*387f9dfdSAndroid Build Coastguard Worker val = counts.lookup_or_try_init(&key, &zero); 68*387f9dfdSAndroid Build Coastguard Worker if (val) { 69*387f9dfdSAndroid Build Coastguard Worker (*val) += delta; 70*387f9dfdSAndroid Build Coastguard Worker } 71*387f9dfdSAndroid Build Coastguard Worker return 0; 72*387f9dfdSAndroid Build Coastguard Worker} 73*387f9dfdSAndroid Build Coastguard Worker]] 74*387f9dfdSAndroid Build Coastguard Worker 75*387f9dfdSAndroid Build Coastguard Workerreturn function(BPF, utils) 76*387f9dfdSAndroid Build Coastguard Worker local ffi = require("ffi") 77*387f9dfdSAndroid Build Coastguard Worker 78*387f9dfdSAndroid Build Coastguard Worker local parser = utils.argparse("offcputime", "Summarize off-cpu time") 79*387f9dfdSAndroid Build Coastguard Worker parser:flag("-u --user-only") 80*387f9dfdSAndroid Build Coastguard Worker parser:option("-p --pid"):convert(tonumber) 81*387f9dfdSAndroid Build Coastguard Worker parser:flag("-f --folded") 82*387f9dfdSAndroid Build Coastguard Worker parser:option("-d --duration", "duration to trace for", 9999999):convert(tonumber) 83*387f9dfdSAndroid Build Coastguard Worker 84*387f9dfdSAndroid Build Coastguard Worker local args = parser:parse() 85*387f9dfdSAndroid Build Coastguard Worker local ksym = BPF.SymbolCache() 86*387f9dfdSAndroid Build Coastguard Worker local filter = "1" 87*387f9dfdSAndroid Build Coastguard Worker local MAXDEPTH = 20 88*387f9dfdSAndroid Build Coastguard Worker 89*387f9dfdSAndroid Build Coastguard Worker if args.pid then 90*387f9dfdSAndroid Build Coastguard Worker filter = "pid == %d" % args.pid 91*387f9dfdSAndroid Build Coastguard Worker elseif args.user_only then 92*387f9dfdSAndroid Build Coastguard Worker filter = "!(prev->flags & PF_KTHREAD)" 93*387f9dfdSAndroid Build Coastguard Worker end 94*387f9dfdSAndroid Build Coastguard Worker 95*387f9dfdSAndroid Build Coastguard Worker local text = program:gsub("FILTER", filter) 96*387f9dfdSAndroid Build Coastguard Worker local b = BPF:new{text=text} 97*387f9dfdSAndroid Build Coastguard Worker b:attach_kprobe{event="finish_task_switch", fn_name="oncpu"} 98*387f9dfdSAndroid Build Coastguard Worker 99*387f9dfdSAndroid Build Coastguard Worker if BPF.num_open_kprobes() == 0 then 100*387f9dfdSAndroid Build Coastguard Worker print("no functions matched. quitting...") 101*387f9dfdSAndroid Build Coastguard Worker return 102*387f9dfdSAndroid Build Coastguard Worker end 103*387f9dfdSAndroid Build Coastguard Worker 104*387f9dfdSAndroid Build Coastguard Worker print("Sleeping for %d seconds..." % args.duration) 105*387f9dfdSAndroid Build Coastguard Worker pcall(utils.posix.sleep, args.duration) 106*387f9dfdSAndroid Build Coastguard Worker print("Tracing...") 107*387f9dfdSAndroid Build Coastguard Worker 108*387f9dfdSAndroid Build Coastguard Worker local counts = b:get_table("counts") 109*387f9dfdSAndroid Build Coastguard Worker local stack_traces = b:get_table("stack_traces") 110*387f9dfdSAndroid Build Coastguard Worker 111*387f9dfdSAndroid Build Coastguard Worker for k, v in counts:items() do 112*387f9dfdSAndroid Build Coastguard Worker for addr in stack_traces:walk(tonumber(k.stack_id)) do 113*387f9dfdSAndroid Build Coastguard Worker print(" %-16p %s" % {addr, ksym:resolve(addr)}) 114*387f9dfdSAndroid Build Coastguard Worker end 115*387f9dfdSAndroid Build Coastguard Worker print(" %-16s %s" % {"-", ffi.string(k.name)}) 116*387f9dfdSAndroid Build Coastguard Worker print(" %d\n" % tonumber(v)) 117*387f9dfdSAndroid Build Coastguard Worker end 118*387f9dfdSAndroid Build Coastguard Workerend 119