This patches includes - a profiler file/Makefile that can be added to an application to enable kernel event logger flush over UART - a nanokernel and a microkernel sample application permitting to exercise the profiler - scripts permitting to get kernel event profiler data over UART console and post-process this data Origin: Original Change-Id: Icacf4354c526c7f780b11371e9c28c87e6461eb8 Signed-off-by: Fabrice Olivero <fabrice.olivero@intel.com>
190 lines
4.6 KiB
Python
Executable File
190 lines
4.6 KiB
Python
Executable File
#!/usr/bin/python
|
|
|
|
#
|
|
# Copyright (c) 2016 Intel Corporation.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
#
|
|
|
|
import sys,re,os
|
|
|
|
class monitorEvent():
|
|
def __init__(self, time, data1, data2, ptr):
|
|
self.time = time
|
|
self.data1 = data1
|
|
self.data2 = data2
|
|
self.ptr = ptr
|
|
|
|
class Params():
|
|
# Quark X1000
|
|
TICKS_PER_MSEC = 14318.1
|
|
|
|
def getData(monitorFile):
|
|
|
|
eventList = []
|
|
|
|
with open(monitorFile, 'rb') as f:
|
|
for chunk in iter(lambda: f.read(16), ''):
|
|
time = int(chunk[0:4][::-1].encode('hex'), 16)
|
|
data1 = int(chunk[4:8][::-1].encode('hex'), 16)
|
|
data2 = int(chunk[8:12][::-1].encode('hex'), 16)
|
|
ptr = int(chunk[12:16][::-1].encode('hex'), 16)
|
|
|
|
if ((time == 0) and (data1 == 0) and (data2 == 0)):
|
|
break
|
|
eventList.append(monitorEvent(time, data1, data2, ptr))
|
|
return eventList
|
|
|
|
def formatTime(val):
|
|
ticks_per_ms = Params.TICKS_PER_MSEC
|
|
val_ms = val / ticks_per_ms
|
|
return "{:15.3f}".format(val_ms)
|
|
|
|
def getTask(val):
|
|
global symbols
|
|
|
|
if val == 0:
|
|
return "Idle"
|
|
else:
|
|
return symbols[val].replace('_k_task_obj_', '')
|
|
|
|
def formatEvent(time, data1, data2, ptr):
|
|
global symbols
|
|
global prevTaskName
|
|
global prevTaskId
|
|
|
|
mo_stbit0 = 0x20000000
|
|
mo_stbit1 = 0x30000000
|
|
mo_event = 0x40000000
|
|
mo_lcomm = 0x50000000
|
|
evt_type = data2 & 0xF0000000
|
|
mask = 0xFFFFFFF
|
|
evt_mask = 0xFFFFFFC
|
|
|
|
if (evt_type == mo_stbit0):
|
|
event = [ "State clear", decodeStateBits(data2 & mask), getTask(data1) ]
|
|
elif (evt_type == mo_stbit1):
|
|
event = [ "State set", decodeStateBits(data2 & mask), getTask(data1) ]
|
|
elif (evt_type == mo_event):
|
|
event = [ "Server event",
|
|
symbols[data2 & evt_mask].replace('_k_event_obj_',''),
|
|
"" ]
|
|
elif (evt_type == mo_lcomm):
|
|
event = [ "Server cmd", symbols[ptr], getTask(data1) ]
|
|
elif (evt_type == 0):
|
|
event = [ "Task switch to", "", getTask(data1) ]
|
|
if (ftrace_format):
|
|
ret = ""
|
|
if (prevTaskId >= 0):
|
|
ret = " {:>16}-{:<8} [000] .... {:12}: sched_switch: prev_comm={}" \
|
|
" prev_pid={} prev_prio=0 prev_state=S ==> next_comm={}" \
|
|
" next_pid={} next_prio=0".format(prevTaskName,
|
|
prevTaskId,
|
|
formatTime(time),
|
|
prevTaskName,
|
|
prevTaskId,
|
|
getTask(data1),
|
|
data1)
|
|
prevTaskName = getTask(data1)
|
|
prevTaskId = data1
|
|
return ret
|
|
else:
|
|
event = [ "UNDEFINED",
|
|
"data1={:08x}".format(data1),
|
|
"data2={:08x}".format(data2),
|
|
"ptr={:08x}".format(ptr) ]
|
|
|
|
if (ftrace_format):
|
|
return ""
|
|
else:
|
|
return "{} ms: {:15} {:13} {}".format(formatTime(time),
|
|
event[0],
|
|
event[2],
|
|
event[1])
|
|
|
|
def decode(eventList):
|
|
for evt in eventList:
|
|
s = formatEvent(evt.time, evt.data1, evt.data2, evt.ptr)
|
|
if len(s) > 0:
|
|
print s
|
|
|
|
def decodeStateBits(flags):
|
|
bitValue = [ "STOP", "TERM", "SUSP", "BLCK", "GDBSTOP", "PRIO" , "NA" , "NA", "NA", "NA",
|
|
"NA", "TIME", "DRIV", "RESV", "EVNT", "ENQU", "DEQU", "SEND", "RECV", "SEMA",
|
|
"LIST", "LOCK", "ALLOC", "GTBL", "RESV", "RESV", "RECVDATA", "SENDDATA" ]
|
|
s = ''
|
|
|
|
for x in range(0, len(bitValue) - 1):
|
|
if (flags & (1 << x)):
|
|
s += bitValue[x] + " "
|
|
|
|
return s
|
|
|
|
def loadSymbols(elfFile):
|
|
os.system('readelf -s ' + elfFile + ' > symbols.txt')
|
|
|
|
prog = re.compile("\s+\S+:\s+([a-fA-F0-9]+)\s+\d+\s+\S+\s+\S+\s+\S+\s+\S+\s+(\S+)")
|
|
objList = {}
|
|
|
|
with open('symbols.txt', 'r') as f:
|
|
for line in f:
|
|
match = prog.match(line)
|
|
if match:
|
|
idx = int(match.group(1), 16)
|
|
if not objList.has_key(idx):
|
|
objList[idx] = match.group(2)
|
|
else:
|
|
s = match.group(2)
|
|
# Prioritize tasks / event symbols when multiple symbols
|
|
# on same address
|
|
if "_k_task_obj" in s or "_k_event_obj" in s:
|
|
objList[idx] = s
|
|
|
|
|
|
os.system('rm -rf symbols.txt')
|
|
|
|
return objList
|
|
|
|
symbols = {}
|
|
prevTaskName = ""
|
|
prevTaskId = -1
|
|
ftrace_format=0
|
|
|
|
def Main(argv):
|
|
global symbols
|
|
|
|
dumpFile = ""
|
|
elfFile = ""
|
|
|
|
sys.argv.pop(0)
|
|
|
|
for arg in sys.argv:
|
|
if arg == "--qemu":
|
|
Params.TICKS_PER_MSEC=100000.0
|
|
else:
|
|
if not dumpFile:
|
|
dumpFile = arg
|
|
elif not elfFile:
|
|
elfFile = arg
|
|
|
|
if not elfFile:
|
|
print "profile.py [DUMP FILE] [ELF FILE]"
|
|
sys.exit(0)
|
|
|
|
eventList = getData(dumpFile)
|
|
symbols = loadSymbols(elfFile)
|
|
decode(eventList)
|
|
|
|
if __name__ == "__main__":
|
|
Main(sys.argv[1:])
|