blob: bbf7c61563f6e5ec676ba90d026f20346769129b [file] [log] [blame]
#!/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
import datetime
class ContextSwitch():
def __init__(self, context):
self.context = context
class Interrupt():
def __init__(self, irq):
self.irq = irq
class Sleep():
def __init__(self, duration, irq):
self.duration = duration
self.irq = irq
class TaskState():
SWITCH = 0
RESET_BIT = 1
SET_BIT = 2
def __init__(self, task, switch, bits):
self.task = task
self.switch = switch
self.bits = bits
class PacketCmd():
def __init__(self, task, command_ptr):
self.task = task
self.command_ptr = command_ptr
class Kevent():
def __init__(self, event_ptr):
self.event_ptr = event_ptr
class Event():
TYPE_ERROR = -1
TYPE_CONTEXTSWITCH = 1
TYPE_INTERRUPT = 2
TYPE_SLEEP = 3
TYPE_WAKEUP = 4
TYPE_TASK_STATE_CHANGE = 5
TYPE_COMMAND_PACKET = 6
TYPE_KEVENT = 7
def __init__(self, time, event_type, data):
self.time = time
self.etype = event_type
self.data = data
class EventType():
PLATFORM_INFO = 255
CONTEXTSWITCH = 1
INTERRUPT = 2
SLEEP = 3
TASK_STATE_CHANGE = 4
COMMAND_PACKET = 5
KEVENT = 6
class Params():
TICKS_PER_MSEC = 0
def getData(monitorFile):
global symbols
MO_STBIT0 = 0x20000000
MO_STBIT1 = 0x30000000
MO_EVENT = 0x40000000
MO_MASK = 0xFFFFFFF
EVT_MASK = 0xFFFFFFC
eventList = []
count = 0
with open(monitorFile, 'rb') as f:
while (1):
c = f.read(1)
count += 1
if (len(c) < 1):
return eventList
code = int(c.encode('hex'), 16)
if (code > 0):
#print "Count={:x}".format(count-1)
header = c
cc = f.read(3)
if (len(cc) < 3):
return eventList
header += cc
count += 3
evt_type = int(header[0:2][::-1].encode('hex'), 16)
size = int(header[2:4][::-1].encode('hex'), 16)
#print "Event {}({})".format(evt_type, size)
chunk = f.read(size*4)
if (len(chunk) < size*4):
return eventList
count += size*4
if (evt_type == EventType.PLATFORM_INFO):
Params.TICKS_PER_MSEC = \
int(chunk[0:4][::-1].encode('hex'), 16) / 1000.0
elif (evt_type == EventType.CONTEXTSWITCH):
time = int(chunk[0:4][::-1].encode('hex'), 16)
context = int(chunk[4:8][::-1].encode('hex'), 16)
eventList.append(Event(time,
Event.TYPE_CONTEXTSWITCH,
ContextSwitch(context)))
elif (evt_type == EventType.INTERRUPT):
time = int(chunk[0:4][::-1].encode('hex'), 16)
irq = int(chunk[4:8][::-1].encode('hex'), 16)
eventList.append(Event(time,
Event.TYPE_INTERRUPT,
Interrupt(irq)))
elif (evt_type == EventType.SLEEP):
time = int(chunk[0:4][::-1].encode('hex'), 16)
duration = int(chunk[4:8][::-1].encode('hex'), 16)
cause = int(chunk[8:12][::-1].encode('hex'), 16)
eventList.append(Event(time,
Event.TYPE_SLEEP,
Sleep(duration, cause)))
eventList.append(Event(time,
Event.TYPE_WAKEUP,
Sleep(duration, cause)))
elif (evt_type == EventType.TASK_STATE_CHANGE):
time = int(chunk[0:4][::-1].encode('hex'), 16)
task = int(chunk[4:8][::-1].encode('hex'), 16)
data = int(chunk[8:12][::-1].encode('hex'), 16)
if data == 0:
eventList.append(Event(
time,
Event.TYPE_TASK_STATE_CHANGE,
TaskState(task,
TaskState.SWITCH,
0)))
elif (data & 0xF0000000) == MO_STBIT0:
eventList.append(Event(
time,
Event.TYPE_TASK_STATE_CHANGE,
TaskState(task,
TaskState.RESET_BIT,
data & MO_MASK )))
elif (data & 0xF0000000) == MO_STBIT1:
eventList.append(Event(
time,
Event.TYPE_TASK_STATE_CHANGE,
TaskState(task,
TaskState.SET_BIT,
data & MO_MASK )))
elif (evt_type == EventType.COMMAND_PACKET):
time = int(chunk[0:4][::-1].encode('hex'), 16)
task = int(chunk[4:8][::-1].encode('hex'), 16)
cmd_ptr = int(chunk[8:12][::-1].encode('hex'), 16)
eventList.append(Event(time,
Event.TYPE_COMMAND_PACKET,
PacketCmd(task, cmd_ptr)))
elif (evt_type == EventType.KEVENT):
time = int(chunk[0:4][::-1].encode('hex'), 16)
event = int(chunk[4:8][::-1].encode('hex'), 16)
eventList.append(Event(time,
Event.TYPE_KEVENT,
Kevent(event & EVT_MASK)))
else:
eventList.append(Event(0, Event.TYPE_ERROR, evt_type))
def findFollowingTask(events, i):
i = i + 1
while (i < len(events)) and (events[i].etype != Event.TYPE_CONTEXTSWITCH):
i = i + 1
if (i == len(events)):
return -1
else:
return events[i].data.context
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 display(events):
global ftrace_format
global isr
current_task = -1
for i in range(0, len(events) -1):
evt = events[i]
if ftrace_format == 0:
if (evt.etype == Event.TYPE_CONTEXTSWITCH):
fTask = findFollowingTask(events, i)
if (fTask >= 0):
print "{:12} : {:>16} ---> {:<16}".format(
formatTime(evt.time),
getTask(evt.data.context),
getTask(fTask))
elif (evt.etype == Event.TYPE_INTERRUPT):
print "{:12} : IRQ{} handler={}".format(
formatTime(evt.time),
evt.data.irq,
getIsr(evt.data.irq))
elif (evt.etype == Event.TYPE_SLEEP):
print "{:12} : SLEPT {} OS ticks".format(
formatTime(evt.time),
evt.data.duration)
elif (evt.etype == Event.TYPE_WAKEUP):
print "{:12} : WAKEUP IRQ{}".format(
formatTime(evt.time),
evt.data.irq)
elif (evt.etype == Event.TYPE_TASK_STATE_CHANGE):
if (evt.data.task == 0):
task = "main_task"
else:
task = getSymbol(evt.data.task).replace('_k_task_obj_', '')
if (evt.data.switch == TaskState.SWITCH):
print "{:12} : " \
"Task switch to {}".format(formatTime(evt.time),
task)
elif (evt.data.switch == TaskState.SET_BIT):
print "{:12} : " \
"Task bits set ({}) {}".format(
formatTime(evt.time),
task,
decodeStateBits(evt.data.bits))
elif (evt.data.switch == TaskState.RESET_BIT):
print "{:12} : " \
"Task bits reset ({}) {}".format(
formatTime(evt.time),
task,
decodeStateBits(evt.data.bits))
elif (evt.etype == Event.TYPE_COMMAND_PACKET):
if (evt.data.task == 0):
task = "main_task"
else:
task = getSymbol(evt.data.task).replace('_k_task_obj_', '')
print "{:12} : " \
"Command ({}) {}".format(formatTime(evt.time),
task,
getSymbol(evt.data.command_ptr))
elif (evt.etype == Event.TYPE_KEVENT):
print "{:12} : " \
"Event {}".format(
formatTime(evt.time),
getSymbol(evt.data.event_ptr).replace(
'_k_event_obj_',''
)
)
else:
print "ERROR type={:08x}".format(evt.data)
else:
if (evt.etype == Event.TYPE_CONTEXTSWITCH):
ftask_id = findFollowingTask(events, i)
if (ftask_id > 0):
task_id = evt.data.context
task_name = getTask(evt.data.context)
if task_name == "main_task":
task_id = 0
if task_name == "_k_server":
task_id = 1
ftask_name = getTask(ftask_id)
if ftask_name == "main_task":
ftask_id = 0
if ftask_name == "_k_server":
ftask_id = 1
print " {:>16}-{:<8} [000] .... {:12}: sched_switch:" \
" prev_comm={} prev_pid={} prev_prio=0" \
" prev_state=S ==> next_comm={} next_pid={}" \
" next_prio=0".format(task_name,
task_id,
formatTime(evt.time),
task_name,
task_id,
ftask_name,
ftask_id)
current_task = evt.data.context
elif (evt.etype == Event.TYPE_INTERRUPT):
print " {:>16}-{:<8} [000] .... {:12}: irq_handler_entry: irq={}" \
" name={} handler={}".format(getTask(current_task),
current_task,
formatTime(evt.time),
evt.data.irq,
evt.data.irq,
getIsr(evt.data.irq))
print " {:>16}-{:<8} [000] .... {:12}: irq_handler_exit: irq={}" \
" ret=handled".format(getTask(current_task),
current_task,
formatTime(evt.time),
evt.data.irq)
last_timestamp = 0.0
base_timestamp = 0.0
def formatTime(val):
global last_timestamp
global base_timestamp
ticks_per_ms = Params.TICKS_PER_MSEC
val_ms = base_timestamp + (val / ticks_per_ms)
if val_ms < last_timestamp:
val_ms = val_ms + (0xFFFFFFFF / ticks_per_ms)
base_timestamp = base_timestamp + (0xFFFFFFFF / ticks_per_ms)
last_timestamp = val_ms
return "{:15.3f}".format(val_ms)
def getSymbol(val):
global symbols
if symbols.has_key(val):
return symbols[val]
else:
mem_key = 0
for key, value in symbols.iteritems():
if key < val:
if key > mem_key:
mem_key = key
symbols[val] = symbols[mem_key] + "+{}".format(val - mem_key)
return symbols[val]
def getTask(val):
return getSymbol(val).replace("_stack", "")
def getIsr(val):
global isr
if (isr.has_key(val)):
return isr[val].replace("$","").replace("_stub","")
else:
return "??{}".format(val)
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:
address = int(match.group(1), 16)
if not objList.has_key(address):
objList[address] = 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) or
("_idt_base_address" in s)):
objList[address] = s
os.system('rm -rf symbols.txt')
return objList
def getIdtFunc(str1, str2):
# Format: cc1d0800 008e1000 => 0x00101dcc
# IDT encoding (see _IdtEntCreate function in zephyr)
address = str2[6:8]+str2[4:6]+str1[2:4]+str1[0:2]
if symbols.has_key(int(address, 16)):
return symbols[int(address, 16)]
else:
return "??{}".format(address)
def getSection(address, elfFile):
os.system('readelf -S ' + elfFile + ' > sections.txt')
prog = re.compile("\s+\[.+\]\s(\S+)\s+\S+\s+([0-9a-fA-F]+)\s+[0-9a-fA-F]+\s+([0-9a-fA-F]+)")
with open("sections.txt", 'r') as f:
for line in f:
match = prog.match(line)
if match:
start = int(match.group(2), 16)
end = start + int(match.group(3), 16)
name = match.group(1)
if (address >= start) and (address < end):
os.system('rm -rf sections.txt')
return name
os.system('rm -rf sections.txt')
return ''
def getIsrTable(elfFile):
# First get IDT table address '_idt_base_address' symbol
idt_address = 0
for addr,sym in symbols.iteritems():
if sym == '_idt_base_address':
idt_address = addr
if idt_address == 0:
print "IDT table address not found"
return 0
sectionName = getSection(idt_address, elfFile)
if sectionName == '':
print "IDT section not found"
return 0
os.system('readelf -x ' + sectionName + ' ' + elfFile + ' > ' + sectionName + '.txt')
prog = re.compile(
"\s+0x([0-9a-fA-F]+)\s+([0-9a-fA-F]+)\s+([0-9a-fA-F]+)\s+([0-9a-fA-F]+)" \
"\s+([0-9a-fA-F]+)\s+\S+")
symbol_table = {}
first = 0
with open(sectionName + '.txt', 'r') as f:
for line in f:
match = prog.match(line)
if match:
address = int(match.group(1), 16)
if (first == 0):
first = address
symbol_table[address] = match.group(2)
symbol_table[address+4] = match.group(3)
symbol_table[address+8] = match.group(4)
symbol_table[address+12] = match.group(5)
address_end = address + 12
capture_on = 0
index = 0
isr = {}
address = first
while address < address_end:
if not capture_on:
if (address == idt_address):
capture_on = 1
if (capture_on):
isr[index] = getIdtFunc(symbol_table[address], symbol_table[address+4])
index += 1
isr[index] = getIdtFunc(symbol_table[address+8], symbol_table[address+12])
index += 1
if (index == 256):
break
address = address + 16
else:
address = address + 4
os.system('rm -rf ' + sectionName + '.txt')
return isr
symbols = {}
isr = {}
prevTaskName = ""
prevTaskId = -1
ftrace_format = 0
def Main(argv):
global symbols, isr
global ftrace_format
dumpFile = ""
elfFile = ""
sys.argv.pop(0)
iterator = sys.argv.__iter__()
for arg in iterator:
if arg == "--ftrace":
ftrace_format = 1
elif arg == "-c":
Params.TICKS_PER_MSEC = float(iterator.next()) / 1000.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)
symbols = loadSymbols(elfFile)
isr = getIsrTable(elfFile)
eventList = getData(dumpFile)
if (Params.TICKS_PER_MSEC == 0):
print "Platform info not found ! Use -c option if decoding dump from JTAG"
sys.exit(0)
display(eventList)
if __name__ == "__main__":
Main(sys.argv[1:])