1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env bcc-lua 2*387f9dfdSAndroid Build Coastguard Worker--[[ 3*387f9dfdSAndroid Build Coastguard WorkerCopyright 2016 Marek Vavrusa <[email protected]> 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-- Summarize off-CPU time by stack trace 18*387f9dfdSAndroid Build Coastguard Worker-- Related tool: https://github.com/iovisor/bcc/blob/master/tools/offcputime.py 19*387f9dfdSAndroid Build Coastguard Workerlocal ffi = require('ffi') 20*387f9dfdSAndroid Build Coastguard Workerlocal bpf = require('bpf') 21*387f9dfdSAndroid Build Coastguard Workerlocal S = require('syscall') 22*387f9dfdSAndroid Build Coastguard Worker-- Create BPF maps 23*387f9dfdSAndroid Build Coastguard Worker-- TODO: made smaller to fit default memory limits 24*387f9dfdSAndroid Build Coastguard Workerlocal key_t = 'struct { char name[16]; int32_t stack_id; }' 25*387f9dfdSAndroid Build Coastguard Workerlocal starts = assert(bpf.map('hash', 128, ffi.typeof('uint32_t'), ffi.typeof('uint64_t'))) 26*387f9dfdSAndroid Build Coastguard Workerlocal counts = assert(bpf.map('hash', 128, ffi.typeof(key_t), ffi.typeof('uint64_t'))) 27*387f9dfdSAndroid Build Coastguard Workerlocal stack_traces = assert(bpf.map('stack_trace', 16)) 28*387f9dfdSAndroid Build Coastguard Worker-- Open tracepoint and attach BPF program 29*387f9dfdSAndroid Build Coastguard Worker-- The 'arg' parses tracepoint format automatically 30*387f9dfdSAndroid Build Coastguard Workerlocal tp = bpf.tracepoint('sched/sched_switch', function (arg) 31*387f9dfdSAndroid Build Coastguard Worker -- Update previous thread sleep time 32*387f9dfdSAndroid Build Coastguard Worker local pid = arg.prev_pid 33*387f9dfdSAndroid Build Coastguard Worker local now = time() 34*387f9dfdSAndroid Build Coastguard Worker starts[pid] = now 35*387f9dfdSAndroid Build Coastguard Worker -- Calculate current thread's delta time 36*387f9dfdSAndroid Build Coastguard Worker pid = arg.next_pid 37*387f9dfdSAndroid Build Coastguard Worker local from = starts[pid] 38*387f9dfdSAndroid Build Coastguard Worker if not from then 39*387f9dfdSAndroid Build Coastguard Worker return 0 40*387f9dfdSAndroid Build Coastguard Worker end 41*387f9dfdSAndroid Build Coastguard Worker local delta = (now - from) / 1000 42*387f9dfdSAndroid Build Coastguard Worker starts[pid] = nil 43*387f9dfdSAndroid Build Coastguard Worker -- Check if the delta is below 1us 44*387f9dfdSAndroid Build Coastguard Worker if delta < 1 then 45*387f9dfdSAndroid Build Coastguard Worker return 46*387f9dfdSAndroid Build Coastguard Worker end 47*387f9dfdSAndroid Build Coastguard Worker -- Create key for this thread 48*387f9dfdSAndroid Build Coastguard Worker local key = ffi.new(key_t) 49*387f9dfdSAndroid Build Coastguard Worker comm(key.name) 50*387f9dfdSAndroid Build Coastguard Worker key.stack_id = stack_id(stack_traces, BPF.F_FAST_STACK_CMP) 51*387f9dfdSAndroid Build Coastguard Worker -- Update current thread off cpu time with delta 52*387f9dfdSAndroid Build Coastguard Worker local val = counts[key] 53*387f9dfdSAndroid Build Coastguard Worker if not val then 54*387f9dfdSAndroid Build Coastguard Worker counts[key] = 0 55*387f9dfdSAndroid Build Coastguard Worker end 56*387f9dfdSAndroid Build Coastguard Worker xadd(counts[key], delta) 57*387f9dfdSAndroid Build Coastguard Workerend, 0, -1) 58*387f9dfdSAndroid Build Coastguard Worker-- Helper: load kernel symbols 59*387f9dfdSAndroid Build Coastguard Workerffi.cdef 'unsigned long long strtoull(const char *, char **, int);' 60*387f9dfdSAndroid Build Coastguard Workerlocal ksyms = {} 61*387f9dfdSAndroid Build Coastguard Workerfor l in io.lines('/proc/kallsyms') do 62*387f9dfdSAndroid Build Coastguard Worker local addr, sym = l:match '(%w+) %w (%S+)' 63*387f9dfdSAndroid Build Coastguard Worker if addr then ksyms[ffi.C.strtoull(addr, nil, 16)] = sym end 64*387f9dfdSAndroid Build Coastguard Workerend 65*387f9dfdSAndroid Build Coastguard Worker-- User-space part of the program 66*387f9dfdSAndroid Build Coastguard Workerwhile true do 67*387f9dfdSAndroid Build Coastguard Worker for k,v in counts.pairs,counts,nil do 68*387f9dfdSAndroid Build Coastguard Worker local s = '' 69*387f9dfdSAndroid Build Coastguard Worker local traces = stack_traces[k.stack_id] 70*387f9dfdSAndroid Build Coastguard Worker if traces then 71*387f9dfdSAndroid Build Coastguard Worker for i, ip in ipairs(traces) do 72*387f9dfdSAndroid Build Coastguard Worker s = s .. string.format(" %-16p %s", ip, ksyms[ip]) 73*387f9dfdSAndroid Build Coastguard Worker end 74*387f9dfdSAndroid Build Coastguard Worker end 75*387f9dfdSAndroid Build Coastguard Worker s = s .. string.format(" %-16s %s", "-", ffi.string(k.name)) 76*387f9dfdSAndroid Build Coastguard Worker s = s .. string.format(" %d", tonumber(v)) 77*387f9dfdSAndroid Build Coastguard Worker print(s) 78*387f9dfdSAndroid Build Coastguard Worker end 79*387f9dfdSAndroid Build Coastguard Worker S.sleep(1) 80*387f9dfdSAndroid Build Coastguard Workerend 81