Analyze APP Profiler data without Visual Studio
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

153 lines
3.8 KiB

#!/usr/bin/env python
# coding=utf8
#
# (c) 2012 Matthias Bach <bach@compeng.uni-frankfurt.de>
import argparse
import re
class ProfileEntry:
def __init__(self, commandKey, commandName, commandStart, commandEnd):
self.key = int(commandKey)
self.name = commandName
self.start = int(commandStart)
self.end = int(commandEnd)
def isKernel(self):
return self.key == 66
def isMemcpy(self):
return self.key >= 52 and self.key <= 56
class DeviceEntry(ProfileEntry):
def __init__(self, commandKey, commandName, commandStart, commandEnd, deviceCommandKey, deviceCommandName, timeQueued, timeSubmitted, timeStarted, timeEnded, *args):
ProfileEntry.__init__(self, commandKey, commandName, commandStart, commandEnd)
self.deviceKey = int(deviceCommandKey)
self.deviceName = deviceCommandName
self.timeQueued = int(timeQueued)
self.timeSubmitted = int(timeSubmitted)
self.timeStarted = int(timeStarted)
self.timeEnded = int(timeEnded)
if self.isKernel():
self.kernelName = args[6]
if self.isMemcpy():
self.copyBytes = int(args[-1])
def isDeviceCommand(key):
"""Checks if the command will be executed on the device"""
return key >= 52 and key < 70
def parseAPT(aptfilename):
aptfile = open(aptfilename)
# expect first to lines to contain Trace File Version and Profiler Version
file_ver = re.match(r'TraceFileVersion=\d+\.\d+', aptfile.next())
app_ver = re.match(r'ProfilerVersion=\d+\.\d+.\d+', aptfile.next())
if not file_ver or not app_ver:
print 'Seems not to be an APP Profiler API trace file'
raise Exception('Invalid input file')
# fast forward until we reach the timestamp output
for tmp in aptfile:
if re.match('=====AMD APP Profiler Timestamp Output=====', tmp):
break
aptfile.next() # skip entry with unkown meaning
expected_count = int(aptfile.next())
# read all remaining lines (or until empty line)
entries = []
for tmp in aptfile:
line = tmp.split()
if len(line) == 0:
break
if isDeviceCommand(int(line[0])):
entry = DeviceEntry(*line)
else:
entry = ProfileEntry(*line[0:4])
entries.append(entry)
if len(entries) != expected_count:
print 'Warning: Expected {0} entries, but found {1} entries'.format(expected_count, len(entries))
return entries
def printCommandKeyList(aptfilename):
entries = parseAPT(aptfilename)
commands = {}
for entry in entries:
try:
check = commands[entry.key]
if check and check != entry.name:
print 'Error: Found key {0} for name "{1}", but already mapped to name "{2}"'.format(entry.key, entry.name, check)
return
except KeyError:
pass
commands[entry.key] = entry.name
for entry in commands.items():
print '{0:>5} {1}'.format(*entry)
def main(aptfilename):
entries = parseAPT(aptfilename)
last_device_end = 0
table_format = '{0:>10} {1}'
print 'Device Utilization'
print '=================='
print
print table_format.format('Time (ns)', 'Operation')
print
for entry in entries:
if isinstance(entry, DeviceEntry):
idle = entry.timeStarted - last_device_end
print table_format.format(idle, 'Idle')
duration = entry.timeEnded - entry.timeStarted
last_device_end = entry.timeEnded
if entry.isKernel():
description = entry.kernelName
elif entry.isMemcpy():
description = '{0} of {1} bytes'.format(entry.name, entry.copyBytes)
print table_format.format(duration, description)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Plot a timeline of the OpenCL events')
parser.add_argument('aptfile', metavar='FILE', help='The file containing the API trace generated by the APP Profiler')
advanced = parser.add_argument_group('Advanced')
advanced.add_argument('--list-keys', action='store_true', default=False, help='Print a list of command keys')
args = parser.parse_args()
if args.list_keys:
printCommandKeyList(args.aptfile)
else:
main(args.aptfile)