From f58b610a9eb76d2599b7d6de117c3435ee462fed Mon Sep 17 00:00:00 2001 From: Lindong Wu Date: Wed, 3 Nov 2021 16:36:02 +0800 Subject: [PATCH] add trace tool to support libva trace process Signed-off-by: Lindong Wu --- tracetool/README.md | 125 ++ tracetool/callStack.py | 70 + tracetool/core.py | 160 ++ tracetool/dataParser.py | 288 +++ tracetool/drawQueue.py | 42 + tracetool/main.py | 47 + tracetool/manifest.py | 190 ++ tracetool/manifests/Intel-Media-Open.json | 1970 +++++++++++++++++++++ tracetool/manifests/libva_trace.man | 612 +++++++ tracetool/modules/ftrace.py | 538 ++++++ tracetool/modules/i915.py | 151 ++ tracetool/modules/iHD.py | 220 +++ tracetool/modules/libva.py | 601 +++++++ tracetool/modules/surface.py | 395 +++++ tracetool/statistic.py | 49 + tracetool/test/__init__.py | 5 + tracetool/test/test_callStack.py | 56 + tracetool/test/test_core.py | 185 ++ tracetool/test/test_dataParser.py | 37 + tracetool/test/test_drawQueue.py | 62 + tracetool/test/test_ftrace.py | 51 + tracetool/test/test_i915.py | 107 ++ tracetool/test/test_media.py | 122 ++ tracetool/test/test_surface.py | 129 ++ tracetool/util.py | 57 + tracetool/version.py | 15 + tracetool/writeUI.py | 73 + 27 files changed, 6357 insertions(+) create mode 100644 tracetool/README.md create mode 100644 tracetool/callStack.py create mode 100644 tracetool/core.py create mode 100644 tracetool/dataParser.py create mode 100644 tracetool/drawQueue.py create mode 100644 tracetool/main.py create mode 100644 tracetool/manifest.py create mode 100644 tracetool/manifests/Intel-Media-Open.json create mode 100644 tracetool/manifests/libva_trace.man create mode 100644 tracetool/modules/ftrace.py create mode 100644 tracetool/modules/i915.py create mode 100644 tracetool/modules/iHD.py create mode 100644 tracetool/modules/libva.py create mode 100644 tracetool/modules/surface.py create mode 100644 tracetool/statistic.py create mode 100644 tracetool/test/__init__.py create mode 100644 tracetool/test/test_callStack.py create mode 100644 tracetool/test/test_core.py create mode 100644 tracetool/test/test_dataParser.py create mode 100644 tracetool/test/test_drawQueue.py create mode 100644 tracetool/test/test_ftrace.py create mode 100644 tracetool/test/test_i915.py create mode 100644 tracetool/test/test_media.py create mode 100644 tracetool/test/test_surface.py create mode 100644 tracetool/util.py create mode 100644 tracetool/version.py create mode 100644 tracetool/writeUI.py diff --git a/tracetool/README.md b/tracetool/README.md new file mode 100644 index 00000000..1d919276 --- /dev/null +++ b/tracetool/README.md @@ -0,0 +1,125 @@ +# Linux trace tool + + +## Introduction + +This is python tool helps to analysis media stack trace logs combining ftrace events from libva, media driver and Linux kernel mode driver (e.g. i915). + + +## Linux trace capture + +1. Install trace-cmd: + + sudo apt-get install trace-cmd + +2. Grant write access to trace node for application: + + sudo chmod 777 /sys/kernel/debug/ + sudo chmod 777 /sys/kernel/debug/tracing/ + sudo chmod 777 /sys/kernel/debug/tracing/trace_marker_raw + +3. Enable libva trace: + + export LIBVA_TRACE = FTRACE + + to enable libva buffer data capture + + export LIBVA_TRACE_BUFDATA = 1 + +4. Run application under trace-cmd in a proxy mode: + + trace-cmd record -e i915 + +5. Output is "trace.dat" + +Alternatively you can collect trace data in separate terminal. +It is useful if you want to profile daemon or a service: + +1. Start trace capture: + + sudo trace-cmd record -e i915 + +2. Run test app in another terminal +3. Stop capturing in the first terminal +4. Output is "trace.dat" + + +## Trace post-processing and analysis + + python3 main.py [-raw] file.dat|file.etl [file.dat|file.etl ...] + +Options: + +* `-raw` - Parse trace events and dump into .csv file. + +Output: + +* `.json.gz` - visualized trace activity, open in `` or `` +* `_stat.csv` - statistic of trace activity, open in Excel +* `_surface.csv` - surface attributes and runtime usage in GPU, open in Excel +* `_rtlog.txt` - iHD driver runtime log + + +## Trace tool manifests + +Manifests are for decoding trace data. Each trace system supported by trace tool need have a manifest file in manifests folder. +The manifest file could be in MSFT ETW XML manifest format or json format. Current supported traces: +* libva_trace.man - libva trace manifest in MSFT ETW XML +* Intel-Media-Open.json - iHD open source media driver trace manifest in json. + + +## Trace Modules + +Trace tool dynamic load functional module in modules folders. Each module should have its own standalone function. +Two types of module supported: traceReader and traceHandler. +Each module should have 1 class traceReader or class traceHandler implemented. Trace tool load module by class name, so no change on class name. +### class traceReader +trace file reader module, responsible for parsing trace file into trace events, and call core handler one by one in event timestamp order. +trace reader external interface: +|interface|description| +|---|---| +|open(self, file, options)->int|open trace file, return 0 for sucess, negative for failure. user command line options are provided in args.| +|setParser(self, parsers)->None|set trace head parsers. Since all Linux user space trace share single trace_marker_raw entry, each user trace(libva and iHD) need register its own header parser to identify itself.| +|syncSource(self, src)->int|for sync timestamp across multi trace readers. return -1 for no support.| +|process(self, filter, handler)->None|start trace event process with filter and handler callbacks. Filt events with filter callback could speed up event process.| + +add new reader to support more trace file format +### traceHandler +trace event handler module to customize event handling. +core interface for trace handler: +|interface|description| +|---|---| +|core.regParser(id, parser)->int|register trace header parser, id is 4bytes trace identifier, parer callback is to parser event header.| +|core.regHandler(sys, name, handler)->None|register event handler, set name to None for common trace handler.| +|core.getContext()->dict|get share context from core.| + +Since all handler modules are in seperated instance, could not share anything across modules, core provide shared context for sharing. +by default, shared context provide following class instance: +|name in context|access example| description| +|---|---|---| +|UI|sharedCtx['UI']|instance of class writeUI, wrap UI event for chrome://tracing.| +|Stack|sharedCtx['Stack']|instance of class callStack, provide call stack of trace event. call stack is built from event sequence from the same process id and thread id.| +|Stat|sharedCtx['Stat']|instace of statistic, build statistic for specific events.| +|Output|sharedCtx['Output']|output path string, in case module need to create its own output file.| + +developer could add more in shared context. +Note: It is possible multi modules register their own handers for one specific event. core will call these callback one by one when target event occurs. + +current modules: +|module|description| +|---|---| +|ftrace.py|Linux ftace file parser, trace file from trace-cmd.| +|i915.py|i915 trace handler to extract GPU workload submit&execution timing.| +|libva.py|libva trace handler.| +|iHD.py|Intel iHD open source media driver trace handler.| +|surface.py|track surface object & attributes across iHD and i915 traces.| + +## Making changes in the tool + +Make sure to run unit tests before creating PR: + + cd tracetool + python3 -m unittest + +Make sure trace event and event data are backward compatible. + diff --git a/tracetool/callStack.py b/tracetool/callStack.py new file mode 100644 index 00000000..67eb90b1 --- /dev/null +++ b/tracetool/callStack.py @@ -0,0 +1,70 @@ +# +# Copyright (C) Intel Corporation. All rights reserved. +# Licensed under the MIT License. +# + +# build call stack from events with the same process and thread id +class callStack: + + def __init__(self): + self.context = {} # maintain call stack + + # get latest pushed call event in stack + def current(self, pid, tid): + if pid not in self.context or tid not in self.context[pid]: + return None + if self.context[pid][tid]: + return self.context[pid][tid][0] + return None + + # get full call stack record + def get(self, pid, tid): + if pid not in self.context: + self.context[pid] = {} + if tid not in self.context[pid]: + self.context[pid][tid] = [] + return self.context[pid][tid] + + # push event into stack + def push(self, evt): + if evt['pid'] not in self.context: + self.context[evt['pid']] = {} + if evt['tid'] not in self.context[evt['pid']]: + self.context[evt['pid']][evt['tid']] = [] + self.context[evt['pid']][evt['tid']].insert(0, evt) + + # pop event from stack + def pop(self, evt): + if evt['pid'] not in self.context: + return None + if evt['tid'] not in self.context[evt['pid']] or not self.context[evt['pid']][evt['tid']]: + thrds = self.context[evt['pid']] + for t in thrds.values(): + if t and t[0]['name'] == evt['name']: + return t.pop(0) + return None + ctx = self.context[evt['pid']][evt['tid']] + name = evt['name'] + idx = 0 + ret = None + # find target in the stack + for i in range(len(ctx)): + if ctx[i]['name'] == name: + idx = i+1 + ret = ctx[i] + break + # remove target from stack + del ctx[0:idx] + return ret + + # find top event with the same sys id + pid + tid + def find(self, evt): + if evt['pid'] not in self.context or evt['tid'] not in self.context[evt['pid']]: + return None + for e in self.context[evt['pid']][evt['tid']]: + if e['sys'] == evt['sys']: + return e + return None + + def __del__(self): + del self.context diff --git a/tracetool/core.py b/tracetool/core.py new file mode 100644 index 00000000..79ced4d0 --- /dev/null +++ b/tracetool/core.py @@ -0,0 +1,160 @@ +# +# Copyright (C) Intel Corporation. All rights reserved. +# Licensed under the MIT License. +# + +import os +import sys +import importlib +from writeUI import writeUI +from statistic import statistic +from callStack import callStack +from util import * + +class core: + + def __init__(self): + self.source = None + self.sharedCtx = {} # shared context for all handlers, dict for flexible usage + self.handlers = {} + self.instances = [] + self.readers = [] + self.parsers = {} + self.dumpRaw = False + + cur = os.path.abspath(os.path.dirname(__file__)) + sys.path.append(cur+os.sep+'modules') + for py in os.listdir('modules'): + name = os.path.splitext(py)[0] + m = importlib.import_module(name) + if hasattr(m, 'traceHandler'): + cls = getattr(m, 'traceHandler') + # create handler instace, the class init should call register of this instance + instance = cls(self) + # just for keep instance ref + self.instances.append(instance) + elif hasattr(m, 'traceReader'): + cls = getattr(m, 'traceReader') + self.readers.append(cls) + + # open trace file + def open(self, input, options) -> int: + ret = -1 + if isinstance(input, list) and len(input) == 1: + input = input[0] + if isinstance(input, list): + # enumerate and open trace files + names = [] + readers = [] + for i in input: + for cls in self.readers: + reader = cls() + sts = reader.open(i, options) + if sts == 0: + names.append(i) + readers.append(reader) + break + if len(input) == len(readers): + # sync time stamp across multi trace files, need find single source reader + print('Multi trace input files, sync time line ...') + for i in readers: + for j in readers: + if i != j and i.syncSource(j) == 0: + self.source = i + self.sharedCtx['sourceFile'] = names[readers.index(i)] + break + if self.source != None: + break + if self.source != None: + print('done') + ret = 0 + else: + print('Error! could not syn time line') + else: + for cls in self.readers: + reader = cls() + sts = reader.open(input, options) + if sts == 0: + self.source = reader + self.sharedCtx['sourceFile'] = input + ret = 0 + break + # setup handlers and output if success + if ret == 0: + self.source.setParser(self.parsers) + + baseName = self.sharedCtx['sourceFile'] + baseName = os.path.splitext(baseName)[0] + self.sharedCtx['Output'] = baseName + self.sharedCtx['UI'] = writeUI(baseName) + self.sharedCtx['Stat'] = statistic(baseName) + self.sharedCtx['Stack'] = callStack() + self.sharedCtx['Opt'] = options + return ret + + # start process event from trace file + def process(self) -> None: + self.source.process(self.filter, self.callback) + + # close + def __del__(self): + del self.source + del self.readers + del self.instances + del self.handlers + del self.sharedCtx + + # test if event handler is set for this event + def filter(self, evt) -> bool: + if 'raw' in self.sharedCtx['Opt']: + return True + if 'sys' not in evt or 'name' not in evt: + return False + if evt['sys'] not in self.handlers: + return False + handler = self.handlers[evt['sys']] + if evt['name'] not in handler and 'allEvent' not in handler: + return False + return True + + # call back function to process event with handler + def callback(self, evt) -> None: + if evt['sys'] not in self.handlers: + return + # get handler, could be a list, multi handler for single event + hnd = self.handlers[evt['sys']] + flag = 0 + if evt['name'] in hnd: + for h in hnd[evt['name']]: + sts = h(evt) + if sts != None and sts < 0: + flag = 1 + # call all event handler at last step, skip if any handler has returned -1 + if 'allEvent' in hnd and flag == 0: + for h in hnd['allEvent']: + h(evt) + + # register event handler + def regHandler(self, sys, name, handler) -> None: + if name == None: + name = 'allEvent' # name = None means handler for all events of this trace system + if sys not in self.handlers: + self.handlers[sys] = {} + # add handler to list + hnd = self.handlers[sys] + if name in hnd: + hnd[name].append(handler) + else: + hnd[name] = [handler] + + # register event head parser from raw message + def regParser(self, id, parser) -> int: + if id in self.parsers: + print('Warning! duplicated event header id') + return -1 + self.parsers[id] = parser + return 0 + + # get shared context + def getContext(self) -> dict: + return self.sharedCtx diff --git a/tracetool/dataParser.py b/tracetool/dataParser.py new file mode 100644 index 00000000..964520a5 --- /dev/null +++ b/tracetool/dataParser.py @@ -0,0 +1,288 @@ +# +# Copyright (C) Intel Corporation. All rights reserved. +# Licensed under the MIT License. +# + +import os +import json +import glob +import uuid +import struct +from manifest import * + +def formatAnsiStr(raw): + str = '' + size = 0 + while True: + c = raw[size] + size += 1 + if c == 0 or len(raw) <= size: + break + str += chr(c) + return str, size + +def formatUnicodeStr(raw): + str = '' + size = 0 + while True: + c = raw[size] + (raw[size+1]<<8) + size += 2 + if c == 0: + break + str += chr(c) + return str, size + +def formatInt(raw): + return int.from_bytes(raw, 'little'), 0 # return 0 for fix sized data type + +def formatHex(raw): + return hex(int.from_bytes(raw, 'little')), 0 + +def formatFloat(raw): + return struct.unpack('f', raw)[0], 0 + +def formatDouble(raw): + return struct.unpack('d', raw)[0], 0 + +def formatMap(raw, fmt): + ret = '' + val = int.from_bytes(raw, 'little') + if val in fmt: + ret= fmt[val] + ret += ' ({:d})'.format(val) + return ret, 0 + +def formatBits(raw, fmt): + ret = '' + val = int.from_bytes(raw, 'little') + if val: + pos = 0 + i = val + while i: + if i & 1 and pos in fmt: + ret += fmt[pos] + ' | ' + pos += 1 + i >>= 1 + ret = ret[:-3] # remove | in tail + elif 0 in fmt: + # need special handle for 0 + ret += fmt[0] + ret += ' (0x{:x})'.format(val) + return ret, 0 + +def formatGUID(raw): + return uuid.UUID(bytes_le=raw), 0 + +def formatBinary(raw): + ret = '' + for b in raw: + ret += '%02x' % b + return ret, 0 # no need to return size + +class dataParser: + def __init__(self, pointerSize): + self.pointerSize = pointerSize + + def getInTypeSize(self, fmt): + # field in [name, input type, output type, [len/size from field name]] + if 'Binary' in fmt[1]: + return fmt[3] + if 'Int8' in fmt[1]: + return 1 + if 'Int16' in fmt[1]: + return 2 + if 'Int32' in fmt[1]: + return 4 + if 'Int64' in fmt[1]: + return 8 + if 'Boolean' in fmt[1]: + return 4 + if 'Pointer' in fmt[1]: + return self.pointerSize + if 'Float' in fmt[1]: + return 4 + if 'Double' in fmt[1]: + return 8 + return 0 # return 0 for variable length + + def parseDataStruct(self, raw, tpl): + ret = {} + offset = 0 + total = len(raw) + for f in tpl: + field = f[0] + size = f[1] + format = f[2] + num = f[3] + count = 1 + elem_size = 0 + if isinstance(size, str): + size = ret[size] + if isinstance(num, str): + count = ret[num] + if count > 65535: + elem_size = count >> 16 + count &= 65535 + ret[num] = count + num = count + if isinstance(field, list): + substruct = [] + for i in range(0, count): + sub, size = self.parseDataStruct(raw[offset:], field) + substruct.append(sub) + if elem_size != 0: + size = elem_size + offset += size + ret[format] = substruct + continue + if num > 0: + out = [] + for i in range(0, num): + o,s = format[0](raw[offset:offset+size], *format[1:]) + out.append(o) + offset += size + s + ret[field] = out + continue + if size: + data = raw[offset:offset+size] + else: + data = raw[offset:] + o,s = format[0](data, *(format[1:])) + ret[field] = o + offset += size + s + if offset >= total: + break # happen in case of manifest version > driver trace version + return ret, offset + + def optimizeDataStruct(self, fmt, tpl, m): + st = [] + for f in tpl[fmt]: + item = [] + if f[1] == 'struct': + item.append(self.optimizeDataStruct(f[0], tpl, m)) + item.append(0) + item.append(f[0].replace(fmt, '')) + item.append(f[2]) + st.append(item) + continue + item.append(f[0]) + item.append(self.getInTypeSize(f)) + type = f[1] + if 'Binary' in type: + item.append([formatBinary]) + elif 'Float' in type: + item.append([formatFloat]) + elif 'Double' in type: + item.append([formatDouble]) + elif 'AnsiString' in type: + item.append([formatAnsiStr]) + elif 'UnicodeString' in type: + item.append([formatUnicodeStr]) + elif 'GUID' in type: + item.append([formatGUID]) + else: # default format as int + item.append([formatInt]) + if len(f) > 3 and 'Binary' not in type: + item.append(f[3]) + else: + item.append(0) + # adjust dec/hex output format + out = f[2] + if 'HexInt' in out: + item[2] = [formatHex] + if out in m['bitMap']: + item[2] = [formatBits, m['bitMap'][out]] + elif out in m['valueMap']: + item[2] = [formatMap, m['valueMap'][out]] + st.append(item) + return st + + def optimizeManifest(self, manifest): + m = {'name':manifest['name'], 'id': manifest['id'], 'events': manifest['events']} + # optimize enum maps, split value and bit map, convert key to int + m['valueMap'] = {} + m['bitMap'] = {} + for k,v in manifest['maps'].items(): + type = v['type'] + del v['type'] + if type: + maps = {} + pos = 0 + for b,n in v.items(): + v = int(b, 0) + if v: + v >>=pos + while v: + if v == 1: + maps[pos] = n + break + else: + pos += 1 + v >>= 1 + else: + maps[0] = n + m['bitMap'][k] = maps + else: + maps = {} + for b,n in v.items(): + maps[int(b, 0)] = n + m['valueMap'][k] = maps + # optimize data template, preprocess data type, size and output format + tpl = {} + for k in manifest['templates'].keys(): + tpl[k] = self.optimizeDataStruct(k, manifest['templates'], m) + m['templates'] = tpl + return m + + def loadManifest(self, name = 'all'): + files = glob.glob(r'manifests' + os.sep + '*') + # load media trace format + self.manifest = {} + for f in files: + if f.endswith('.json'): + fp = open(f, 'r') + m = json.load(fp) + fp.close() + elif f.endswith('.man'): + m = manifest.load(f) + else: + continue + m = self.optimizeManifest(m) + if m['name'] not in self.manifest: + self.manifest[m['name']] = m + else: + # select the big one + if len(self.manifest[m['name']]['templates']) < len(m['templates']): + self.manifest[m['name']] = m + + def parseName(self, evt): + if evt['sys'] in self.manifest and str(evt['id']) in self.manifest[evt['sys']]['events']: + desc = self.manifest[evt['sys']]['events'][str(evt['id'])] + evt['name'] = desc['name'] + return evt + return None + + def parseData(self, raw, event): + if event['sys'] not in self.manifest: + return None # ignore unknown provider name + manifest = self.manifest[event['sys']] + if str(event['id']) not in manifest['events']: + return None # ignore unknown event id + desc = manifest['events'][str(event['id'])] + if str(event['op']) not in desc['op']: + return None # ignore unknown event opcode + fmtId = desc['op'][str(event['op'])] + evtData = {} + if fmtId in manifest['templates']: + evtData, size = self.parseDataStruct(raw, manifest['templates'][fmtId]) + event['name'] = desc['name'] + del event['id'] + event['data'] = evtData + return event + + def getIds(self): + map = {} + for name in self.manifest: + id = uuid.UUID(self.manifest[name]['id']).bytes_le.hex() + map[id] = name + return map diff --git a/tracetool/drawQueue.py b/tracetool/drawQueue.py new file mode 100644 index 00000000..03ef9d90 --- /dev/null +++ b/tracetool/drawQueue.py @@ -0,0 +1,42 @@ +# +# Copyright (C) Intel Corporation. All rights reserved. +# Licensed under the MIT License. +# + +# split block to fix chrome tracing queue limitation +class drawQueue: + def __init__(self, output): + self.queue = [] + self.Output = output + + def enter(self, evt): + self.queue.append(evt) + + def exit(self, evt): + found = 0 + for i in range(0, len(self.queue)): + if self.queue[i]['name'] == evt['name']: + found = 1 + break + if found == 0: + return + # handle exit for itself + out = self.queue[i] + if evt['ts'] > out['ts']: + out['dur'] = evt['ts'] - out['ts'] + self.Output.AddEvent(out) + del self.queue[i] + # split block behinds in queue + for s in range(i, len(self.queue)): + slice = self.queue[s] + if evt['ts'] > slice['ts']: + out = slice.copy() + out['dur'] = evt['ts'] - out['ts'] + slice['ts'] = evt['ts'] + self.Output.AddEvent(out) + + def finalize(self): + for blk in self.queue: + blk['ph'] = 'B' + self.Output.AddEvent(blk) + self.queue = [] diff --git a/tracetool/main.py b/tracetool/main.py new file mode 100644 index 00000000..a1ff9dfc --- /dev/null +++ b/tracetool/main.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 + +# +# Copyright (C) Intel Corporation. All rights reserved. +# Licensed under the MIT License. +# +import sys +import os +import gzip +import json +from core import * +from version import version + +# print version +name = os.path.basename(os.path.dirname(os.path.realpath(__file__))) +print('{:s} - Version: {:s}'.format(name, version)) + +inputs = [] +options = [] +for i in sys.argv[1:]: + if i.startswith('-'): + options.append(i[1:]) + else: + inputs.append(i) + +if len(inputs) < 1: + print('No input trace specified.') + print(' usage: python3 main.py [-raw] file.dat|file.etl [file.dat|file.etl ...]') + print('') + print('Options:') + print('-raw Parse trace events and dump into .csv file (ftrace) or .json file') + sys.exit(0) + +trace = core() +if trace.open(inputs, options) < 0: + print('fail to open trace file', inputs) + sys.exit(0) + +trace.getContext()['UI'].AddMetaData({'TraceTool':version}) +trace.process() + +print("\rProcessEvent: 100% !") + +# finalize and generate report, remove input file ext +print("Generating reports ...") +del trace +print("Trace Analysis Complete!") diff --git a/tracetool/manifest.py b/tracetool/manifest.py new file mode 100644 index 00000000..5d0a3d28 --- /dev/null +++ b/tracetool/manifest.py @@ -0,0 +1,190 @@ +# +# Copyright (C) Intel Corporation. All rights reserved. +# Licensed under the MIT License. +# + +import sys +import os +import json +import xml.dom.minidom + +# get the first valid node +def getFirstNode(nodes): + for i in nodes: + if i.nodeType == i.ELEMENT_NODE: + return i + return None + +# strip empty node +def getNodes(nodes): + ret = [] + for i in nodes: + if i.nodeType == i.ELEMENT_NODE: + ret.append(i) + return ret + +# parse xml string nodes into python dict +def parseXmlString(nodes): + ret = {} + list = getNodes(nodes) + for i in list: + ret[i.getAttribute('id')] = i.getAttribute('value') + return ret + +# parse xml map into python dict +def parserXmlMap(node): + ret = {} + list = getNodes(node.childNodes) + for i in list: + key = i.getAttribute('value') + val = i.getAttribute('message')[9:-1] # remove $(string.<>) + ret[key] = val + return ret + +# parse xml struct into python list +def parserXmlStruct(node): + ret = [] + list = getNodes(node.childNodes) + for i in list: + elem = {} + if i.nodeName == 'struct': + elem['struct'] = parserXmlStruct(i) + for attr in i.attributes.items(): + elem[attr[0]] = attr[1] + ret.append(elem) + return ret + +# parser xml element +def parseXmlElement(node): + ret = {'type': node.nodeName} + if node.nodeName in ['bitMap', 'valueMap']: + ret['map'] = parserXmlMap(node) + if node.nodeName == 'template': + ret['struct'] = parserXmlStruct(node) + for attr in node.attributes.items(): + ret[attr[0]] = attr[1] + return ret + +# parser provider +def parseProvider(nodes): + ret = {} + for attr in nodes.attributes.items(): + ret[attr[0]] = attr[1] + list = getNodes(nodes.childNodes) + for i in list: + data = [] + child = getNodes(i.childNodes) + for j in child: + data.append(parseXmlElement(j)) + ret[i.nodeName] = data + return ret + +# format field +def formatField(node): + ret = [node['name'], node['inType']] + if 'map' in node: + ret.append(node['map']) + else: + if 'outType' not in node: + node['outType'] = 'xs:unsignedInt' + ret.append(node['outType']) + if 'length' in node: + if node['length'].isdigit(): + ret.append(int(node['length'])) + else: + ret.append(node['length']) + if 'count' in node: + if node['count'].isdigit(): + ret.append(int(node['count'])) + else: + ret.append(node['count']) + return ret + +class manifest: + + def load(file): + # Open XML manifest + tree = xml.dom.minidom.parse(file) + collection = tree.documentElement + + if collection.nodeName != 'instrumentationManifest': + print('Error: invalid manifest') + return + + # parse from manifest + providerNode = getFirstNode(getFirstNode(getFirstNode(collection.childNodes).childNodes).childNodes) + stringNode = getFirstNode(getFirstNode(getFirstNode(collection.getElementsByTagName('localization')).childNodes).childNodes) + stringMap = parseXmlString(stringNode.childNodes) + provider = parseProvider(providerNode) + + # build event format + opcodes = {'win:Info':'0', 'win:Start':'1', 'win:Stop':'2', 'win:DC_Start':'3', 'win:DC_Stop':'4', 'win:Extension':'5', 'win:Reply':'6', 'win:Resume':'7', 'win:Suspend':'8', 'win:Send':'9', 'win:Receive':'240'} + if 'opcodes' in provider: + for i in provider['opcodes']: + opcodes[i['name']] = i['value'] + + task = {} + for i in provider['tasks']: + task[i['name']] = i['value'] + + evt = {} + for i in provider['events']: + if not 'template' in i: + i['template'] = 't_Empty' + if not 'opcode' in i: + i['opcode'] = 'win:Info' + + id = task[i['task']] + if id in evt: + evt[id]['op'][opcodes[i['opcode']]] = i['template'] + else: + evt[id] = {'name': i['task'], 'op':{opcodes[i['opcode']]:i['template']}} + + map = {} + for i in provider['maps']: + elem = {} + if i['type'] == 'bitMap': + elem['type'] = 1 # bitmap require loop + else: + elem['type'] = 0 + for x, y in i['map'].items(): + elem[x] = stringMap[y] + map[i['name']] = elem + + tmpl = {} + for i in provider['templates']: + field = [] + for j in i['struct']: + if 'struct' in j: + subfield = [] + for sub in j['struct']: + subfield.append(formatField(sub)) + tmpl[i['tid']+j['name']] = subfield + if 'count' in j: + field.append([i['tid']+j['name'], 'struct', j['count']]) + else: + field.append([i['tid']+j['name'], 'struct']) + continue + field.append(formatField(j)) + tmpl[i['tid']] = field + + # sort dict by key, for tracking changes in json + sorted_evt = {} + + for i in sorted(evt.keys(), key=lambda x: int(x)): + sorted_op = {} + for j in sorted(evt[i]['op'].keys(), key=lambda x: int(x)): + sorted_op[j] = evt[i]['op'][j] + sorted_evt[i] = {'name':evt[i]['name'], 'op':sorted_op} + sorted_map = {} + for i in sorted(map.keys()): + sorted_map_elem = {'type':map[i]['type']} + del map[i]['type'] + for v in sorted(map[i].keys(), key=lambda x: int(x,0)): + sorted_map_elem[v] = map[i][v] + sorted_map[i] = sorted_map_elem + sorted_tmpl = {} + for i in sorted(tmpl.keys()): + sorted_tmpl[i] = tmpl[i] + return {'name':provider['name'], 'id':provider['guid'], 'events':sorted_evt, 'maps':sorted_map, 'templates':sorted_tmpl} + diff --git a/tracetool/manifests/Intel-Media-Open.json b/tracetool/manifests/Intel-Media-Open.json new file mode 100644 index 00000000..0688ec35 --- /dev/null +++ b/tracetool/manifests/Intel-Media-Open.json @@ -0,0 +1,1970 @@ +{ + "name": "Intel-Media", + "id": "{4E1C52C9-1D1E-4470-A110-25A9F3EBE1A5}", + "events": { + "1": { + "name": "AllocateResource", + "op": { + "0": "t_AllocateResource", + "1": "t_Empty", + "2": "t_Status" + } + }, + "3": { + "name": "RegisterResource", + "op": { + "3": "t_RegisterResource2" + } + }, + "4": { + "name": "PatchResource", + "op": { + "3": "t_PatchResource2" + } + }, + "12": { + "name": "Codecl_NV12ToP010", + "op": { + "1": "t_Empty", + "2": "t_NV12ToP010Exit" + } + }, + "15": { + "name": "Codec_Decode", + "op": { + "1": "t_Codec_DecodeEntry", + "2": "t_Status" + } + }, + "19": { + "name": "CodecHal_Create", + "op": { + "0": "t_CodecHal_CreateEntry" + } + }, + "20": { + "name": "CodecHal_Execute", + "op": { + "1": "t_CodecHal_ExecuteEntry", + "2": "t_Status" + } + }, + "21": { + "name": "CodecHal_Destroy", + "op": { + "1": "t_Empty", + "2": "t_Empty" + } + }, + "77": { + "name": "MediaCopy", + "op": { + "1": "t_Empty", + "2": "t_Empty" + } + }, + "78": { + "name": "Mos_Batch_Submit", + "op": { + "0": "t_Mos_Batch", + "1": "t_Empty", + "2": "t_Status" + } + }, + "79": { + "name": "VA_Render", + "op": { + "0": "t_vaRender_info", + "1": "t_vaRender_start", + "2": "t_vaRender_end" + } + }, + "80": { + "name": "VA_SyncSurface", + "op": { + "0": "t_BoHandle", + "1": "t_VAId", + "2": "t_Empty" + } + }, + "81": { + "name": "VA_GetImage", + "op": { + "1": "t_vaGetImage_start", + "2": "t_Empty" + } + }, + "82": { + "name": "VA_Config", + "op": { + "0": "t_VAConfig" + } + }, + "83": { + "name": "VA_CreateSurface", + "op": { + "0": "t_VA_CreateSurface_info", + "1": "t_VA_CreateSurface_start", + "2": "t_VAIdArray" + } + }, + "84": { + "name": "VA_DestroySurface", + "op": { + "1": "t_VAIdArray", + "2": "t_Empty" + } + }, + "85": { + "name": "VA_DeriveImage", + "op": { + "1": "t_Empty", + "2": "t_VA_derive_end" + } + }, + "86": { + "name": "VA_MapBuffer", + "op": { + "0": "t_vaMapBuf_info", + "1": "t_vaMapBuf_start", + "2": "t_Empty" + } + }, + "87": { + "name": "VA_UnmapBuffer", + "op": { + "1": "t_VAId", + "2": "t_Empty" + } + }, + "88": { + "name": "VA_LockSurface", + "op": { + "1": "t_VAId", + "2": "t_Empty" + } + }, + "89": { + "name": "VA_UnlockSurface", + "op": { + "1": "t_VAId", + "2": "t_Empty" + } + }, + "90": { + "name": "VA_CreateBuffer", + "op": { + "0": "t_VA_CreateSurface_info", + "1": "t_VA_Buffer_start", + "2": "t_VAId" + } + }, + "91": { + "name": "VA_DestroyBuffer", + "op": { + "1": "t_VAId", + "2": "t_Empty" + } + }, + "92": { + "name": "VA_CreateImage", + "op": { + "1": "t_vaCreateImage_start", + "2": "t_VAId" + } + }, + "93": { + "name": "VA_DestroyImage", + "op": { + "1": "t_VAId", + "2": "t_Empty" + } + }, + "94": { + "name": "VA_PutImage", + "op": { + "1": "t_vaPutImage_start", + "2": "t_Empty" + } + }, + "95": { + "name": "MediaPipeExecute", + "op": { + "0": "t_MeidaPipeExecInfo", + "1": "t_Empty", + "2": "t_Empty" + } + }, + "96": { + "name": "ActivatePacket", + "op": { + "0": "t_ActivatePacketInfo" + } + }, + "113": { + "name": "GPU_ContextCreate", + "op": { + "1": "t_GPUContextCreate_start", + "2": "t_GPUContextCreate_end" + } + }, + "114": { + "name": "GPU_ContextDestroy", + "op": { + "1": "t_GPUContextDestroy_start", + "2": "t_Empty" + } + }, + "115": { + "name": "Picture_Param_AVC", + "op": { + "0": "t_PicParamAvc_info" + } + }, + "119": { + "name": "MediaRuntimeLog", + "op": { + "0": "t_RTLog0", + "1": "t_RTLog1", + "2": "t_RTLog2", + "3": "t_RTLog3", + "4": "t_RTLog4", + "5": "t_RTLog5", + "6": "t_RTLog6", + "7": "t_RTLog7" + } + }, + "121": { + "name": "MediaRuntimeError", + "op": { + "0": "t_RTError0", + "1": "t_RTError1", + "2": "t_RTError2", + "3": "t_RTError3", + "4": "t_Empty", + "5": "t_Empty", + "6": "t_Empty", + "7": "t_Empty" + } + } + }, + "maps": { + "MosFormat": { + "type": 0, + "0": "Any", + "1": "A8R8G8B8", + "2": "X8R8G8B8", + "3": "A8B8G8R8", + "4": "X8B8G8R8", + "5": "A16B16G16B16", + "6": "A16R16G16B16", + "7": "R5G6B5", + "8": "R32U", + "9": "R32F", + "10": "R8G8B8", + "11": "RGBP", + "12": "BGRP", + "13": "YUY2", + "14": "YUYV", + "15": "YVYU", + "16": "UYVY", + "17": "VYUY", + "18": "Y216", + "19": "Y210", + "20": "Y416", + "21": "AYUV", + "22": "AUYV", + "23": "Y410", + "24": "400P", + "25": "NV12", + "26": "NV12_UnAligned", + "27": "NV21", + "28": "NV11", + "29": "NV11_UnAligned", + "30": "P208", + "31": "P208_UnAligned", + "32": "IMC1", + "33": "IMC2", + "34": "IMC3", + "35": "IMC4", + "36": "422H", + "37": "422V", + "38": "444P", + "39": "411P", + "40": "411R", + "41": "I420", + "42": "IYUV", + "43": "YV12", + "44": "YVU9", + "45": "AI44", + "46": "IA44", + "47": "P8", + "48": "A8P8", + "49": "A8", + "50": "L8", + "51": "A4L4", + "52": "A8L8", + "53": "IRW0", + "54": "IRW1", + "55": "IRW2", + "56": "IRW3", + "57": "IRW4", + "58": "IRW5", + "59": "IRW6", + "60": "IRW7", + "61": "STMM", + "62": "Buffer", + "63": "Buffer_2D", + "64": "V8U8", + "65": "R32S", + "66": "R8U", + "67": "R8G8UN", + "68": "R8G8SN", + "69": "G8R8_G8B8", + "70": "R16U", + "71": "R16S", + "72": "R16UN", + "73": "RAW", + "74": "Y8", + "75": "Y1", + "76": "Y16U", + "77": "Y16S", + "78": "L16", + "79": "D16", + "80": "R10G10B10A2", + "81": "B10G10R10A2", + "82": "P016", + "83": "P010", + "84": "YV12_Planar", + "85": "A16B16G16R16F", + "86": "R16G16UN", + "87": "R16F", + "88": "P210", + "89": "P216", + "90": "A16R16G16B16F", + "91": "YUY2V", + "92": "Y216V", + "93": "D32F", + "94": "D24S8UN", + "95": "D32S8X24_Float", + "96": "R16", + "97": "R16G16S", + "98": "R24G8", + "99": "R32", + "100": "R32G8X24", + "101": "R8UN", + "102": "R32G32B32A32F" + }, + "HwCommandType": { + "type": 0, + "0": "NULL", + "1": "MiBatchBufferStart", + "2": "MiCLFLUSH", + "3": "MiConditionalBatchBufferEnd", + "4": "MiCopyMemMem", + "5": "MiFlushDw", + "6": "MiLocalRegistreMem", + "7": "MiReportPerfCount", + "8": "MiSemaphoreMbox", + "9": "MiSemaphoneSignal", + "10": "MiSemaphoneWait", + "11": "MiStoreDataImm", + "12": "MiStoreDataIndex", + "13": "MiStoreRegisterMem", + "14": "MiUpdateGTT", + "15": "PipeControl", + "16": "HWCommandsMax", + "17": "MiBatchBufferStartRCS", + "18": "MfxPipeBufAddr", + "19": "MfxIndirectObjBaseAddr", + "20": "MfxBspBufBaseAddr", + "21": "MfxAvcDirctMode", + "22": "MfxVC1DirctMode", + "23": "MfxVp8Pic", + "24": "MfxDbkObject", + "25": "HucDmem", + "26": "HucVirtualAddr", + "27": "HucIndirectObjBaseAddr", + "28": "VdencPipeBufAddr", + "29": "MediaSurfaceState", + "30": "MediaSurfaceStateAdv", + "31": "MediaStateBaseAddr", + "32": "VeboxState", + "33": "VeboxDiIecp", + "34": "VeboxTilingConvert", + "35": "SfcState", + "36": "MiAtomic", + "37": "MfxCCBaseAddrState", + "38": "VeboxSurfaceState" + }, + "PatchType": { + "type": 0, + "0": "BaseAddress", + "1": "Pitch", + "2": "UV_Y_Offset", + "3": "BindOnly", + "4": "UV_BaseAddress", + "5": "V_BaseAddress", + "6": "V_Y_Offset" + }, + "CodecStandard": { + "type": 0, + "0": "MPEG2", + "1": "VC1", + "2": "AVC", + "3": "JPEG", + "5": "VP8", + "63": "DECRYPT", + "64": "HEVC", + "65": "VP9" + }, + "CodecFunction": { + "type": 1, + "0x0": "INVALID", + "0x1": "DECODE", + "0x2": "ENC", + "0x4": "PAK", + "0x8": "ENC_PAK", + "0x10": "HYBRIDPAK", + "0x20": "ENC_VDENC_PAK", + "0x40": "CREATE_OS_INSTANCE", + "0x80": "DECODE_DECRYPT", + "0x100": "DEMO_COPY", + "0x200": "FEI_PRE_ENC", + "0x400": "FEI_ENC", + "0x800": "FEI_PAK", + "0x1000": "FEI_ENC_PAK" + }, + "vaCtxType": { + "type": 0, + "0": "ContextNone", + "1": "ContextDecoder", + "2": "ContextEncoder", + "3": "ContextVP", + "4": "ContextMedia", + "5": "ContextCM", + "6": "ContextProtected", + "7": "ContextMFE" + }, + "VaProfile": { + "type": 0, + "0": "MPEG2Simple", + "1": "MPEG2Main", + "2": "MPEG4Simple", + "3": "MPEG4AdvancedSimple", + "4": "MPEG4Main", + "5": "H264Baseline", + "6": "H264Main", + "7": "H264High", + "8": "VC1Simple", + "9": "VC1Main", + "10": "VC1Advance", + "11": "H263Baseline", + "12": "JPEGBaseline", + "13": "H264ContrainedBaseline", + "14": "VP8Version0_3", + "15": "H264MultiviewHigh", + "16": "H264StereoHigt", + "17": "HEVCMain", + "18": "HEVCMain10", + "19": "VP9Profile0", + "20": "VP9Profile1", + "21": "VP9Profile2", + "22": "VP9Profile3", + "23": "HEVCMain12", + "24": "HEVCMain422_10", + "25": "HEVCMain422_12", + "26": "HEVCMain444", + "27": "HEVCMain444_10", + "28": "HEVCMain444_12", + "29": "HEVCSccMain", + "30": "HEVCSccMain10", + "31": "HEVCSccMain444", + "32": "AV1Profile0", + "33": "AV1Profile1", + "34": "HEVCSccMain444_10" + }, + "VaEntryPoint": { + "type": 0, + "1": "VLD", + "2": "IZZ", + "3": "IDCT", + "4": "MoComp", + "5": "Deblocking", + "6": "EncodeSlice", + "7": "EncodePicture", + "8": "EncodeSliceLP", + "10": "VideoProcess", + "11": "FEI", + "12": "Stats" + }, + "vaDDIFormat": { + "type": 0, + "0": "NV12", + "1": "NV21", + "2": "Buffer", + "3": "2DBuffer", + "4": "PerfBuffer", + "5": "X8R8G8B8", + "6": "A8R8G8B8", + "7": "X8B8G8R8", + "8": "A8B8G8R8", + "9": "R8G8B8A8", + "10": "R5G6B5", + "11": "R10G10B10A2", + "12": "B10G10A10A2", + "13": "R10G10B10X2", + "14": "B10G10R10X2", + "15": "CPU", + "16": "YUY2", + "17": "UYVY", + "18": "YV12", + "19": "IYUV", + "20": "I420", + "21": "422H", + "22": "444P", + "23": "411P", + "24": "400P", + "25": "422V", + "26": "IMC3", + "27": "P010", + "28": "R8G8B8", + "29": "RGBP", + "30": "BGRP", + "31": "P016", + "32": "Y210", + "33": "Y216", + "34": "AYUV", + "35": "Y410", + "36": "Y416", + "37": "Y8", + "38": "Y16S", + "39": "Y16U", + "40": "VYUY", + "41": "YVYU", + "42": "A16R16G16B16", + "43": "A16B16G16R16", + "44": "P012" + }, + "I195_tile": { + "type": 0, + "0": "None", + "1": "TilingX", + "2": "TilingY" + }, + "vaFormat": { + "type": 1, + "0x1": "YUV420", + "0x2": "YUV422", + "0x4": "YUV444", + "0x8": "YUV411", + "0x10": "YUV400", + "0x100": "YUV420_10bit", + "0x200": "YUV422_10bit", + "0x400": "YUV44_10bit", + "0x1000": "YUV420_12bit", + "0x2000": "YUV422_12bit", + "0x4000": "YUV444_12bit", + "0x10000": "RGB16", + "0x20000": "RGB32", + "0x100000": "RGBP", + "0x200000": "RGB32_10bit", + "0x80000000": "Protected" + }, + "vaBufferType": { + "type": 0, + "0": "VAPictureParameterBuffer", + "1": "VAIQMatrixBuffer", + "2": "VABitPlaneBuffer", + "3": "VASliceGroupMapBuffer", + "4": "VASliceParameterBuffer", + "5": "VASliceDataBuffer", + "6": "VAMacroblockParameterBuffer", + "7": "VAResidualDataBuffer", + "8": "VADeblockingParameterBuffer", + "9": "VAImageBuffer", + "10": "VAProtectedSliceDataBuffer", + "11": "VAQMatrixBuffer", + "12": "VAHuffmanTableBuffer", + "13": "VAProbabilityBuffer", + "21": "VAEncCodedBuffer", + "22": "VAEncSequenceParameterBuffer", + "23": "VAEncPictureParameterBuffer", + "24": "VAEncSliceParameterBuffer", + "25": "VAEncPackedHeaderParameterBuffer", + "26": "VAEncPackedHeaderDataBuffer", + "27": "VAEncMiscParameterBuffer", + "28": "VAEncMacroblockParameterBuffer", + "29": "VAEncMacroblockMapBuffer", + "30": "VAEncQPBuffer", + "41": "VAProcPipelineParameterBuffer", + "42": "VAProcFilterParameterBuffer", + "43": "VAEncFEIMVBuffer", + "44": "VAEncFEIMBCodeBuffer", + "45": "VAEncFEIDistortionBuffer", + "46": "VAEncFEIMBControlBuffer", + "47": "VAEncFEIMVPredictorBuffer", + "48": "VAStatsStatisticsParameterBuffer", + "49": "VAStatsStatisticsBuffer", + "50": "VAStatsStatisticsBottomFieldBuffer", + "51": "VAStatsMVBuffer", + "52": "VAStatsMVPredictorBuffer", + "53": "VAEncMacroblockDisableSkipMapBuffer", + "54": "VAEncFEICTBCmdBuffer", + "55": "VAEncFEICURecordBuffer", + "56": "VADecodeStreamoutBuffer", + "57": "VASubsetsParameterBuffer" + }, + "BOOL": { + "type": 0, + "0": "FALSE", + "1": "TRUE" + }, + "GpuNodeName": { + "type": 0, + "0": "Default3D", + "1": "Render", + "2": "BSD", + "3": "Blt", + "4": "Vebox", + "65536": "Video", + "131072": "Blt_", + "196608": "VE", + "262144": "VCS2", + "327680": "CCS0", + "393216": "GSC", + "458752": "PICS", + "524288": "Overlay", + "589824": "GDI2D", + "655360": "VXD" + }, + "PicFlagsAVC": { + "type": 1, + "0x1": "field_pic", + "0x2": "MbaffFrame", + "0x4": "resid_colr_transf", + "0x8": "sp_for_switch", + "0x40": "RefPic", + "0x80": "constrained_intra_pred", + "0x100": "weighted_pred", + "0x800": "MbsConsecutive", + "0x1000": "frame_mbs_only", + "0x2000": "transform_8x8", + "0x4000": "MinLumaBipredSize8x8", + "0x8000": "IntraPic" + }, + "MT_LOG_ID": { + "type": 0, + "0": "MT_LOG_ID_BASE", + "1": "MT_ERR_MEM_ALLOC", + "2": "MT_ERR_GRAPHIC_ALLOC", + "3": "MT_ERR_NULL_CHECK", + "4": "MT_ERR_HR_CHECK", + "5": "MT_ERR_MOS_STATUS_CHECK", + "6": "MT_ERR_CONDITION_CHECK", + "7": "MT_ERR_INVALID_ARG", + "8": "MT_ERR_LOCK_SURFACE", + "9": "MT_MOS_GPUCXT_CREATE", + "10": "MT_MOS_GPUCXT_DESTROY", + "11": "MT_MOS_GPUCXT_GET", + "12": "MT_MOS_GPUCXT_PRIMARIES", + "13": "MT_MOS_ADDCMD", + "16777216": "MT_LOG_ID_CP_BASE", + "16777217": "MT_CP_HAL_NOT_INITIALIZED", + "16777218": "MT_CP_HAL_FAIL", + "16777219": "MT_CP_HAL_KEY_RULE", + "16777220": "MT_CP_HAL_FW_RULE", + "16777221": "MT_CP_HAL_EPID_CERT", + "16777222": "MT_CP_HAL_VERIFY_TRANS_KERNEL", + "16777223": "MT_CP_HAL_METADATA", + "16777224": "MT_CP_HAL_EPID_STATUS", + "16777225": "MT_CP_HAL_STATUS_CHECK", + "16777226": "MT_CP_PROVISION_CERT_CHECK", + "16777227": "MT_CP_PROVISION_CERT_NOT_FOUND", + "16777228": "MT_CP_KERNEL_RULE", + "16777229": "MT_CP_KERNEL_TRANSCRYPT", + "16777230": "MT_CP_BUFFER_RULE", + "16777231": "MT_CP_MEM_COPY", + "33554432": "MT_LOG_ID_VP_BASE", + "33554433": "MT_VP_CREATE", + "33554434": "MT_VP_DESTROY", + "33554435": "MT_VP_BLT", + "33554436": "MT_VP_BLT_START", + "33554437": "MT_VP_BLT_END", + "33554438": "MT_VP_BLT_BYPSSED", + "33554439": "MT_VP_BLT_FORCE_COLORFILL", + "33554440": "MT_VP_BLT_PROCAMP_PARAM", + "33554441": "MT_VP_BLT_DN_PARAM", + "33554442": "MT_VP_BLT_IEF_PARAM", + "33554443": "MT_VP_BLT_IECP_PARAM", + "33554444": "MT_VP_BLT_SR_PARAM", + "33554445": "MT_VP_BLT_RENDERPASS_DATA", + "33555456": "MT_VP_HAL_ID_BASE", + "33555457": "MT_VP_HAL_PIPELINE_ADAPTER", + "33555458": "MT_VP_HAL_PIPELINE_ADAPTER_EXT_ENTRY", + "33555459": "MT_VP_HAL_PIPELINE_ADAPTER_EXT_EXIT", + "33555460": "MT_VP_HAL_PIPELINE", + "33555461": "MT_VP_HAL_PIPELINE_PREPARE", + "33555462": "MT_VP_HAL_PIPELINE_EXT", + "33555463": "MT_VP_HAL_POLICY", + "33555464": "MT_VP_HAL_HWFILTER", + "33555465": "MT_VP_HAL_SWWFILTER", + "33555466": "MT_VP_HAL_INIT", + "33555467": "MT_VP_HAL_DESTROY", + "33555468": "MT_VP_HAL_RENDER", + "33555469": "MT_VP_HAL_RENDER_VE", + "33555470": "MT_VP_HAL_RENDER_VE_ISNEEDED", + "33555471": "MT_VP_HAL_RENDER_VE_GETOUTPUTPIPE", + "33555472": "MT_VP_HAL_RENDER_SFC", + "33555473": "MT_VP_HAL_RENDER_COMPOSITE", + "33555474": "MT_VP_HAL_ALLOC_SURF", + "33555475": "MT_VP_HAL_REALLOC_SURF", + "33562624": "MT_VP_MHW_ID_BASE", + "33562625": "MT_VP_MHW_VE_SURFSTATE_INPUT", + "33562626": "MT_VP_MHW_VE_SURFSTATE_OUT", + "33562627": "MT_VP_MHW_VE_SURFSTATE_DNOUT", + "33562628": "MT_VP_MHW_VE_SURFSTATE_SKINSCORE", + "33562629": "MT_VP_MHW_VE_SURFSTATE_STMM", + "33562630": "MT_VP_MHW_VE_SCALABILITY", + "33562631": "MT_VP_MHW_VE_ADJUST_SURFPARAM", + "33566720": "MT_VP_KERNEL_ID_BASE", + "33566721": "MT_VP_KERNEL_CSC", + "33566722": "MT_VP_KERNEL_RULE", + "33570816": "MT_MEDIA_COPY_ID_BASE", + "33570817": "MT_VE_DECOMP_COPY", + "33570818": "MT_MEDIA_COPY", + "33570819": "MT_MEDIA_COPY_BLT", + "33570820": "MT_MEDIA_COPY_RENDER", + "33570821": "MT_MEDIA_COPY_VE", + "50331648": "MT_LOG_ID_DEC_BASE", + "50331649": "MT_DEC_HEVC", + "67108864": "MT_LOG_ID_ENC_BASE" + }, + "MT_LOG_LEVEL": { + "type": 0, + "0": "Verbose", + "1": "Normal", + "2": "Critial" + }, + "MT_PARAM_ID": { + "type": 0, + "0": "MT_PARAM_ID_BASE", + "1": "MT_ERROR_CODE", + "2": "MT_COMPONENT", + "3": "MT_SUB_COMPONENT", + "4": "MT_CODE_LINE", + "5": "MT_GENERIC_VALUE", + "6": "MT_PRODUCT_FAMILY", + "7": "MT_SURF_PTR", + "8": "MT_SURF_ALLOC_HANDLE", + "9": "MT_SURF_WIDTH", + "10": "MT_SURF_HEIGHT", + "11": "MT_SURF_PITCH", + "12": "MT_SURF_MOS_FORMAT", + "13": "MT_SURF_TILE_TYPE", + "14": "MT_SURF_TILE_MODE", + "15": "MT_SURF_COMP_ABLE", + "16": "MT_SURF_COMP_MODE", + "17": "MT_SURF_GMM_FLAG_GPU", + "18": "MT_SURF_GMM_FLAG_INF", + "19": "MT_SURF_GMM_FLAG_WA", + "20": "MT_SURF_RES_ARRAYSIZE", + "21": "MT_SURF_RES_INDEX", + "22": "MT_SURF_CP_TAG", + "23": "MT_SURF_IS_INPUT", + "24": "MT_SURF_IS_OUTPUT", + "25": "MT_RECT_LEFT", + "26": "MT_RECT_TOP", + "27": "MT_RECT_RIGHT", + "28": "MT_RECT_BOTTOM", + "29": "MT_SYSMEM_PTR", + "30": "MT_SYSMEM_WIDTH", + "31": "MT_SYSMEM_HSTRIDE", + "32": "MT_SYSMEM_VSTRIDE", + "4096": "MT_PARAM_ID_MOS_BASE", + "4097": "MT_MOS_STATUS", + "4098": "MT_MOS_GPU_NODE", + "4099": "MT_MOS_GPUCXT_MGR_PTR", + "4100": "MT_MOS_GPUCXT_PTR", + "4101": "MT_MOS_GPUCXT_HANDLE", + "4102": "MT_MOS_GPUCXT_COUNT", + "4103": "MT_MOS_GPUCXT_NUMPRIMARIES", + "16777216": "MT_PARAM_ID_CP_BASE", + "16777217": "MT_CP_SESSION_TYPE", + "16777218": "MT_CP_SESSION_MODE", + "16777219": "MT_CP_STREAM_ID", + "16777220": "MT_CP_FW_CAPABILITY", + "16777221": "MT_CP_KEY_LENGTH", + "16777222": "MT_CP_COMMAND_ID", + "16777223": "MT_CP_COMMAND", + "16777224": "MT_CP_GROUP_ID", + "16777225": "MT_CP_METADATA_INFO_VERSION", + "16777226": "MT_CP_FW_API_VERSION", + "16777227": "MT_CP_BUFFER_NAME", + "33554432": "MT_PARAM_ID_VP_BASE", + "33554433": "MT_VP_SCALINGMODE_SR", + "33554944": "MT_PARAM_ID_VP_FTR_BASE", + "33554945": "MT_VP_SKU_FTR_VERING", + "33554946": "MT_VP_SKU_FTR_MCPY", + "33555200": "MT_PARAM_ID_VP_BLT_BASE", + "33555201": "MT_VP_BLT_PARAM_DATA", + "33555202": "MT_VP_BLT_PARAM_FLAG", + "33555203": "MT_VP_BLT_SRC_COUNT", + "33555456": "MT_PARAM_ID_VP_HAL_BASE", + "33555457": "MT_VP_HAL_APO", + "33555458": "MT_VP_HAL_PTR", + "33555459": "MT_VP_HAL_PIPE_CNT", + "33555460": "MT_VP_HAL_INTER_SURF_TYPE", + "33555461": "MT_VP_RENDERPASS_FLAG_COMP_NEEDED", + "33555462": "MT_VP_RENDERPASS_FLAG_HDR_NEEDED", + "33555463": "MT_VP_RENDERPASS_FLAG_FASTCOLORFILL", + "33555464": "MT_VP_RENDERPASS_FLAG_BYPASS_HDRKERNEL", + "33555465": "MT_VP_RENDERPASS_FLAG_USEVEHDRSFC", + "33555466": "MT_VP_RENDERDATA_OUTPUT_PIPE", + "33555467": "MT_VP_RENDERDATA_2PASS_CSC", + "33555468": "MT_VP_RENDERDATA_HDRCSCCUSDS", + "33555469": "MT_VP_RENDERDATA_HDRSFC", + "33555470": "MT_VP_RENDERDATA_HDR3DLUT", + "33555471": "MT_VP_RENDERDATA_HDR1DLUT", + "33555472": "MT_VP_RENDERDATA_BPROCAMP", + "33555473": "MT_VP_RENDERDATA_BIECP", + "33555474": "MT_VP_RENDERDATA_DV_TONAMAPPING", + "33555475": "MT_VP_RENDER_VE_2PASS_SFC", + "33555476": "MT_VP_RENDER_VE_USE_HDRTEMPSURF", + "33555477": "MT_VP_RENDER_VE_HDRMODE", + "33555478": "MT_VP_RENDER_VE_NEEDED", + "33555479": "MT_VP_RENDER_VE_HITLIMITATION", + "33555480": "MT_VP_RENDER_VE_8KFORCERENDER", + "33555481": "MT_VP_RENDER_VE_CROPPING", + "33555482": "MT_VP_RENDER_VE_SFCONLYFORVE", + "33555483": "MT_VP_RENDER_VE_COMPBYPASSFEASIBLE", + "33562624": "MT_PARAM_ID_VP_MHW_BASE", + "33562625": "MT_VP_MHW_VE_SCALABILITY_EN", + "33562626": "MT_VP_MHW_VE_SCALABILITY_USE_SFC", + "33562627": "MT_VP_MHW_VE_SCALABILITY_IDX", + "33566720": "MT_PARAM_ID_VP_KERNEL_BASE", + "33566721": "MT_VP_KERNEL_CSPACE", + "33566722": "MT_VP_KERNEL_RULE_ID", + "33566723": "MT_VP_KERNEL_RULE_LAYERNUM", + "33566724": "MT_VP_KERNEL_RULE_SEARCH_STATE", + "33570816": "MT_PARAM_ID_MEDIA_COPY_BASE", + "33570817": "MT_VE_DECOMP_COPY_SURF_LOCK_STATUS", + "33570818": "MT_MEDIA_COPY_CAPS", + "33570819": "MT_MEDIA_COPY_DIRECTION", + "33570820": "MT_MEDIA_COPY_METHOD", + "50331648": "MT_PARAM_ID_DEC_BASE", + "50331649": "MT_DEC_HUC_ERROR_STATUS2", + "67108864": "MT_PARAM_ID_ENC_BASE" + } + }, + "templates": { + "t_AllocateResource": [ + [ + "Surface Handle", + "win:UInt32", + "win:HexInt32" + ], + [ + "Format", + "win:UInt32", + "MosFormat" + ], + [ + "Width", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Height", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Pitch", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Size", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "TileType", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "GpuFlags", + "win:UInt64", + "win:HexInt64" + ], + [ + "InfoFlags", + "win:UInt64", + "win:HexInt64" + ], + [ + "WaFlags", + "win:UInt32", + "win:HexInt32" + ], + [ + "Reserve", + "win:UInt32", + "win:HexInt32" + ], + [ + "Name", + "win:AnsiString", + "xs:string" + ] + ], + "t_Empty": [], + "t_Status": [ + [ + "Status", + "win:UInt32", + "xs:unsignedInt" + ] + ], + "t_RegisterResource2": [ + [ + "HwCommand", + "win:UInt32", + "HwCommandType" + ], + [ + "DwOffset", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Offset", + "win:UInt32", + "win:HexInt32" + ], + [ + "Size", + "win:UInt32", + "win:HexInt32" + ], + [ + "GpuAddr", + "win:UInt64", + "win:HexInt64" + ] + ], + "t_PatchResource2": [ + [ + "hAllocation", + "win:UInt32", + "win:HexInt32" + ], + [ + "ResourceOffset", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "PatchOffset", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Write", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "HwCommand", + "win:UInt32", + "HwCommandType" + ], + [ + "forceDwordOffset", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "patchType", + "win:UInt32", + "PatchType" + ] + ], + "t_NV12ToP010Exit": [ + [ + "Width", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Height", + "win:UInt32", + "xs:unsignedInt" + ] + ], + "t_Codec_DecodeEntry": [ + [ + "Standard", + "win:UInt32", + "CodecStandard" + ], + [ + "Frame", + "win:UInt32", + "xs:unsignedInt" + ] + ], + "t_CodecHal_CreateEntry": [ + [ + "CodecFunction", + "win:UInt32", + "CodecFunction" + ] + ], + "t_CodecHal_ExecuteEntry": [ + [ + "CodecFunction", + "win:UInt32", + "CodecFunction" + ] + ], + "t_Mos_Batch": [ + [ + "Bo Handle", + "win:UInt32", + "win:HexInt32" + ], + [ + "Write Flag", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Offset", + "win:UInt32", + "win:HexInt32" + ], + [ + "GpuAddr", + "win:UInt64", + "win:HexInt64" + ] + ], + "t_vaRender_info": [ + [ + "ContextId", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Num", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Id", + "win:UInt32", + "xs:unsignedInt", + "Num" + ] + ], + "t_vaRender_start": [ + [ + "ContextId", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "VAContext", + "win:UInt32", + "vaCtxType" + ], + [ + "RenderTarget", + "win:UInt32", + "xs:unsignedInt" + ] + ], + "t_vaRender_end": [ + [ + "ContextId", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Status", + "win:UInt32", + "xs:unsignedInt" + ] + ], + "t_BoHandle": [ + [ + "Handle", + "win:UInt32", + "win:HexInt32" + ] + ], + "t_VAId": [ + [ + "Id", + "win:UInt32", + "xs:unsignedInt" + ] + ], + "t_vaGetImage_start": [ + [ + "SurfaceId", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "X", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Y", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Width", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Height", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "ImageId", + "win:UInt32", + "xs:unsignedInt" + ] + ], + "t_VAConfig": [ + [ + "Profile", + "win:UInt32", + "VaProfile" + ], + [ + "EntryPoint", + "win:UInt32", + "VaEntryPoint" + ], + [ + "Num", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "t_VAConfigConfigs", + "struct", + "Num" + ] + ], + "t_VAConfigConfigs": [ + [ + "Type", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Value", + "win:UInt32", + "win:HexInt32" + ] + ], + "t_VA_CreateSurface_info": [ + [ + "Handle", + "win:UInt32", + "win:HexInt32" + ], + [ + "Format", + "win:UInt32", + "vaDDIFormat" + ], + [ + "Width", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Height", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Pitch", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Size", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Tile", + "win:UInt32", + "I195_tile" + ], + [ + "CpTag", + "win:UInt32", + "win:HexInt32" + ], + [ + "gmmFlags_Gpu", + "win:UInt64", + "win:HexInt64" + ], + [ + "gmmFlags_Info", + "win:UInt64", + "win:HexInt64" + ], + [ + "gmmFlags_Wa", + "win:UInt32", + "win:HexInt32" + ] + ], + "t_VA_CreateSurface_start": [ + [ + "Width", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Height", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Format", + "win:UInt32", + "vaFormat" + ] + ], + "t_VAIdArray": [ + [ + "num", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Id", + "win:UInt32", + "xs:unsignedInt", + "num" + ] + ], + "t_VA_derive_end": [ + [ + "SurfaceId", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "ImageId", + "win:UInt32", + "xs:unsignedInt" + ] + ], + "t_vaMapBuf_info": [ + [ + "VAContext", + "win:UInt32", + "vaCtxType" + ], + [ + "BufferType", + "win:UInt32", + "vaBufferType" + ] + ], + "t_vaMapBuf_start": [ + [ + "Id", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Flags", + "win:UInt32", + "win:HexInt32" + ] + ], + "t_VA_Buffer_start": [ + [ + "Size", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Num", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "BufferType", + "win:UInt32", + "vaBufferType" + ] + ], + "t_vaCreateImage_start": [ + [ + "Width", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Height", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "FourCC", + "win:UInt32", + "win:HexInt32" + ] + ], + "t_vaPutImage_start": [ + [ + "SurfaceId", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "ImageId", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "SrcX", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "SrcY", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "SrcWidth", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "SrcHeight", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "DestX", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "DestY", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "DestWidth", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "DestHeight", + "win:UInt32", + "xs:unsignedInt" + ] + ], + "t_MeidaPipeExecInfo": [ + [ + "PacketId", + "win:UInt32", + "xs:unsignedInt" + ] + ], + "t_ActivatePacketInfo": [ + [ + "PacketId", + "win:UInt32", + "xs:unsignedInt" + ], + [ + "Pipe", + "win:UInt8", + "xs:unsignedByte" + ], + [ + "Pass", + "win:UInt8", + "xs:unsignedByte" + ], + [ + "Row", + "win:UInt8", + "xs:unsignedByte" + ], + [ + "SubPass", + "win:UInt8", + "xs:unsignedByte" + ], + [ + "PipeIndexForSubmit", + "win:UInt8", + "xs:unsignedByte" + ], + [ + "SingleTaskPhaseSupported", + "win:UInt32", + "BOOL" + ] + ], + "t_GPUContextCreate_start": [ + [ + "GpuNode", + "win:UInt32", + "GpuNodeName" + ] + ], + "t_GPUContextCreate_end": [ + [ + "GpuContext", + "win:Pointer", + "win:HexInt64" + ], + [ + "NumOfEngine", + "win:UInt32", + "xs:unsignedInt" + ] + ], + "t_GPUContextDestroy_start": [ + [ + "GpuContext", + "win:Pointer", + "win:HexInt64" + ] + ], + "t_PicParamAvc_info": [ + [ + "FrameIdx", + "win:UInt8", + "xs:unsignedByte" + ], + [ + "MaxFrameNum", + "win:UInt8", + "xs:unsignedByte" + ], + [ + "PocType", + "win:UInt8", + "xs:unsignedByte" + ], + [ + "MaxPoc", + "win:UInt8", + "xs:unsignedByte" + ], + [ + "FrameNum", + "win:UInt16", + "xs:unsignedShort" + ], + [ + "Flags", + "win:UInt16", + "PicFlagsAVC" + ], + [ + "FieldOrderCnt", + "win:UInt32", + "xs:unsignedInt", + 2 + ], + [ + "RefFrameList", + "win:UInt8", + "xs:unsignedByte", + 16 + ] + ], + "t_RTLog0": [ + [ + "LogId", + "win:UInt32", + "MT_LOG_ID" + ], + [ + "LogLevel", + "win:UInt32", + "MT_LOG_LEVEL" + ] + ], + "t_RTLog1": [ + [ + "LogId", + "win:UInt32", + "MT_LOG_ID" + ], + [ + "LogLevel", + "win:UInt32", + "MT_LOG_LEVEL" + ], + [ + "Id1", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value1", + "win:UInt64", + "win:HexInt64" + ] + ], + "t_RTLog2": [ + [ + "LogId", + "win:UInt32", + "MT_LOG_ID" + ], + [ + "LogLevel", + "win:UInt32", + "MT_LOG_LEVEL" + ], + [ + "Id1", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value1", + "win:UInt64", + "win:HexInt64" + ], + [ + "Id2", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value2", + "win:UInt64", + "win:HexInt64" + ] + ], + "t_RTLog3": [ + [ + "LogId", + "win:UInt32", + "MT_LOG_ID" + ], + [ + "LogLevel", + "win:UInt32", + "MT_LOG_LEVEL" + ], + [ + "Id1", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value1", + "win:UInt64", + "win:HexInt64" + ], + [ + "Id2", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value2", + "win:UInt64", + "win:HexInt64" + ], + [ + "Id3", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value3", + "win:UInt64", + "win:HexInt64" + ] + ], + "t_RTLog4": [ + [ + "LogId", + "win:UInt32", + "MT_LOG_ID" + ], + [ + "LogLevel", + "win:UInt32", + "MT_LOG_LEVEL" + ], + [ + "Id1", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value1", + "win:UInt64", + "win:HexInt64" + ], + [ + "Id2", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value2", + "win:UInt64", + "win:HexInt64" + ], + [ + "Id3", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value3", + "win:UInt64", + "win:HexInt64" + ], + [ + "Id4", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value4", + "win:UInt64", + "win:HexInt64" + ] + ], + "t_RTLog5": [ + [ + "LogId", + "win:UInt32", + "MT_LOG_ID" + ], + [ + "LogLevel", + "win:UInt32", + "MT_LOG_LEVEL" + ], + [ + "Id1", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value1", + "win:UInt64", + "win:HexInt64" + ], + [ + "Id2", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value2", + "win:UInt64", + "win:HexInt64" + ], + [ + "Id3", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value3", + "win:UInt64", + "win:HexInt64" + ], + [ + "Id4", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value4", + "win:UInt64", + "win:HexInt64" + ], + [ + "Id5", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value5", + "win:UInt64", + "win:HexInt64" + ] + ], + "t_RTLog6": [ + [ + "LogId", + "win:UInt32", + "MT_LOG_ID" + ], + [ + "LogLevel", + "win:UInt32", + "MT_LOG_LEVEL" + ], + [ + "Id1", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value1", + "win:UInt64", + "win:HexInt64" + ], + [ + "Id2", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value2", + "win:UInt64", + "win:HexInt64" + ], + [ + "Id3", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value3", + "win:UInt64", + "win:HexInt64" + ], + [ + "Id4", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value4", + "win:UInt64", + "win:HexInt64" + ], + [ + "Id5", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value5", + "win:UInt64", + "win:HexInt64" + ], + [ + "Id6", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value6", + "win:UInt64", + "win:HexInt64" + ] + ], + "t_RTLog7": [ + [ + "LogId", + "win:UInt32", + "MT_LOG_ID" + ], + [ + "LogLevel", + "win:UInt32", + "MT_LOG_LEVEL" + ], + [ + "Id1", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value1", + "win:UInt64", + "win:HexInt64" + ], + [ + "Id2", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value2", + "win:UInt64", + "win:HexInt64" + ], + [ + "Id3", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value3", + "win:UInt64", + "win:HexInt64" + ], + [ + "Id4", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value4", + "win:UInt64", + "win:HexInt64" + ], + [ + "Id5", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value5", + "win:UInt64", + "win:HexInt64" + ], + [ + "Id6", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value6", + "win:UInt64", + "win:HexInt64" + ], + [ + "Id7", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value7", + "win:UInt64", + "win:HexInt64" + ] + ], + "t_RTError0": [ + [ + "LogId", + "win:UInt32", + "MT_LOG_ID" + ] + ], + "t_RTError1": [ + [ + "LogId", + "win:UInt32", + "MT_LOG_ID" + ], + [ + "Id1", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value1", + "win:UInt64", + "win:HexInt64" + ] + ], + "t_RTError2": [ + [ + "LogId", + "win:UInt32", + "MT_LOG_ID" + ], + [ + "Id1", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value1", + "win:UInt64", + "win:HexInt64" + ], + [ + "Id2", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value2", + "win:UInt64", + "win:HexInt64" + ] + ], + "t_RTError3": [ + [ + "LogId", + "win:UInt32", + "MT_LOG_ID" + ], + [ + "Id1", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value1", + "win:UInt64", + "win:HexInt64" + ], + [ + "Id2", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value2", + "win:UInt64", + "win:HexInt64" + ], + [ + "Id3", + "win:UInt32", + "MT_PARAM_ID" + ], + [ + "Value3", + "win:UInt64", + "win:HexInt64" + ] + ] + } +} \ No newline at end of file diff --git a/tracetool/manifests/libva_trace.man b/tracetool/manifests/libva_trace.man new file mode 100644 index 00000000..4e036285 --- /dev/null +++ b/tracetool/manifests/libva_trace.man @@ -0,0 +1,612 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tracetool/modules/ftrace.py b/tracetool/modules/ftrace.py new file mode 100644 index 00000000..15536259 --- /dev/null +++ b/tracetool/modules/ftrace.py @@ -0,0 +1,538 @@ +# +# Copyright (C) Intel Corporation. All rights reserved. +# Licensed under the MIT License. +# + +import os +import re +import time +from dataParser import * +from util import * + +TYPE_PADDING = 29 +TYPE_TIME_EXTEND = 30 +TYPE_TIME_STAMP = 31 + +FIELD_ARRAY = (1<<8) +FIELD_DYNAMIC = (1<<9) +FIELD_STRING = (1<<10) + +OPTION_DATE = 1 +OPTION_CPUSTAT = 2 +OPTION_BUFFER = 3 +OPTION_TRACECLOCK = 4 +OPTION_UNAME = 5 +OPTION_HOOK = 6 +OPTION_OFFSET = 7 +OPTION_CPUCOUNT = 8 +OPTION_VERSION = 9 +OPTION_PROCMAPS = 10 +OPTION_TRACEID = 11 +OPTION_TIME_SHIFT = 12 +OPTION_GUEST = 13 + +def readString(file): + str = '' + while True: + c = file.read(1) + if c == b'\x00': + break + str += c.decode('ascii') + return str + +def readNum(file, bytes): + return int.from_bytes(file.read(bytes), 'little') + +def parseProcessName(string): + lines = string.splitlines() + map = {} + for l in lines: + sub = l.split(' ') + map[int(sub[0])] = sub[1] + return map + +def parsePrintkName(string): + lines = string.splitlines() + map = {} + for l in lines: + sub = l.split(':', 1) + fmt = sub[1].replace('"', '') + fmt = fmt.replace('\\n', '') + map[int(sub[0], 16)] = fmt + return map + +def parseSymbolName(string): + lines = string.splitlines() + map = {} + for l in lines: + sub = l.split(' ') + if sub[1] in ['A', 'a'] or '[' not in sub[2]: + continue + name = sub[2].split('\t') + name[1] = name[1][1:-1] # remove [] + map[int(sub[0], 16)] = name + return map + +def parseEventFormat(string, fmt, sys, pointerSize): + lines = string.splitlines() + val = re.findall(r'name:\s+(\w+)', lines[0]) + if len(val) != 1: + print('invalid event format: ' + string) + return + name = val[0] + val = re.findall(r'ID:\s+(\d+)', lines[1]) + if len(val) != 1: + print('invalid event format: ' + string) + return + id = int(val[0]) + fields = [] + for i in range(7, len(lines)): # skip common fields in header + # skip non field line + if 'field:' not in lines[i]: + continue + attr = lines[i].split(';') + # in format of [field: xxx, offset:dd, size:dd, ...] + if len(attr) > 3: + offset = int(re.findall(r'\d+', attr[1])[0]) + size = int(re.findall(r'\d+', attr[2])[0]) + head = attr[0].split(' ') + fname = head[-1] # normally field name is the last one, but array name could be diff + flags = 0 + if '[' in attr[0]: + # remove [xxx] in field name if have + if '[' in fname: + fname = fname.partition('[')[0] + # handle case like __u8 saddr[sizeof(struct sockaddr_in6)] + if ']' in fname: + fname = head[-2].partition('[')[0] + head[0] = head[0].strip().replace('field:', '') + # remove __data_loc/signed/unsigned, only keep data type + if head[0] == '__data_loc': + del head[0] + if head[0] in ['signed', 'unsigned']: + del head[0] + if '8' in head[0] or 'char' in head[0]: + elem_size = 1 + elif '16' in head[0] or 'short' in head[0]: + elem_size = 2 + elif '32' in head[0] or 'int' in head[0]: + elem_size = 4 + elif '64' in head[0] or (head[0] == 'long' and head[1] == 'long'): + elem_size = 8 + elif 'long' in head[0]: + elem_size = pointerSize + else: + print('warning: fail to extract field in ' + lines[i]) + return + flags = size//elem_size + if size != elem_size * flags: + print('warning: array size mismatch in ' + lines[i]) + flags |= FIELD_ARRAY + if '__data_loc' in attr[0]: + flags |= FIELD_DYNAMIC + if 'char' in attr[0]: + flags |= FIELD_STRING + fields.append([fname, offset, size, flags]) + fmt[id] = {'sys': sys, 'name':name, 'field':fields} + +def formatPrintk(fmt, raw): + if '%' in fmt: + sub = fmt.split('%') + ret = sub[0] + offset = 0 + for i in sub[1:]: + if i == '': + ret += '%' + continue + if i[0] == 's': + o, s = formatAnsiStr(raw[offset:]) + ret += o + i[1:] + offset += s + continue + # skip number after % + while i[0] in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']: + i = i[1:] + # calc data size + s = 4 + if i[0:2] == 'll': + s = 8 + i = i[2:] + elif i[0] == 'l': + i = i[1:] + offset += 3 + offset &= ~3 + val = int.from_bytes(raw[offset:offset+s], 'little', signed=True) + offset += s + if i[0] in ['x', 'X']: + ret += hex(val) + else: + ret += str(val) + ret += i[1:] + else: + ret = fmt + return ret + +def ip2addr(sl, target): + end = len(sl) + pos = 0 + # binary search in sorted list + while end - pos > 1: + mid = pos + (end - pos)//2 + if target < sl[mid]: + end = mid + else: + pos = mid + return sl[pos] + +def getTs(it): + return it['ts'] + +def field2str(field): + ret = '' + for k in field: + if isinstance(field[k], list): + if len(field[k]) == 0: + continue + if isinstance(field[k][0], dict): + for a in field[k]: + ret += field2str(a) + else: + ret += '{0}: '.format(k) + for a in field[k]: + ret += '{0} '.format(a) + ret += '; ' + elif isinstance(field[k], dict): + ret += field2str(field[k]) + else: + ret += '{0}:{1}; '.format(k, field[k]) + return ret + +def dumpTrace(fp, evt): + opmap = {0:'info', 1:'start', 2:'end', 3:'info'} + line = evt['pid']+'-'+str(evt['tid'])+','+str(evt['ts'])+','+evt['name']+','+opmap[evt['op']]+',' + line += field2str(evt['data']) + line += '\n' + fp.write(line) + +class traceReader: + + def __init__(self): + self.tracefp = None + self.dumpRaw = False + self.metaData = {} + + def open(self, file, options): + if 'raw' in options: + self.dumpRaw = True + fp = open(file, 'rb') + if fp == -1: + print("failed to open trace file" + file) + return -1 + magic = fp.read(10) + if magic != b'\x17\x08\x44\x74\x72\x61\x63\x69\x6e\x67': + return -1 + if self.dumpRaw: + self.dumpFp = open(os.path.splitext(file)[0]+'.csv', 'w') + self.dumpFp.write('process,ts,event,opcode,event data\n') + ver = readString(fp) + print('trace version '+ver) + endian = readNum(fp, 1) + if endian != 0: + print('big endian trace not support yet') + return -1 + self.pointerSize = readNum(fp, 1) + self.pageSize = readNum(fp, 4) + # page header struct in string + if readString(fp) != 'header_page': + print('invalid header page in ftrace data file') + return -1 + size = readNum(fp, 8) + # skip page header, script don't need that + fp.seek(size, 1) + # event header + if readString(fp) != 'header_event': + print('invalid header event in ftrace data file') + return -1 + size = readNum(fp, 8) + # skip event header, script don't need that + fp.seek(size, 1) + # ftrace event format + count = readNum(fp, 4) + manifest = {} + for i in range(0, count): + size = readNum(fp, 8) + buf = fp.read(size).decode('ascii') + parseEventFormat(buf, manifest, 'ftrace', self.pointerSize) + # event provider system + count = readNum(fp, 4) + for i in range(0, count): + providerName = readString(fp) + num = readNum(fp, 4) + for j in range(0, num): + size = readNum(fp, 8) + buf = fp.read(size).decode('ascii') + parseEventFormat(buf, manifest, providerName, self.pointerSize) + self.manifest = manifest + # ksym info + size = readNum(fp, 4) + buf = fp.read(size).decode('ascii') + self.symbolMap = parseSymbolName(buf) + self.symbolAddr = sorted(list(self.symbolMap.keys())) + # prink info + size = readNum(fp, 4) + buf = fp.read(size).decode('ascii') + self.printkMap = parsePrintkName(buf) + # process info + size = readNum(fp, 8) + buf = fp.read(size).decode('ascii') + self.procesNameMap = parseProcessName(buf) + # load fixup section, sometime trace-cmd trace miss process name/id map + fixup = os.path.splitext(file)[0]+'.fixup' + if os.path.isfile(fixup): + f = open(fixup, 'r') + m = parseProcessName(f.read()) + f.close() + self.procesNameMap.update(m) + # cpu num info + cpuNum = readNum(fp, 4) + # option + str = readString(fp) + if 'options' in str: + type = readNum(fp, 2) + while type != 0: + size = readNum(fp, 4) + if size > 0: + self.parseTraceOptions(type, fp.read(size)) + type = readNum(fp, 2) + str = readString(fp) # read next option + # event buffers + totalSize = 0 + bufmap = [] + if 'flyrecord' in str: + # read buffer in pair of offset and size in file + for i in range(0, cpuNum): + offset = readNum(fp, 8) + size = readNum(fp, 8) + bufmap.append({'offset':offset, 'size':size, 'cur':0, 'events':[]}) + totalSize += size + self.bufmap = bufmap + self.tracefp = fp + # load media trace format + self.parser = dataParser(self.pointerSize) + self.parser.loadManifest() + self.timeStamp = time.time() + self.curOffset = 0 # for progress report + self.totalSize = totalSize + return 0 + + def setParser(self, parsers): + self.headerParser = parsers + + def syncSource(self, src): + return -1 # not support ftace with guc log + + def parseTraceOptions(self, type, raw): + if type == OPTION_UNAME: + self.metaData['Uname'] = raw.decode('ascii').rstrip('\x00') + if type == OPTION_CPUSTAT: + stat = raw.decode('ascii').rstrip('\x00').split('\n', 1) + self.metaData[stat[0]] = stat[1] + + def parseBPrint(self, raw, evt, fmt): + f = fmt[0] + ip = int.from_bytes(raw[f[1]:f[1]+f[2]], 'little') + addr = ip2addr(self.symbolAddr, ip) + [func, mod] = self.symbolMap[addr] + f = fmt[1] + v = int.from_bytes(raw[f[1]:f[1]+f[2]], 'little') + if v in self.printkMap: + s = self.printkMap[v] + else: + s = '...' + f = fmt[2] + msg = func + ': ' + formatPrintk(s, raw[f[1]:]) + evt['data'] = {'mod': mod, 'msg': msg} + return evt + + def parseFTrace(self, raw, event, fmt): + event['op'] = 0 + data = {} + offset = 0 + if event['name'] == 'bprint': + return self.parseBPrint(raw, event, fmt) + if event['name'] == 'print': + for f in fmt: + if f[0] == 'buf': + offset = f[1] + string, size = parseDataString(raw[offset:]) + fields = string.split(':') + if len(fields) != 2: + return None + label = fields[0] + content = fields[1] + if label == 'intel_media': + data[f[0]] = content + event['data'] = data + else: + event = None + return event + for f in fmt: + flags = f[3] + if flags == 0: + val = int.from_bytes(raw[f[1]:f[1]+f[2]], 'little') + data[f[0]] = val + elif flags & FIELD_STRING: + if flags & FIELD_DYNAMIC: + val = int.from_bytes(raw[f[1]:f[1]+f[2]], 'little') + offset = val & ((1<<16)-1) + else: + offset = f[1] + string, size = formatAnsiStr(raw[offset:]) + data[f[0]] = string + elif flags & FIELD_ARRAY: + if flags & FIELD_DYNAMIC: + val = int.from_bytes(raw[f[1]:f[1]+f[2]], 'little') + offset = val & ((1<<16)-1) + size = val >> 16 + else: + offset = f[1] + size = f[2] + array = [] + elemSize = f[3] & 255 + if elemSize == 0: + continue + for i in range(0, size//elemSize): + elem = raw[offset+i*elemSize:offset+(i+1)*elemSize] + array.append(int.from_bytes(elem, 'little')) + data[f[0]] = array + event['data'] = data + return event + + def parseEventData(self, data): + # event data header = 4byte id, 4bytes pid + id = int.from_bytes(data[0:4], 'little') & ((1<<16)-1) + pid = int.from_bytes(data[4:8], 'little') + if id not in self.manifest: + print('event id:(0) is not recognized'.format(id)) + return None + fmt = self.manifest[id] + if pid in self.procesNameMap: + pname = self.procesNameMap[pid] + else: + pname = 'Unknown' + event = {'pid':pname, 'tid':pid, 'sys':fmt['sys'], 'name':fmt['name']} + offset = 8 + + if event['name'] == 'raw_data': + for k in self.headerParser.keys(): + size = len(k) + id = data[offset:offset+size] + if id in self.headerParser: + evtRawData = self.headerParser[id](data[offset:], event) + if self.parser.parseName(event) == None: + return None + # delay event data parse + event['rawData'] = evtRawData + return event + # delay ftrace data parse too + event['rawData'] = data + event['format'] = fmt['field'] + return event + + def processInPage(self, page): + events = [] + pageTime = int.from_bytes(page[0:8], 'little') + offset = 8 + self.pointerSize + while offset < len(page): + hdr = int.from_bytes(page[offset:offset+4], 'little') + offset += 4 + type = hdr & ((1<<5)-1) + delta = hdr >> 5 + if type == TYPE_PADDING: + offset += int.from_bytes(page[offset:offset+4], 'little') + size = 0 + elif type == TYPE_TIME_EXTEND: + pageTime += int.from_bytes(page[offset:offset+4], 'little') << 27 + pageTime += delta + offset += 4 + size = 0 + elif type == TYPE_TIME_STAMP: + pageTime = int.from_bytes(page[offset:offset+4], 'little') << 27 + offset += 4 + size = 0 + elif type == 0: + size = int.from_bytes(page[offset:offset+4], 'little') - 4 + size = (size+3) & ~3 + offset += 4 + else: + size = type * 4 + if size > 0: + eventData = page[offset:offset+size] + offset += size + pageTime += delta + event = self.parseEventData(eventData) + if event != None: + event['ts'] = pageTime//1000 + events.append(event) + return events + + def peekNextEvent(self): + latest = None + event = None + # search from buf queue, find the smallest time stamp event + for buf in self.bufmap: + if not buf['events']: + if buf['cur'] < buf['size']: + self.tracefp.seek(buf['offset']+buf['cur'], 0) + data = self.tracefp.read(self.pageSize) + buf['cur'] += self.pageSize + buf['events'] = self.processInPage(data) + self.reportProgress(self.pageSize) + if not buf['events']: + continue + if latest is None or latest['events'][0]['ts'] > buf['events'][0]['ts']: + latest = buf + if latest is not None: + event = latest['events'].pop(0) + return event + + def reportProgress(self, size): + self.curOffset += size + # print progress every second + if time.time() - self.timeStamp < 1: + return + else: + print('\rProcessEvent: %.1f%%' %(self.curOffset / self.totalSize * 100), end='') + self.timeStamp = time.time() + + def process(self, filter, handler): + self.filter = filter + event = self.peekNextEvent() + if event == None: + return + startTs = event['ts'] + # add a marker event to match UI timestamp with statistic + marker = {'sys':'Intel-Media', 'pid':event['pid'], 'tid':event['tid'], 'name':'MetaData', 'op':0, 'ts':0} + handler(marker) + for k,v in self.metaData.items(): + handler({'sys':'Intel-Media', 'name':'MetaData', 'op':1, 'data':{k:v}}) + del self.metaData + while event != None: + if self.dumpRaw or self.filter(event): + if 'format' in event: + self.parseFTrace(event['rawData'], event, event['format']) + del event['format'] + else: + self.parser.parseData(event['rawData'], event) + del event['rawData'] + if self.dumpRaw: + dumpTrace(self.dumpFp, event) + event['ts'] -= startTs # give tool relative timestamp for ftrace + handler(event) + event = self.peekNextEvent() + + def __del__(self): + if self.tracefp: + self.tracefp.close() + if self.dumpRaw: + self.dumpFp.close() diff --git a/tracetool/modules/i915.py b/tracetool/modules/i915.py new file mode 100644 index 00000000..c77da39b --- /dev/null +++ b/tracetool/modules/i915.py @@ -0,0 +1,151 @@ +# +# Copyright (C) Intel Corporation. All rights reserved. +# Licensed under the MIT License. +# + +from drawQueue import drawQueue + +class traceHandler: + i915EngineName = ['Render', 'Copy', 'VDBox', 'VEBox', 'Compute'] + + def __init__(self, core): + self.sharedCtx = core.getContext() + self.gpuContext = {} + self.fp = None + + core.regHandler('i915', 'i915_request_add', self.requestStart) + core.regHandler('i915', 'i915_request_submit', self.requestStart) + core.regHandler('i915', 'i915_request_retire', self.requestEnd) + core.regHandler('i915', 'i915_request_in', self.requestGpuStart) + core.regHandler('i915', 'i915_request_out', self.requestGpuEnd) + core.regHandler('i915', 'i915_request_wait_begin', self.fenceWaitStart) + core.regHandler('i915', 'i915_request_wait_end', self.fenceWaitEnd) + core.regHandler('ftrace', 'print', self.traceMarkerProcess) + core.regHandler('ftrace', 'bprint', self.i915printk) + + def writeMsg(self, line): + if self.fp == None: + self.fp = open(self.sharedCtx['Output'] + '_i915.txt', 'w') + self.fp.write(line) + + def i915printk(self, evt): + if evt['data']['mod'] != 'i915': + return + # get more runtime info from i916 trace log in next. + line = '{:<10d} {:<6} {:<6} '.format(evt['ts'], evt['pid'], evt['tid']) + self.writeMsg(line + evt['data']['msg'] + '\n') + + def requestStart(self, evt): + data = evt['data'] + tname = data['ctx'] + output = self.sharedCtx['UI'] + stat = self.sharedCtx['Stat'] + if tname not in self.gpuContext: + ctx = {'active':{}, 'queue':drawQueue(output), 'process':[]} + for k in ['ctx', 'class', 'dev', 'instance']: + ctx[k] = data[k] + self.gpuContext[data['ctx']] = ctx + ctx = self.gpuContext[data['ctx']] + if data['seqno'] in ctx['active']: + return # ingore sequence already known + if evt['pid'] not in ctx['process']: + ctx['process'].append(evt['pid']) + engine = {'name':'thread_name', 'ph':'M', 'pid':evt['pid'], 'tid':tname} + engine['args'] = {'name':' ctx '+str(ctx['ctx'])+'('+self.i915EngineName[ctx['class']]+str(ctx['instance'])+')'} + output.AddMetaEvent(engine) + namesort = {'name':'thread_sort_index', 'ph':'M', 'pid':evt['pid'], 'tid':tname, 'args':{'sort_index':1000000+ctx['class']}} + output.AddMetaEvent(namesort) + out = {'pid':evt['pid'], 'tid':tname, 'ts':evt['ts'], 'ph': 'X'} + out['name'] = 'SW #{0}'.format(data['seqno']) + fstart = {'pid':evt['pid'], 'tid':evt['tid'], 'ts':evt['ts'], 'ph': 's', 'id':str(data['ctx'])+str(data['seqno']), 'name':'submit', 'cat':'Workload Flow'} + fend = {'pid':evt['pid'], 'tid':tname, 'ts':evt['ts'], 'ph': 'f', 'id':str(data['ctx'])+str(data['seqno']), 'name':'submit', 'bp':'e', 'cat':'Workload Flow'} + ctx['active'][data['seqno']] = {'pid':evt['pid'], 'flow':[fstart, fend]} + ctx['queue'].enter(out) + stat.enter({'id':str(data['ctx'])+str(data['seqno']), 'class':'Engine'+self.i915EngineName[data['class']], 'name':'Ctx'+str(tname), 'ts':evt['ts']}) + + def requestEnd(self, evt): + data = evt['data'] + output = self.sharedCtx['UI'] + stat = self.sharedCtx['Stat'] + if data['ctx'] not in self.gpuContext: + return # ignore unknown context + # retire all fence <= current in context + ctx = self.gpuContext[data['ctx']] + for k in list(ctx['active']): + if k <= data['seqno']: + out = ctx['active'][k] + for e in out['flow']: + output.AddEvent(e) + ctx['queue'].exit({'name':'HW #{0}'.format(k), 'ts':evt['ts']}) + ctx['queue'].exit({'name':'SW #{0}'.format(k), 'ts':evt['ts']}) + del ctx['active'][k] + stat.exit({'id':str(data['ctx'])+str(data['seqno']), 'ts':evt['ts']}) + + def requestGpuStart(self, evt): + data = evt['data'] + if data['ctx'] not in self.gpuContext or data['seqno'] not in self.gpuContext[data['ctx']]['active']: + return # ignore unknown context + ctx = self.gpuContext[data['ctx']] + out = {'pid':ctx['active'][data['seqno']]['pid'], 'tid':data['ctx'], 'ts':evt['ts'], 'ph': 'X'} + out['name'] = 'HW #{0}'.format(data['seqno']) + ctx['queue'].enter(out) + + def requestGpuEnd(self, evt): + data = evt['data'] + if data['ctx'] not in self.gpuContext: + return # ignore unknown context + ctx = self.gpuContext[data['ctx']] + ctx['queue'].exit({'name':'HW #{0}'.format(data['seqno']), 'ts':evt['ts']}) + self.requestEnd(evt) + + def fenceWaitStart(self, evt): + tname = evt['data']['ctx'] + if tname not in self.gpuContext: + return + out = {'pid':evt['pid'], 'tid':tname, 'ts':evt['ts'], 'ph': 'X'} + out['name'] = 'Wait #{0}'.format(evt['data']['seqno']) + ctx = self.gpuContext[tname] + ctx['queue'].enter(out) + + def fenceWaitEnd(self, evt): + data = evt['data'] + if data['ctx'] not in self.gpuContext: + return + ctx = self.gpuContext[data['ctx']] + ctx['queue'].exit({'name':'Wait #{0}'.format(data['seqno']), 'ts':evt['ts']}) + # fence complete + self.requestEnd(evt) + + def traceMarkerProcess(self, evt): + # per-process counters trace format: + # intel_media:counters,process=abc,pid=123,counter1=value1,counter2=value2 + # global counters trace format: + # intel_media:counters,counter1=value1,counter2=value2 + output = self.sharedCtx['UI'] + data = evt['data'] + tmpStr = data['buf'] + elements = tmpStr.split(',') + if elements[0] == 'counters': + evt['ph'] = 'C' + del elements[0] + args = {} + for e in elements: + name = e.split("=")[0] + value = e.split("=")[1] + if name == 'process': + evt['pid'] = value + evt['name'] = 'per-process counters' + elif name == 'pid': + evt['id'] = value + else: + args[name] = int(value) + evt['args'] = args + if evt['name'] == 'print': + evt['name'] = 'global counters' + evt['id'] = evt['tid'] + output.AddEvent(evt) + + def __del__(self): + if self.fp: + self.fp.close() + diff --git a/tracetool/modules/iHD.py b/tracetool/modules/iHD.py new file mode 100644 index 00000000..99a670bb --- /dev/null +++ b/tracetool/modules/iHD.py @@ -0,0 +1,220 @@ +# +# Copyright (C) Intel Corporation. All rights reserved. +# Licensed under the MIT License. +# + +import re +from util import * + +class traceHandler: + phaseMap = {1:'B', 2:'E'} + compMap = ['Common', 'CP', 'VP', 'Decode', 'Encode'] + + def __init__(self, core): + self.sharedCtx = core.getContext() + self.fp = None + + self.DataDump = {} + + core.regParser(b'ETMI', self.mediaHeaderParse) + core.regHandler('Intel-Media', 'RegisterResource', self.registerResource) + core.regHandler('Intel-Media', 'DataDump', self.processDataDump) + core.regHandler('Intel-Media', 'MetaData', self.processMetaData) + core.regHandler('Intel-Media', 'VA_Render', self.vaRenderCtx) + core.regHandler('Intel-Media', 'Picture_Param_AVC', self.PicParamAVC) + core.regHandler('Intel-Media', 'MediaRuntimeLog', self.rtLog) + core.regHandler('Intel-Media', 'MediaRuntimeError', self.rtLog) + core.regHandler('Intel-Media', None, self.MediaEventHander) + + def mediaHeaderParse(self, raw, evt): + # media trace header = 4byte tag, 2bytes size, 2 bytes event id, 4bytes type + id = int.from_bytes(raw[4:8], 'little') + type = int.from_bytes(raw[8:12], 'little') + total = id & ((1<<16)-1) + id >>= 16 + + # overwrite event name/id/etc + evt['id'] = id + evt['sys'] = 'Intel-Media' + evt['op'] = type + return raw[12:12+total] + + def MediaEventHander(self, evt): + key = str(evt['pid']) + str(evt['tid']) + stack = self.sharedCtx['Stack'] + # WA old driver eDDI_Codec_View start end is not in pair, force it to info + # new driver don't need this, which have new added CpTag field. + if evt['name'] == 'eDDI_Codec_View' and evt['op'] == 1 and 'CpTag' not in evt['data']: + evt['op'] = 0 + output = self.sharedCtx['UI'] + # process start end event + if evt['op'] in [1, 2]: + stat = self.sharedCtx['Stat'] + out = {'pid':evt['pid'], 'tid':evt['tid'], 'ts':evt['ts'], 'ph': self.phaseMap[evt['op']], 'name':evt['name']} + if evt['op'] == 1: + if evt['data']: + out['args'] = {'input':evt['data']} + evt['event'] = out + stack.push(evt) + stat.enter({'id':key, 'class':'Media', 'name':evt['name'], 'ts':evt['ts']}) + else: + stat.exit({'id':key, 'ts':evt['ts']}) + if evt['data']: + out['args'] = {'output':evt['data']} + exit = stack.pop(evt) + if exit != None and 'group' in exit: + if 'args' not in out: + out['args'] = exit['group'] + else: + out['args'].update(exit['group']) + output.AddEvent(out) + else: + cur = stack.find(evt) + if cur != None: + if 'group' not in cur: + cur['group'] = {} + group = cur['group'] + if evt['name'] not in group: + group[evt['name']] = evt['data'] + else: + if isinstance(group[evt['name']], list): + group[evt['name']].append(evt['data']) + else: # change to list and append + save = group[evt['name']] + group[evt['name']] = [save, evt['data']] + else: + # this info event did not belong to any activity + out = {'pid':evt['pid'], 'tid':evt['tid'], 'ts':evt['ts'], 'ph': 'i', 'name':evt['name']} + out['args'] = evt['data'] + output.AddEvent(out) + + def vaRenderCtx(self, evt): + if evt['op'] != 1: + return + ctx = evt['data']['VAContext'] + if 'Context' in ctx: + # cut out XXX from 'ContextXXX (d)' + v = ctx.split('Context') + evt['name'] += '_'+v[1].split(' ')[0] + + def processDataDump(self, event): + output = self.sharedCtx['UI'] + key = str(event['pid']) + str(event['tid']) + if event['op'] == 1: + event['ph'] = 'X' + event['name'] = event['data']['Name'] + del event['data']['Name'] + event['raw'] = [] + self.DataDump[key] = event + if event['op'] == 0: + self.DataDump[key]['raw'] += event['data']['Data'] + if event['op'] == 2: + name = self.DataDump[key]['name'] + self.DataDump[key]['dur'] = event['ts'] - self.DataDump[key]['ts'] + if 'dataParser' in self.sharedCtx and name in self.sharedCtx['dataParser']: + self.sharedCtx['dataParser'][name](self.DataDump[key]) + else: + self.ProcessRawData(self.DataDump[key]) + del self.DataDump[key] + return -1 + + def ProcessRawData(self, event): + output = self.sharedCtx['UI'] + #event['args'] = {event['name']:event['raw']}; + event['args'] = {event['name']: 'skip'} # skip for now, the decrypt output is too big, UI fail to open + del event['raw'] + output.AddEvent(event) + + def processMetaData(self, evt): + output = self.sharedCtx['UI'] + if evt['op'] == 0: + evt['ph'] = 'R' + output.AddEvent(evt) + elif evt['op'] == 1: + output.AddMetaData(evt['data']) + return -1 + + def registerResource(self, evt): + if evt['op'] == 0: + stack = self.sharedCtx['Stack'] + media = stack.find(evt) + if media != None: + media['lastSurf'] = evt['data']['Surface Handle'] + return + if evt['op'] != 3: + return + data = evt['data'] + if 'GpuAddr' not in data: + return -1 # skip old event handling + stack = self.sharedCtx['Stack'] + media = stack.find(evt) + if media == None: + return -1 # skip if no context found + if 'resource' not in media: + media['resource'] = [] + data['accessSize'] = data['Size'] + if 'lastSurf' in media: + data['handle'] = media['lastSurf'] + # find more surface info from surface db + info = {'pid': evt['pid'], 'handle':media['lastSurf']} + surface = self.sharedCtx['Surface'] + record = surface.fetch(info) + if record != None: + for k in ['primary', 'Format', 'Width', 'Height', 'Pitch', 'Size']: + if k in record: + data[k] = record[k] + media['resource'].append(data) + return -1 + + def PicParamAVC(self, evt): + if evt['op'] != 0: + return + # find component name from context + context = None + if 'Stack' in self.sharedCtx: + context = self.sharedCtx['Stack'].find(evt) + if context == None or 'render' not in context: + return + data = evt['data'] + # update frame type to render target + if 'IntraPic' in data['Flags']: + context['render'][context['render']['target']]['Access'] += ' I' + else: + context['render'][context['render']['target']]['Access'] += ' P' # simply to P frame + + def writeOutput(self, line): + if self.fp == None: + self.fp = open(self.sharedCtx['Output'] + '_rtlog.txt', 'w') + self.fp.write(line) + + def stripField(self, evt): + data = evt['data'] + out = [] + comp = int(GetEnumVal(data['LogId'])) >> 24 + out.append(self.compMap[comp]) + id = GetEnumName(data['LogId'])[3:] # remove prefix MT_ + out.append(id) + if 'LogLevel' in data: + out.append(GetEnumName(data['LogLevel'])) + else: + out.append('Error') + cnt = len(data)//2 + for i in range(1, cnt): + n = GetEnumName(data['Id'+str(i)])[3:] # remove prefix MT_ + v = GetEnumName(data['Value'+str(i)]) + out.append(n+': '+v) + return out + + def rtLog(self, evt): + out = self.stripField(evt) + txt = '{:<10d} {:<6} {:<6} {:<6s} {:<30s} {:<8s}'.format(evt['ts'], evt['pid'], evt['tid'], out[0], out[1], out[2]) + for i in out[3:]: + txt += ' ' + i + self.writeOutput(txt+'\n') + return -1 + + def __del__(self): + del self.DataDump + if self.fp: + self.fp.close() + diff --git a/tracetool/modules/libva.py b/tracetool/modules/libva.py new file mode 100644 index 00000000..d4d4de4c --- /dev/null +++ b/tracetool/modules/libva.py @@ -0,0 +1,601 @@ +# +# Copyright (C) Intel Corporation. All rights reserved. +# Licensed under the MIT License. +# + +import os +from ctypes import Structure, c_uint, c_ushort, c_ubyte, Array, cast, POINTER +from util import * + +class traceHandler: + + def __init__(self, core): + self.sharedCtx = core.getContext() + self.vaDb = {} + + core.regParser(b'VATE', self.libvaHeaderParse) + core.regHandler('Libva', 'BufferData', self.bufferDataHandler) + core.regHandler('Libva', 'CreateConfigure', self.configHandler) + core.regHandler('Libva', 'CreateContext', self.contextHandler) + core.regHandler('Libva', 'CreateBuffer', self.bufferHandler) + core.regHandler('Libva', 'CreateSurface', self.surfaceHandler) + core.regHandler('Libva', 'RenderPicture', self.renderHandler) + core.regHandler('Libva', None, self.commonHander) + + self.dispatch = {} + self.profileMap = { + 'MPEG2Simple':mpeg2, + 'MPEG2Main':mpeg2, + 'MPEG4Simple':mpeg4, + 'MPEG4AdvancedSimple':mpeg4, + 'MPEG4Main':mpeg4, + 'H264Baseline':h264, + 'H264Main':h264, + 'H264High':h264, + 'VC1Simple':vc1, + 'VC1Main':vc1, + 'VC1Advanced':vc1, + 'H263Baseline':h263, + 'JPEGBaseline':jpeg, + 'H264ConstrainedBaseline':h264, + 'VP8Version0_3':vp8, + 'H264MultiviewHigh':h264, + 'H264StereoHigh':h264, + 'HEVCMain':hevc, + 'HEVCMain10':hevc, + 'VP9Profile0':vp9, + 'VP9Profile1':vp9, + 'VP9Profile2':vp9, + 'VP9Profile3':vp9, + 'HEVCMain12':hevc, + 'HEVCMain422_10':hevc, + 'HEVCMain422_12':hevc, + 'HEVCMain444':hevc, + 'HEVCMain444_10':hevc, + 'HEVCMain444_12':hevc, + 'HEVCMainSccMain':hevc, + 'HEVCMainSccMain10':hevc, + 'HEVCMainSccMain444':hevc, + 'AV1Profile0':av1, + 'AV1Profile1':av1, + 'HEVCMainSccMain444_10':hevc, + 'Protected':protected} + + def libvaHeaderParse(self, raw, evt): + # libva trace header = 4byte tag, 2bytes size, 2 bytes event id, 4bytes type + id = int.from_bytes(raw[4:8], 'little') + type = int.from_bytes(raw[8:12], 'little') + size = id & ((1<<16)-1) + id >>= 16 + + # set event name/id/etc + evt['id'] = id + evt['sys'] = 'Libva' + evt['op'] = type + return raw[12:12+size] + + def commonHander(self, evt): + output = self.sharedCtx['UI'] + stack = self.sharedCtx['Stack'] + stat = self.sharedCtx['Stat'] + if evt['op'] == 1: + out = {'pid':evt['pid'], 'tid':evt['tid'], 'ts':evt['ts'], 'ph': 'B', 'name':evt['name'], 'args':evt['data']} + output.AddEvent(out) + stack.push(evt) + stat.enter({'id':evt['tid'], 'class':evt['sys'], 'name':evt['name'], 'ts':evt['ts']}) + elif evt['op'] == 2: + out = {'pid':evt['pid'], 'tid':evt['tid'], 'ts':evt['ts'], 'ph': 'E', 'name':evt['name'], 'args':evt['data']} + output.AddEvent(out) + stack.pop(evt) + stat.exit({'id':evt['tid'], 'ts':evt['ts']}) + + def bufferDataHandler(self, evt): + output = self.sharedCtx['UI'] + stack = self.sharedCtx['Stack'] + data = evt['data'] + cur = stack.current(evt['pid'], evt['tid']) + if cur == None or cur['name'] != 'RenderPicture': + return -1 + id = cur['data']['ContextId'] + if evt['pid'] not in self.vaDb or id not in self.vaDb[evt['pid']]['ctx']: + return -1 + ctx = self.vaDb[evt['pid']]['ctx'][id] + # setup profile for buffer parser, fetch from context/config event + if ctx['ConfigId'] not in self.vaDb[evt['pid']]['cfg']: + return -1 + cfg = self.vaDb[evt['pid']]['cfg'][ctx['ConfigId']] + profile = cfg['Profile'] + out = None + if evt['op'] == 0: + data['Profile'] = profile + out = self.parseBuffer(data) + else: + if evt['op'] == 1: + data['Profile'] = profile + data['BufData'] = '' + cur['buffer'] = data # store data in stack + if evt['op'] == 2: + out = self.parseBuffer(cur['buffer']) + del cur['buffer'] + if evt['op'] == 3: + cur['buffer']['BufData'] += data['BufData'] # append data + if out != None: + name = out['Profile'] + ' : ' + out['BufferType'] + blk = {'pid':evt['pid'], 'tid':evt['tid'], 'ts':evt['ts'], 'ph': 'i', 'name':name, 'args':out} + output.AddEvent(blk) + return -1 # skip common handler + + # separate va instance by process + def getInstance(self, pid): + if pid not in self.vaDb: + self.vaDb[pid] = {'ctx':{}, 'cfg':{}, 'buf':{}, 'surf':{}} + return self.vaDb[pid] + + def configHandler(self, evt): + output = self.sharedCtx['UI'] + stack = self.sharedCtx['Stack'] + va = self.getInstance(evt['pid']) + + if evt['op'] == 1: + va['cfg']['cur'] = evt['data'] + elif evt['op'] == 2: + data = evt['data'] + if 'Success ' in data['vaStatus'] and 'cur' in va['cfg']: + va['cfg'][data['ConfigId']] = va['cfg']['cur'] + del va['cfg']['cur'] + + def contextHandler(self, evt): + output = self.sharedCtx['UI'] + stack = self.sharedCtx['Stack'] + va = self.getInstance(evt['pid']) + + if evt['op'] == 1: + va['ctx']['cur'] = evt['data'] + elif evt['op'] == 2: + data = evt['data'] + if 'Success ' in data['vaStatus'] and 'cur' in va['ctx']: + va['ctx'][data['ContextId']] = va['ctx']['cur'] + del va['ctx']['cur'] + + def bufferHandler(self, evt): + output = self.sharedCtx['UI'] + stack = self.sharedCtx['Stack'] + va = self.getInstance(evt['pid']) + + if evt['op'] == 1: + va['buf']['cur'] = evt['data'] + elif evt['op'] == 2: + data = evt['data'] + if 'Success ' in data['vaStatus'] and 'cur' in va['buf']: + va['buf'][data['BufferId']] = va['buf']['cur'] + del va['buf']['cur'] + + def surfaceHandler(self, evt): + output = self.sharedCtx['UI'] + stack = self.sharedCtx['Stack'] + va = self.getInstance(evt['pid']) + + if evt['op'] == 1: + va['surf']['cur'] = evt['data'] + elif evt['op'] == 2: + data = evt['data'] + if 'Success ' in data['vaStatus'] and 'cur' in va['surf']: + for s in data['VASurfaceID']: + va['surf'][s] = va['surf']['cur'] + del va['surf']['cur'] + + def renderHandler(self, evt): + if evt['op'] != 1: + return + data = evt['data'] + va = self.getInstance(evt['pid']) + # fill more info from buffer id + info = [] + for b in data['Buffers']: + buf = 'BufferId: ' + str(b) + if b in va['buf']: + buf += ' BufferType: ' + GetEnumName(va['buf'][b]['BufferType']) + info.append(buf) + data['Buffers'] = info + + def parseBuffer(self, data): + raw = bytes.fromhex(data['BufData']) + profile = GetEnumName(data['Profile']) + type = GetEnumName(data['BufferType']) + cnt = data['MemSize']//data['Size'] + ret = {'Profile':profile, 'BufferType':type, 'Count':cnt, 'Size':data['Size'], 'Details':[]} + if profile not in self.profileMap: + print('Warning! non supported profile {s}'.format(profile)) + return None + if profile not in self.dispatch: + self.dispatch[profile] = self.profileMap[profile]() + pos = 0 + for i in range(cnt): + out = self.dispatch[profile].parse(type, raw[pos:(i+1)*data['Size']]) + if out == None: + print('Warning! non supported buffer type {s}'.format(type)) + return None + ret['Details'].append(out) + pos += data['Size'] + return ret + +class buffer(Structure): + def formatArray(self, val): + ret = '' + if val._type_ is c_ubyte: + ptr = cast(val, POINTER(c_ubyte)) + elif val._type_ is c_ushort: + ptr = cast(val, POINTER(c_ushort)) + elif val._type_ is c_uint: + ptr = cast(val, POINTER(c_uint)) + else: + print('Warning! non supported array type {}'.format(val._type_)) + return ret + + for i in range(len(val)): + ret += '{:02x} '.format(ptr[i]) + if i & 15 == 15: + ret += '\n' + return ret + + def getDict(self): + ret = {} + for field in self._fields_: + val = getattr(self, field[0]) + if isinstance(val, buffer): + ret[field[0]] = val.getDict() + continue + if isinstance(val, Array): + # buffer array + if isinstance(val[0], buffer): + out = [] + for i in val: + out.append(i.getDict()) + ret[field[0]] = out + continue + # 2d array + if isinstance(val[0], Array): + out = [] + for i in val: + out.append(self.formatArray(i)) + ret[field[0]] = out + continue + ret[field[0]] = self.formatArray(val) + continue + ret[field[0]] = val + return ret + +class base: + def parse(self, type, raw): + if type in self.dispatch: + return self.dispatch[type](raw) + return self.formatData(raw) + + def formatData(self, raw): + ret = '' + i = 0 + while i = data['Size']: + alloc['primary'] = i['primary'] + break + self.vaIdMap[key]['bo'+str(evt['tid'])] = [] + for k in ['Format', 'Width', 'Height', 'Pitch', 'Size', 'Tile', 'CpTag']: + alloc[k] = data[k] + alloc['Name'] = 'VASurface'+str(data['Handle']) + self.Allocate(alloc) + + def vaSurfaceFree(self, evt): + if evt['op'] != 1: + return + key = str(evt['pid']) + data = evt['data'] + if key not in self.vaIdMap: + return + idMap = self.vaIdMap[key]['idMap'] + for id in data['Id']: + data = {'ts':evt['ts'], 'pid': evt['pid'], 'tid':evt['tid']} + if id in idMap['Surf']: + data['handle'] = idMap['Surf'][id] + else: + data['handle'] = 'NA' + self.Destroy(data) + + def boVmBind(self, evt): + data = evt['data'] + record = self.fetch({'primary':hex(data['obj'])}) + if record is not None and 'Address' not in record: + record['Address'] = hex(data['vm'] + data['offset']) + self.updateTrack(record) + + def mediaAlloc(self, event): + if event['op'] == 1: + return self.vaSurfaceAlloc(event) + if event['op'] != 0: + return + + data = event['data'] + alloc = {'ts':event['ts'], 'pid':event['pid'], 'tid':event['tid'], 'handle':data['Surface Handle']} + alloc['Compress'] = GetCompress(data['InfoFlags']) + for k in ['Format', 'Width', 'Height', 'Pitch', 'Size']: + alloc[k] = data[k] + alloc['Tile'] = data['TileType'] + if 'Name' in data: + alloc['Name'] = data['Name'] + # find primary handle from i915 + key = str(event['pid']) + if key in self.vaIdMap: + for i in self.vaIdMap[key]['bo'+str(event['tid'])]: + if i['size'] >= data['Size']: + alloc['primary'] = i['primary'] + break + self.vaIdMap[key]['bo'+str(event['tid'])] = [] + self.Allocate(alloc) + + def mediaFree(self, event): + if event['op'] != 0: + return + data = {'ts':event['ts'], 'pid': event['pid'], 'tid':event['tid'], 'handle': event['data']['Surface Handle']} + self.Destroy(data) + + def batchSubmit(self, evt): + if evt['op'] != 0: + return + data = evt['data'] + info = {'pid': evt['pid'], 'handle':data['Bo Handle']} + record = self.fetch(info) + if record != None: + data['Name'] = record['Name'] + else: + data['Name'] = 'Media' + # find component name from context + stack = self.sharedCtx['Stack'] + media = stack.find(evt) + if media == None: + media = {'name':evt['name'], 'ts':evt['ts']} + info['ts'] = media['ts'] + info['tid'] = evt['tid'] + info['operate'] = media['name'] + if data['Write Flag'] != 0: + info['Access'] = 'Write' + else: + info['Access'] = 'Read' + self.Reference(info) + + def resourceHwRef(self, evt): + # find component name from context + stack = self.sharedCtx['Stack'] + media = stack.find(evt) + if media == None: + return -1 # skip common process + if 'lastSurf' not in media or media['lastSurf'] == None: + return -1 # skip common process + if 'lastRef' not in media: + return -1 # skip common process + handle = media['lastSurf'] + media['lastSurf'] = None + ref = media['lastRef'] + ref['Address'] = evt['data']['GpuAddr'] + ref['Offset'] = evt['data']['Offset'] + offset = evt['data']['DwOffset'] + # TODO: put HW CMD and its resource name in centralized class + if 'MfxPipeBufAddr' in evt['data']['HwCommand']: + offsetMap = {} + for ctx in stack.get(evt['pid'], evt['tid']): + if ctx['name'] == 'Codec_DecodeDDI': + if 'H264' in ctx['group']['Codec_DecodeDDI']['DecodeMode']: + # MFX Pipe Buffer addr cmd + offsetMap[1] = 'PreDeblock' + offsetMap[4] = 'PostDeblock' + offsetMap[10] = 'StreamOut' + offsetMap[13] = 'IntraRowScratch' + offsetMap[16] = 'DeblockingFilter' + for i in range(19, 51): + offsetMap[i] = 'RefPic' + offsetMap[55] = 'MacroblockIldbStreamOut' + offsetMap[58] = 'MacroblockIldbStreamOut2' + offsetMap[62] = '4xDsSurface' + offsetMap[65] = 'SliceSizeStreamOut' + else: + # HCP pipe buffer addr cmd + offsetMap[1] = 'PreDeblock' + offsetMap[4] = 'DeblockingFilter' + offsetMap[7] = 'DeblockingFilterTile' + offsetMap[10] = 'DeblockingFilterColumn' + offsetMap[13] = 'MetadataLine' + offsetMap[16] = 'MetadataTileLine' + offsetMap[19] = 'MetadataTileColumn' + offsetMap[22] = 'SaoLine' + offsetMap[25] = 'SaoTileLine' + offsetMap[28] = 'SaoTileColumn' + offsetMap[31] = 'CurMvTemp' + for i in range(37, 53): + offsetMap[i] = 'RefPic' + offsetMap[54] = 'Raw' + offsetMap[57] = 'StreamOut' + offsetMap[60] = 'LcuBaseAddress' + offsetMap[63] = 'LcuILDBStreamOut' + for i in range(66, 82): + offsetMap[i] = 'CollocatedMotionVector' + offsetMap[83] = 'Vp9Prob' + offsetMap[86] = 'Vp9SegmentId' + offsetMap[89] = 'HvdLine' + offsetMap[92] = 'HvdTile' + offsetMap[95] = 'SaoRow' + offsetMap[98] = 'FrameStat' + offsetMap[101] = 'SseSrcPixel' + offsetMap[104] = 'SliceState' + offsetMap[107] = 'CABACSyntax' + offsetMap[110] = 'MvUpRightCol' + offsetMap[113] = 'IntraPredUpRightCol' + offsetMap[116] = 'IntraPredLeftReconCol' + offsetMap[119] = 'CABACSyntax' + if offset in offsetMap: + if 'Access' not in ref: + ref['Access'] = offsetMap[offset] + else: + ref['Access'] += ' ' + offsetMap[offset] + return -1 + + def resourceRef(self, evt): + if evt['op'] == 3: + return self.resourceHwRef(evt) + if evt['op'] != 0: + return + stack = self.sharedCtx['Stack'] + handle = evt['data']['Surface Handle'] + + # find component name from context + media = stack.find(evt) + if media == None: + media = {'name':evt['name'], 'ts':evt['ts']} + # save surface handle for RegisterResource2 locat surface handle, thus it can find detail surface info + media['lastSurf'] = handle + data = {'ts':media['ts'], 'pid':evt['pid'], 'tid':evt['tid'], 'operate': media['name'], 'handle':handle} + # load attribute from context if have + if 'render' in media and handle in media['render']: + for k in media['render'][handle]: + data[k] = media['render'][handle][k] + # set attribute in current event + for k in ['Format', 'Width', 'Height', 'Pitch', 'Size']: + data[k] = evt['data'][k] + data['Compress'] = GetCompress(evt['data']['InfoFlags']) + data['Tile'] = evt['data']['TileType'] + self.Reference(data) + #save a reference to update info later + media['lastRef'] = data + # return -1 to skip common media handler + return -1 + + def boAlloc(self, evt): + k1 = str(evt['pid']) + k2 = 'bo'+str(evt['tid']) + if k1 in self.vaIdMap and k2 in self.vaIdMap[k1]: + self.vaIdMap[k1][k2].append({'primary': hex(evt['data']['obj']), 'size':evt['data']['size']}) + + def close(self): + if len(self.surfaceTrack) == 0: + return + file = self.sharedCtx['Output'] + # remove duplicated record + setflag = set() # use set to test whether record is duplicated + record = [] + for d in self.surfaceTrack: + t = tuple(d.items()) + if t not in setflag: + setflag.add(t) + record.append(d) + # build up render reference + render = {} + for i in record: + if 'Access' in i and 'primary' in i and ('Target' in i['Access'] or 'Write' in i['Access']): + render[i['primary']] = i + if 'Destroy' in i['operate'] and 'primary' in i and i['primary'] in render: + del render[i['primary']] + if 'PAVPTeardown' == i['operate']: + # need clean up all render history when teardown happens + render.clear() + # only check on protected surface + if 'Present' in i['operate'] and 'CpTag' in i and i['CpTag'] != '0x0': + if i['primary'] not in render: + i['Health'] = 'Corruption' + + fields = ['ts','pid','tid','operate', 'handle', 'primary', 'Name', 'Access', 'Health', 'Format', 'Width', 'Height', 'Address', 'Offset', 'Compress', 'Protected', 'CpTag', 'Local'] + line = '' + for f in fields: + line += '{0},'.format(f) + line += '\n' + self.fp.write(line) + for i in record: + line = '' + for f in fields: + if f in i: + line += '{0},'.format(i[f]) + else: + line += ',' + line += '\n' + self.fp.write(line) + self.fp.close(); + + def __del__(self): + self.close() diff --git a/tracetool/statistic.py b/tracetool/statistic.py new file mode 100644 index 00000000..0b64f828 --- /dev/null +++ b/tracetool/statistic.py @@ -0,0 +1,49 @@ +# +# Copyright (C) Intel Corporation. All rights reserved. +# Licensed under the MIT License. +# + +import os + +class statistic: + + def __init__(self, file): + self.file = file + self.fp = None + self.fields = ['class','name','ts','latency'] + self.cache = {} + + def add(self, elem): + if self.fp == None: + self.fp = open(self.file + '_stat.csv', 'w') + line = '' + for f in self.fields: + line += '{0},'.format(f) + line += '\n' + self.fp.write(line) + line = '' + for f in self.fields: + if f in elem: + line += '{0},'.format(elem[f]) + else: + line += ',' + line += '\n' + self.fp.write(line) + + def enter(self, elem): + if elem['id'] in self.cache: + self.cache[elem['id']].append(elem) + else: + self.cache[elem['id']] = [elem] + + def exit(self, elem): + if elem['id'] in self.cache and len(self.cache[elem['id']]) > 0: + start = self.cache[elem['id']].pop() + del start['id'] + start['latency'] = elem['ts'] - start['ts'] + self.add(start) + + def __del__(self): + if self.fp != None: + self.fp.close() + diff --git a/tracetool/test/__init__.py b/tracetool/test/__init__.py new file mode 100644 index 00000000..777e2c63 --- /dev/null +++ b/tracetool/test/__init__.py @@ -0,0 +1,5 @@ +# +# Copyright (C) Intel Corporation. All rights reserved. +# Licensed under the MIT License. +# + diff --git a/tracetool/test/test_callStack.py b/tracetool/test/test_callStack.py new file mode 100644 index 00000000..ad350043 --- /dev/null +++ b/tracetool/test/test_callStack.py @@ -0,0 +1,56 @@ +# +# Copyright (C) Intel Corporation. All rights reserved. +# Licensed under the MIT License. +# + +import unittest +from callStack import * + +class TestCallStack(unittest.TestCase): + + def test_stack(self): + ctx = callStack() + self.assertEqual(ctx.current(0, 1), None) + self.assertEqual(ctx.current(2, 3), None) + + # test normal pid/tid + first = ctx.get(0, 1) + self.assertEqual(len(first), 0) + ctx.push({'pid': 0, 'tid':1, 'id':123, 'name': 'ddi'}) + ctx.push({'pid': 0, 'tid':1, 'id':456, 'name': 'hal'}) + self.assertEqual(ctx.current(0, 1)['id'], 456) + last = ctx.pop({'pid': 0, 'tid':1, 'id':123, 'name': 'ddi'}) + self.assertEqual(last['id'], 123) + self.assertEqual(ctx.current(0, 1), None) + + # test string pid/tid + first = ctx.get('pid', 'tid') + self.assertEqual(len(first), 0) + ctx.push({'pid': 'pid', 'tid':'tid', 'id':123, 'name': 'ddi'}) + ctx.push({'pid': 'pid', 'tid':'tid', 'id':456, 'name': 'hal'}) + self.assertEqual(ctx.current('pid', 'tid')['id'], 456) + self.assertEqual(len(first), 2) + last = ctx.pop({'pid': 'pid', 'tid':'tid', 'id':123, 'name': 'pop'}) + self.assertEqual(last, None) + self.assertEqual(len(first), 2) + + # test push and pop from diff thread id + ctx.push({'pid': 100, 'tid':3, 'id':123, 'name': 'n'}) + ctx.pop({'pid': 100, 'tid':3, 'id':123, 'name': 'n'}) + ctx.push({'pid': 100, 'tid':1, 'id':123, 'name': 'ddi'}) + out = ctx.pop({'pid': 100, 'tid':2, 'id':456, 'name': 'ddi'}) + self.assertEqual(out['name'], 'ddi') + self.assertEqual(ctx.current(100, 1), None) + + def test_find(self): + ctx = callStack() + ctx.push({'sys': 's1', 'pid': 1, 'tid':2, 'id':123, 'name': 'app'}) + ctx.push({'sys': 's1', 'pid': 'pid', 'tid':'tid', 'id':123, 'name': 'ddi'}) + ctx.push({'sys': 's2', 'pid': 'pid', 'tid':'tid', 'id':456, 'name': 'hal'}) + # test find top event with same sys/pid/tid + s1 = ctx.find({'sys': 's1', 'pid': 1, 'tid':2}) + self.assertEqual(s1['name'], 'app') + s1p = ctx.find({'sys': 's1', 'pid': 'pid', 'tid':'tid'}) + self.assertEqual(s1p['name'], 'ddi') + s2 = ctx.find({'sys': 's2', 'pid': 'pid', 'tid':'tid'}) + self.assertEqual(s2['name'], 'hal') diff --git a/tracetool/test/test_core.py b/tracetool/test/test_core.py new file mode 100644 index 00000000..b4b9341a --- /dev/null +++ b/tracetool/test/test_core.py @@ -0,0 +1,185 @@ +# +# Copyright (C) Intel Corporation. All rights reserved. +# Licensed under the MIT License. +# + +import unittest +from core import * + +class handler: + def __init__(self): + self.h1 = 0 + self.h2 = 0 + self.h3 = 0 + self.com = 0 + + def hander1(self, evt): + self.h1 = 1 + + def hander2(self, evt): + self.h2 = 1 + + def hander3(self, evt): + self.h3 = 1 + return -1 + + def common(self, evt): + self.com = 1 + +class reader: + def __init__(self): + self.evt = [] + + def open(self, input, options): + self.options = options + if input.endswith('.dat'): + return 0 + else: + return -1 + + def setParser(self, parsers): + self.parsers = parsers + + def syncSource(self, src): + self.aux = src + return 0 + + def process(self, filter, callback): + for e in self.evt: + callback(e) + + def __del__(self): + pass + +class reader2: + def __init__(self): + self.syncSts = 0 + + def open(self, input, options): + self.options = options + if input.endswith('.bin'): + return 0 + else: + return -1 + + def setParser(self, parsers): + self.parsers = parsers + + def syncSource(self, src): + return -1 + + def process(self, filter, callback): + self.callback = callback + + def __del__(self): + pass + +class TestCore(unittest.TestCase): + + def setUp(self): + self.instance = core() + # remove real readers/handlers + self.instance.readers = [] + self.instance.instances = [] + self.instance.handlers = {} + self.instance.parsers = {} + + def tearDown(self): + del self.instance + + def test_init(self): + ctx = self.instance.getContext() + self.assertTrue(isinstance(ctx, dict)) + + def test_reader(self): + options = {'raw':None} + self.instance.readers = [reader] + # check error path + sts = self.instance.open('test', options) + self.assertEqual(sts, -1) + # check sucess path + sts = self.instance.open('test.dat', options) + self.assertEqual(sts, 0) + + def test_reader2(self): + options = {'raw':None} + self.instance.readers = [reader, reader2] + sts = self.instance.open('test.bin', options) + self.assertEqual(sts, 0) + # check option is set in source + self.assertEqual(self.instance.source.options, options) + + def test_reader3(self): + options = {'raw':None} + files = ['test.bin', 'test.dat'] + self.instance.readers = [reader] + sts = self.instance.open(files, options) + self.assertEqual(sts, -1) + # check success path + self.instance.readers.append(reader2) + sts = self.instance.open(files, options) + self.assertEqual(sts, 0) + # check source and name, should select correct source within multi files + self.assertNotEqual(self.instance.source, None) + self.assertEqual(self.instance.sharedCtx['sourceFile'], 'test.dat') + + def test_callback(self): + h1 = handler() + h2 = handler() + + self.instance.regHandler('test1', 'e1', h1.hander1) + self.instance.regHandler('test1', 'e1', h2.hander2) + self.instance.regHandler('test1', None, h1.common) + self.instance.regHandler('test3', None, h1.hander3) + self.instance.regHandler('test3', 'e1', h2.hander3) + + sts = self.instance.regParser(b'ETMI', h2.hander3) + self.assertEqual(sts, 0) + sts = self.instance.regParser(b'ETMI', h1.hander3) + self.assertEqual(sts, -1) + + # check filter + self.instance.sharedCtx['Opt'] = {} + self.assertTrue(self.instance.filter({'sys':'test1', 'name': 'e1'})) + self.assertTrue(self.instance.filter({'sys':'test1', 'name':'str'})) + self.assertFalse(self.instance.filter({'sys':'test2', 'name': 'str'})) + self.assertTrue(self.instance.filter({'sys':'test3', 'name': 'str'})) + + # only handle3 called + evt = {'sys':'test3', 'name':'dw'} + self.instance.callback(evt) + self.assertEqual(h1.h1, 0) + self.assertEqual(h1.h2, 0) + self.assertEqual(h1.h3, 1) + self.assertEqual(h1.com, 0) + + evt = {'sys':'test1', 'name':'e1'} + self.instance.callback(evt) + # handle1 should have hander1 handler called + self.assertEqual(h1.h1, 1) + self.assertEqual(h1.h2, 0) + self.assertEqual(h1.h3, 1) + self.assertEqual(h1.com, 1) + # handle2 should have handle2 called + self.assertEqual(h2.h1, 0) + self.assertEqual(h2.h2, 1) + self.assertEqual(h2.h3, 0) + + def test_process(self): + h1 = handler() + + self.instance.regHandler('test1', 'e1', h1.hander1) + self.instance.readers = [reader] + self.instance.open('test.dat', {}) + # inject event and process it + self.instance.source.evt.append({'sys':'test1', 'name': 'e1'}) + self.instance.process() + # check handler is called + self.assertEqual(h1.h1, 1) + # check output files + ctx = self.instance.getContext() + self.assertTrue(isinstance(ctx, dict)) + self.assertTrue('UI' in ctx) + self.assertTrue('Stat' in ctx) + self.assertTrue('Stack' in ctx) + self.assertTrue('Opt' in ctx) diff --git a/tracetool/test/test_dataParser.py b/tracetool/test/test_dataParser.py new file mode 100644 index 00000000..645d3b5c --- /dev/null +++ b/tracetool/test/test_dataParser.py @@ -0,0 +1,37 @@ +# +# Copyright (C) Intel Corporation. All rights reserved. +# Licensed under the MIT License. +# + +import unittest +from dataParser import * + +class TestDataParser(unittest.TestCase): + def setUp(self): + # load media trace format + self.parser = dataParser(8) + self.parser.loadManifest() + + def test_rawdata1(self): + data = b'\x01\x00\x00\x00\x01\x00\x00\x00' + head = {'sys':'Intel-Media', 'id':79, 'op':1} + output = {'ContextId': 1, 'VAContext': 'ContextDecoder (1)'} + + out = self.parser.parseData(data, head) + self.assertEqual(out['data'], output) + + def test_rawdata2(self): + data = b'\x02\x00\x00\x00\x13\x00\x01\x00\x02\x40' + head = {'sys':'Intel-Media', 'id':1, 'op':1} + output = {} + + out = self.parser.parseData(data, head) + self.assertEqual(out['data'], output) + + def test_rawdata3(self): + data = b'\x02\x00\x03\x00\x12\x01\x03\x00' + head = {'sys':'Intel-Media', 'id':83, 'op':2} + output = {'num': 2, 'Id': [196882, 0]} + + out = self.parser.parseData(data, head) + self.assertEqual(out['data'], output) diff --git a/tracetool/test/test_drawQueue.py b/tracetool/test/test_drawQueue.py new file mode 100644 index 00000000..8e518c87 --- /dev/null +++ b/tracetool/test/test_drawQueue.py @@ -0,0 +1,62 @@ +# +# Copyright (C) Intel Corporation. All rights reserved. +# Licensed under the MIT License. +# + +import unittest +from drawQueue import drawQueue + +class stub: + def __init__(self): + self.traceEvents = [] + def AddEvent(self, evt): + self.traceEvents.append(evt) + +class TestDrawQueue(unittest.TestCase): + + def setUp(self): + self.output = stub() + self.q = drawQueue(self.output) + + def tearDown(self): + del self.output + del self.q + + def test_queue1(self): + self.q.enter({'ts':0, 'name':1}) + self.q.exit({'ts':3, 'name':1}) + out = [{'ts':0, 'dur':3, 'name':1}] + self.assertEqual(self.output.traceEvents, out) + + def test_queue2(self): + self.q.enter({'ts':0, 'name':1}) + self.q.enter({'ts':1, 'name':2}) + self.q.exit({'ts':3, 'name':1}) + self.q.exit({'ts':4, 'name':2}) + out = [{'ts':0, 'dur':3, 'name':1}, {'ts':1, 'dur':2, 'name':2}, {'ts':3, 'dur':1, 'name':2}] + self.assertEqual(self.output.traceEvents, out) + + def test_queue3(self): + self.q.enter({'ts':0, 'name':1}) + self.q.enter({'ts':1, 'name':2}) + self.q.enter({'ts':2, 'name':3}) + self.q.enter({'ts':3, 'name':4}) + self.q.exit({'ts':4, 'name':2}) + self.q.exit({'ts':5, 'name':1}) + self.q.exit({'ts':6, 'name':4}) + self.q.exit({'ts':7, 'name':3}) + out = [ {'ts':1, 'dur':3, 'name':2}, {'ts':2, 'dur':2, 'name':3}, {'ts':3, 'dur':1, 'name':4}, + {'ts':0, 'dur':5, 'name':1}, {'ts':4, 'dur':1, 'name':3}, {'ts':4, 'dur':1, 'name':4}, + {'ts':5, 'dur':1, 'name':4}, {'ts':5, 'dur':2, 'name':3}] + self.assertEqual(self.output.traceEvents, out) + + def test_queue3(self): + self.q.enter({'ts':0, 'name':1}) + self.q.enter({'ts':1, 'name':2}) + self.q.enter({'ts':2, 'name':3}) + self.q.exit({'ts':3, 'name':2}) + self.q.exit({'ts':3, 'name':1}) + self.q.exit({'ts':4, 'name':3}) + out = [ {'ts':1, 'dur':2, 'name':2}, {'ts':2, 'dur':1, 'name':3}, {'ts':0, 'dur':3, 'name':1}, + {'ts':3, 'dur':1, 'name':3}] + self.assertEqual(self.output.traceEvents, out) diff --git a/tracetool/test/test_ftrace.py b/tracetool/test/test_ftrace.py new file mode 100644 index 00000000..bf611c2b --- /dev/null +++ b/tracetool/test/test_ftrace.py @@ -0,0 +1,51 @@ +# +# Copyright (C) Intel Corporation. All rights reserved. +# Licensed under the MIT License. +# + +import unittest +from modules.ftrace import * + +class Testftrace(unittest.TestCase): + + def test_field2str(self): + data = [ {'a':1, '1':2, 0:0, 'b':'c'}, + {'a':[{'a':0, 'b':'a'}]}, + {'a':[{'a':0, 'b':'a'}, {'c':0, 'd':1}]}] + out = [ 'a:1; 1:2; 0:0; b:c; ', + 'a:0; b:a; ', + 'a:0; b:a; c:0; d:1; '] + for i in range(0, len(data)): + self.assertEqual(field2str(data[i]), out[i]) + + def test_parseEventFormat(self): + data = [ 'name: user_stack\nID: 12\nformat:\n\tfield:unsigned short common_type;\toffset:0;\tsize:2;\tsigned:0;\n\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\tsigned:0;\n\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;\tsigned:0;\n\tfield:int common_pid;\toffset:4;\tsize:4;\tsigned:1;\n\n\tfield:unsigned int tgid;\toffset:8;\tsize:4;\tsigned:0;\n\tfield:unsigned long caller[8];\toffset:16;\tsize:64;\tsigned:0;\n\n\n', + 'name: print\nID: 5\nformat:\n\tfield:unsigned short common_type;\toffset:0;\tsize:2;\tsigned:0;\n\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\tsigned:0;\n\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;\tsigned:0;\n\tfield:int common_pid;\toffset:4;\tsize:4;\tsigned:1;\n\n\tfield:unsigned long ip;\toffset:8;\tsize:8;\tsigned:0;\n\tfield:char buf[];\toffset:16;\tsize:0;\tsigned:1;\n\nprint fmt: "%ps: %s", (void *)REC->ip, REC->buf\n', + 'name: branch\nID: 9\nformat:\n\tfield:unsigned short common_type;\toffset:0;\tsize:2;\tsigned:0;\n\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\tsigned:0;\n\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;\tsigned:0;\n\tfield:int common_pid;\toffset:4;\tsize:4;\tsigned:1;\n\n\tfield:unsigned int line;\toffset:8;\tsize:4;\tsigned:0;\n\tfield:char func[30+1];\toffset:12;\tsize:31;\tsigned:1;\n\tfield:char file[20+1];\toffset:43;\tsize:21;\tsigned:1;\n\tfield:char correct;\toffset:64;\tsize:1;\tsigned:1;\n', + 'name: tcp_probe\nID: 1426\nformat:\n\tfield:unsigned short common_type;\toffset:0;\tsize:2;\tsigned:0;\n\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\tsigned:0;\n\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;\tsigned:0;\n\tfield:int common_pid;\toffset:4;\tsize:4;\tsigned:1;\n\n\tfield:__u8 saddr[sizeof(struct sockaddr_in6)];\toffset:8;\tsize:28;\tsigned:0;\n\tfield:__u8 daddr[sizeof(struct sockaddr_in6)];\toffset:36;\tsize:28;\tsigned:0;\n\tfield:__u16 sport;\toffset:64;\tsize:2;\tsigned:0;\n\tfield:__u16 dport;\toffset:66;\tsize:2;\tsigned:0;\n'] + out = [ {12:{'sys':'ftrace', 'name':'user_stack', 'field':[['tgid',8,4,0], ['caller',16,64,264]]}}, + {5:{'sys':'ftrace', 'name':'print', 'field':[['ip',8,8,0], ['buf',16,0,256]]}}, + {9:{'sys':'ftrace', 'name':'branch', 'field':[['line',8,4,0], ['func',12,31,287], ['file',43,21,277],['correct',64,1,0]]}}, + {1426:{'sys':'ftrace', 'name':'tcp_probe', 'field':[['saddr',8,28,284], ['daddr',36,28,284], ['sport',64,2,0],['dport',66,2,0]]}}] + for i in range(0, len(data)): + testout = {} + parseEventFormat(data[i], testout, 'ftrace', 8) + self.assertEqual(testout, out[i]) + + def test_parseFTrace(self): + data = b'\xe9\x05\x01\x00\x19p\x00\x00\x00\x00\x00\x00\x06\x00\x00\x009\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x07\x00\x008\x04\x00\x00\x00\x00\x00\x00\x00\x00\x80\x07\x00\x008\x04\x00\x008\x00\t\x00plane 1A\x00\xb93\x01' + out = {'name':'i915_flip', 'data': {'dst[4]': [0, 0, 1920, 1080], 'frame': 6, 'name': 'plane 1A', 'pipe': 0, 'scanline': 825, 'src[4]': [0, 0, 125829120, 70778880]}, 'op': 0,} + format = [['pipe', 8, 4, 0], ['frame', 12, 4, 0], ['scanline', 16, 4, 0], ['src[4]', 20, 16, 260], ['dst[4]', 36, 16, 260], ['name', 52, 4, 1792]] + cls = traceReader() + self.assertEqual(out, cls.parseFTrace(data, {'name':'i915_flip'}, format)) + + def test_ip2addr(self): + sl = [2, 4, 6, 8, 10, 12] + self.assertEqual(2, ip2addr(sl, 3)) + self.assertEqual(4, ip2addr(sl, 5)) + self.assertEqual(6, ip2addr(sl, 7)) + self.assertEqual(8, ip2addr(sl, 9)) + self.assertEqual(10, ip2addr(sl, 11)) + self.assertEqual(12, ip2addr(sl, 13)) + self.assertEqual(2, ip2addr(sl, 2)) + self.assertEqual(2, ip2addr(sl, 1)) diff --git a/tracetool/test/test_i915.py b/tracetool/test/test_i915.py new file mode 100644 index 00000000..8a885b43 --- /dev/null +++ b/tracetool/test/test_i915.py @@ -0,0 +1,107 @@ +# +# Copyright (C) Intel Corporation. All rights reserved. +# Licensed under the MIT License. +# + +import unittest +from modules.i915 import * + +class stat: + def __init__(self): + self.ctx = {} + self.stat = [] + + def enter(self, elem): + if elem['id'] in self.ctx: + self.ctx[elem['id']].append(elem) + else: + self.ctx[elem['id']] = [elem] + + def exit(self, elem): + if elem['id'] in self.ctx and len(self.ctx[elem['id']]) > 0: + start = self.ctx[elem['id']].pop() + del start['id'] + start['latency'] = elem['ts'] - start['ts'] + self.stat.append(start) + +class ui: + def __init__(self): + self.evt = [] + self.meta = [] + + def AddMetaEvent(self, evt): + self.meta.append(evt) + + def AddEvent(self, evt): + self.evt.append(evt) + +class core: + def __init__(self): + self.ctx = {'UI':ui(), 'Stat':stat()} + self.handlers = {} + + def getContext(self): + return self.ctx + + def regHandler(self, sys, name, handler): + self.handlers[name] = handler + + def process(self, evt): + for e in evt: + self.handlers[e['name']](e) + +class Testi915(unittest.TestCase): + def setUp(self): + self.core = core() + self.ui = self.core.getContext()['UI'] + self.stat = self.core.getContext()['Stat'] + self.i915 = traceHandler(self.core) + + def tearDown(self): + self.ui = None + self.stat= None + del self.core + + def test_gpusubmit(self): + add = [{'name': 'i915_request_add', 'pid':1, 'tid':1, 'ts':1, 'data':{'ctx':12, 'class':0, 'dev':1234,'instance':0, 'seqno':0}}, + {'name': 'i915_request_add', 'pid':1, 'tid':1, 'ts':2, 'data':{'ctx':12, 'class':0, 'dev':1234,'instance':0, 'seqno':1}}] + self.core.process(add) + self.assertEqual(len(self.ui.meta), 2) + + add = [{'name': 'i915_request_in', 'pid':9, 'tid':1, 'ts':3, 'data':{'ctx':12, 'class':0, 'dev':1234,'instance':0, 'seqno':0}}, + {'name': 'i915_request_in', 'pid':9, 'tid':1, 'ts':4, 'data':{'ctx':12, 'class':0, 'dev':1234,'instance':0, 'seqno':1}}] + self.core.process(add) + + add = [{'name': 'i915_request_out', 'pid':9, 'tid':1, 'ts':5, 'data':{'ctx':12, 'class':0, 'dev':1234,'instance':0, 'seqno':0}}, + {'name': 'i915_request_out', 'pid':9, 'tid':1, 'ts':6, 'data':{'ctx':12, 'class':0, 'dev':1234,'instance':0, 'seqno':1}}] + self.core.process(add) + + add = [{'name': 'i915_request_wait_begin', 'pid':1, 'tid':1, 'ts':7, 'data':{'ctx':12, 'class':0, 'dev':1234,'instance':0, 'seqno':0}}, + {'name': 'i915_request_wait_end', 'pid':1, 'tid':1, 'ts':8, 'data':{'ctx':12, 'class':0, 'dev':1234,'instance':0, 'seqno':0}}] + self.core.process(add) + + add = [{'name': 'i915_request_retire', 'pid':1, 'tid':1, 'ts':9, 'data':{'ctx':12, 'class':0, 'dev':1234,'instance':0, 'seqno':0}}, + {'name': 'i915_request_retire', 'pid':1, 'tid':1, 'ts':9, 'data':{'ctx':12, 'class':0, 'dev':1234,'instance':0, 'seqno':1}}] + self.core.process(add) + self.assertEqual(len(self.ui.meta), 2) + + stat = self.stat.stat + self.assertEqual(len(stat), 2) + self.assertEqual(stat[0]['latency'], 4) + self.assertEqual(stat[1]['latency'], 4) + + evt = self.ui.evt + # minimal check on UI, events may change in future + self.assertGreater(len(evt), 5) # at least 2*(sw activty/hw activity/flow) + wait + + def test_counter(self): + add = [{'name': 'print', 'pid':1, 'tid':1, 'ts':1, 'data':{'buf':'counters,process=1,pid=2,bo=1,gpu=2'}}, + {'name': 'print', 'pid':1, 'tid':1, 'ts':2, 'data':{'buf':'counters,local=1,system=2'}}] + self.core.process(add) + evt = self.ui.evt + self.assertEqual(len(evt), 2) + self.assertEqual(evt[0]['name'], 'per-process counters') + self.assertEqual(evt[0]['args']['bo'], 1) + self.assertEqual(evt[1]['name'], 'global counters') + self.assertEqual(evt[1]['args']['system'], 2) + diff --git a/tracetool/test/test_media.py b/tracetool/test/test_media.py new file mode 100644 index 00000000..9b683b79 --- /dev/null +++ b/tracetool/test/test_media.py @@ -0,0 +1,122 @@ +# +# Copyright (C) Intel Corporation. All rights reserved. +# Licensed under the MIT License. +# + +import unittest +from callStack import * +from modules.iHD import * + +class stat: + def __init__(self): + self.ctx = {} + self.stat = [] + + def enter(self, elem): + if elem['id'] in self.ctx: + self.ctx[elem['id']].append(elem) + else: + self.ctx[elem['id']] = [elem] + + def exit(self, elem): + if elem['id'] in self.ctx and len(self.ctx[elem['id']]) > 0: + start = self.ctx[elem['id']].pop() + del start['id'] + start['latency'] = elem['ts'] - start['ts'] + self.stat.append(start) + +class ui: + def __init__(self): + self.evt = [] + self.meta = [] + + def AddMetaEvent(self, evt): + self.meta.append(evt) + + def AddEvent(self, evt): + self.evt.append(evt) + + def AddMetaData(self, meta): + self.meta.append(meta) + +class surface: + def fetch(self, info): + return None + +class core: + def __init__(self): + self.ctx = {'UI':ui(), 'Stat':stat(), 'Stack':callStack(), 'Surface':surface()} + self.handlers = {} + + def getContext(self): + return self.ctx + + def regHandler(self, sys, name, handler): + if name == None: + name = 'allEvent' + if name in self.handlers: + self.handlers[name].append(handler) + else: + self.handlers[name] = [handler] + + def regParser(self, id, handler): + pass + + def process(self, evt): + hnd = self.handlers + flag = 0 + if evt['name'] in hnd: + for h in hnd[evt['name']]: + sts = h(evt) + if sts != None and sts < 0: + flag = 1 + # call all event handler at last step, skip if any handler has returned -1 + if 'allEvent' in hnd and flag == 0: + for h in hnd['allEvent']: + h(evt) + +class TestMedia(unittest.TestCase): + def write(self, line): + self.line = line + + def setUp(self): + self.core = core() + self.ui = self.core.getContext()['UI'] + self.stat = self.core.getContext()['Stat'] + self.iHD = traceHandler(self.core) + self.iHD.writeOutput = self.write + + def tearDown(self): + self.ui = None + self.stat = None + del self.iHD + del self.core + + def test_common(self): + add = [{'sys': 'm', 'name': 'test', 'pid':1, 'tid':1, 'ts':1, 'op': 1, 'data':{'ctx':12}}, + {'sys': 'm', 'name': 'test', 'pid':1, 'tid':1, 'ts':2, 'op': 0, 'data':{'seq':1}}, + {'sys': 'm', 'name': 'test', 'pid':1, 'tid':1, 'ts':3, 'op': 2, 'data':{}}] + for e in add: + self.core.process(e) + self.assertEqual(len(self.ui.evt), 2) + self.assertEqual(self.ui.evt[1]['args']['test'], {'seq':1}) + self.assertEqual(len(self.stat.stat), 1) + + def test_resource(self): + self.core.process({'sys': 'media', 'name': 'eDDI_Codec_View', 'pid':1, 'tid':1, 'ts':1, 'op': 1, 'data':{'hAllocation':11, 'Width':2, 'CpTag':0, 'hMediaDevice':0}}) + self.core.process({'sys': 'media', 'name': 'RegisterResource', 'pid':1, 'tid':1, 'ts':1, 'op': 0, 'data':{'Surface Handle':122, 'Width':2}}) + self.core.process({'sys': 'media', 'name': 'RegisterResource', 'pid':1, 'tid':1, 'ts':1, 'op': 3, 'data':{'HwCommand':'MiStoreRegisterMem (13)', 'Offset':'0x18', 'Size': '0x0', 'GpuAddr':'0xFFFF80040231E018'}}) + stack = self.core.ctx['Stack'] + media = stack.current(1, 1) + resource = media['resource'] + self.assertEqual(resource[0]['Offset'], '0x18') + self.assertEqual(resource[0]['handle'], 122) + self.core.process({'sys': 'media', 'name': 'eDDI_Codec_View', 'pid':1, 'tid':1, 'ts':2, 'op': 2, 'data':{}}) + self.assertEqual(len(self.ui.evt), 2) + self.assertEqual(len(self.stat.stat), 1) + self.assertFalse('render' in self.ui.evt[0]) + + def test_RTLog(self): + self.core.process({'ts':1, 'pid':2, 'tid':3, 'name': 'MediaRuntimeLog', 'data':{'LogId':'MT_ERR_MEM_ALLOC (1)', 'LogLevel':'Normal (1)', 'Id1':'MT_ERROR_CODE (1)', 'Value1': '0x3'}}) + self.assertTrue('Common' in self.line) + self.assertTrue('ERROR_CODE' in self.line) diff --git a/tracetool/test/test_surface.py b/tracetool/test/test_surface.py new file mode 100644 index 00000000..8ecc3e19 --- /dev/null +++ b/tracetool/test/test_surface.py @@ -0,0 +1,129 @@ +# +# Copyright (C) Intel Corporation. All rights reserved. +# Licensed under the MIT License. +# + +import unittest +from unittest import mock +from callStack import * +from modules.surface import * + +class core: + def __init__(self): + self.ctx = {'Stack':callStack()} + self.handlers = {} + + def getContext(self): + return self.ctx + + def regHandler(self, sys, name, handler): + if name == None: + name = 'allEvent' + if name in self.handlers: + self.handlers[name].append(handler) + else: + self.handlers[name] = [handler] + + def regParser(self, id, handler): + pass + + def process(self, evt): + hnd = self.handlers + flag = 0 + if evt['name'] in hnd: + for h in hnd[evt['name']]: + sts = h(evt) + if sts != None and sts < 0: + flag = 1 + # call all event handler at last step, skip if any handler has returned -1 + if 'allEvent' in hnd and flag == 0: + for h in hnd['allEvent']: + h(evt) + def __del__(self): + pass + +class TestSurface(unittest.TestCase): + def setUp(self): + self.core = core() + self.surface = traceHandler(self.core) + self.surface.setupOutput = mock.Mock(return_value=0) + self.surface.close = mock.Mock(return_value=0) + + def tearDown(self): + del self.surface + del self.core + + def test_syncAttr(self): + src = {'Name':1} + db = {'Format':0, 'Name':2} + syncAttr(src, db, 'Name') + self.assertEqual(db['Name'], 1) + syncAttr(src, db, 'Format') + self.assertEqual(src['Format'], 0) + + def test_SurfaceTracking(self): + track = self.surface + internal = {'pid':0, 'ts':1, 'handle':2, 'Format':3} + track.Allocate(internal) + self.assertEqual(track.allocation['02']['Format'], 3) + self.assertEqual(track.surfaceTrack[0]['operate'], 'Allocate') + + globalA = {'pid':1, 'ts':1, 'handle':2, 'Format':4, 'primary':5} + track.Allocate(globalA) + self.assertEqual(track.allocation['12']['Format'], 4) + self.assertEqual(track.surfaceTrack[1]['operate'], 'Allocate') + + track.Reference({'pid':1, 'handle':2}) + self.assertEqual(track.surfaceTrack[2]['Format'], 4) + + #alloc = track.fetch({'pid':1, 'handle':2}) + #self.assertEqual(alloc['12']['Format'], 4) + + boVmBindEvent = {'sys': 'i915', 'data': {'flags': 2048, 'obj': 18446637090493330688, 'offset': 2097152, 'size': 2097152, 'vm': 18446637093275460608}, 'name': 'i915_vma_bind', 'op': 0, 'pid': 'sample_multi_tr', 'tid': 9419, 'ts': 24794} + track.boVmBind(boVmBindEvent) + + mediaAllocEvent = {'sys': 'Intel-Media', 'data': {'Format':'L8 (50)', 'GpuFlags':'0x400000000', 'Height':1, 'InfoFlags':'0xc0300', 'Name':'', 'Pitch':32768, 'Reserve':'0x0', 'Size':65536, 'Surface Handle':'0x40000d80', 'TileType':3, 'WarFlags':'0x0', 'Width': 32768}, 'name':'AllocateRessource', 'op':0, 'pid':3820, 'tid':6036, 'ts':8958621} + track.mediaAlloc(mediaAllocEvent) + + mediaFreeEvent = {'sys':'Intel-Media', 'data':{'Surface Handle':'0x40001740'}, 'name':'FreeResource', 'op':0, 'pid':3820, 'tid':6036, 'ts':8985446} + track.mediaFree(mediaFreeEvent) + + batchSubmitEvent = {'sys': 'Intel-Media', 'data': {'Bo Handle': '0x33', 'Write Flag': 1}, 'name': 'Mos_Batch_Submit', 'op': 0, 'pid': 'sample_multi_tr', 'tid': 10308, 'ts': 473462} + track.batchSubmit(batchSubmitEvent) + + resourceRefEvent = {'sys': 'Intel-Media', 'data': {'Access': 'NA (0)', 'Format': 'L8 (50)', 'GpuFlags': '0x400000000', 'Height': 1, 'InfoFlags': '0xc0300', 'Pitch': 149632, 'Size': 196608, 'Surface Handle': '0x40001640', 'TileType': 3, 'WarFlags':'0x0', 'Width':149632}, 'name': 'RegisterResource', 'op': 0, 'pid': 3820, 'tid': 6036, 'ts': 8975228} + track.resourceRef(resourceRefEvent) + + boAllocEvent = {'sys': 'i915', 'data': {'obj': 18446637090493330688, 'size': 65536}, 'name': 'i915_gem_object_create', 'op': 0, 'pid': 'sample_multi_tr', 'tid': 9419, 'ts': 24781} + track.boAlloc(boAllocEvent) + + def test_vaSurface(self): + track = self.surface + vaSurfStart = {'sys': 'Intel-Media', 'data': {'Format': 'YUV420 (0x1)', 'Height': 720, 'Width': 1280}, 'name': 'VA_CreateSurface', 'op': 1, 'pid': 'lucas', 'tid': 6903, 'ts': 549908} + track.vaSurfaceAlloc(vaSurfStart) + vaSurfEnd = {'sys': 'Intel-Media', 'data': {'Id': [1], 'num': 1}, 'name': 'VA_CreateSurface', 'op': 2, 'pid': 'lucas', 'tid': 6903, 'ts': 549923} + track.vaSurfaceAlloc(vaSurfEnd) + vaSurfFree = {'sys': 'Intel-Media', 'data': {'Id': [1], 'num': 1}, 'name': 'VA_DestroySurface', 'op': 1, 'pid': 'lucas', 'tid': 6903, 'ts': 566284} + track.vaSurfaceFree(vaSurfFree) + + def test_registerResource(self): + track = self.surface + ctx = self.core.getContext()['Stack'].get(10080, 9068) + call = [{'sys':'media', 'name': 'eDDI_Codec_View', 'lastRef':{'Access': 'Target'}, 'lastSurf': '0xc000c880'}, + {'sys':'media', 'name': 'Codec_DecodeDDI', 'group':{'Codec_DecodeDDI':{'DecodeMode':'HEVC (1)'}}}, + {'sys':'media', 'name': 'Codec_Decode', 'data': {'Frame': 9538, 'Standard': 'HEVC (64)'}}] + ctx.extend(call) + reg1 = {'data': {'DwOffset': 38, 'GpuAddr': '0x10f590000', 'Offset': '0x0', 'HwCommand': 'MfxPipeBufAddr (18)'}, 'name': 'RegisterResource', 'op': 3, 'pid': 10080, 'tid': 9068, 'ts': 978563, 'sys':'media'} + track.resourceHwRef(reg1) + self.assertEqual(ctx[0]['lastRef']['Access'], 'Target RefPic') + + def test_registerResource2(self): + track = self.surface + ctx = self.core.getContext()['Stack'].get(10080, 9068) + call = [{'sys':'media', 'name': 'eDDI_Codec_View', 'lastRef':{'Access': 'Target'}, 'lastSurf': '0xc000c880'}, + {'sys':'media', 'name': 'Codec_DecodeDDI', 'group':{'Codec_DecodeDDI':{'DecodeMode':'H264 (1)'}}}, + {'sys':'media', 'name': 'Codec_Decode', 'data': {'Frame': 9538, 'Standard': 'AVC (3)'}}] + ctx.extend(call) + reg1 = {'data': {'DwOffset': 19, 'GpuAddr': '0x10f590000', 'Offset': '0x0', 'HwCommand': 'MfxPipeBufAddr (18)'}, 'name': 'RegisterResource', 'op': 3, 'pid': 10080, 'tid': 9068, 'ts': 978563, 'sys':'media'} + track.resourceHwRef(reg1) + self.assertEqual(ctx[0]['lastRef']['Access'], 'Target RefPic') diff --git a/tracetool/util.py b/tracetool/util.py new file mode 100644 index 00000000..a42c6ecb --- /dev/null +++ b/tracetool/util.py @@ -0,0 +1,57 @@ +# +# Copyright (C) Intel Corporation. All rights reserved. +# Licensed under the MIT License. +# + +def GetCompress(val): + flag = int(val, 16) + compress = '' + if flag & 1048576: + compress += 'Media' + if flag & 1073741824: + compress += 'Render' + if compress == '': + compress = 'None' + return compress + +def GetTile(val): + flag = int(val, 16) + flag >>= 32 + tile = 0 + if flag & 8: + tile = 4 + if flag & 0x10: + tile = 64 + return tile + +def GetHwProtect(val): + flag = int(val, 16) + if flag & 65536: + return 1 + return 0 + +def GetCameraCapture(val): + flag = int(val, 16) + return flag & 1 + +def GetVpState(state, state_name, s, i): + assert state_name in ('bEnable', 'data') + if s in state[state_name] and i in state[state_name][s]: + return state[state_name][s][i] + if state_name == 'bEnable': + return 0 + elif state_name == 'data': + return ['0x0', '0x0', '0x0', '0x0'] + +def GetEnumVal(val): + # cut substring '0xddd' from 'name (0xddd)' + v = val.split('(') + return v[1].split(')')[0] + +def GetEnumName(val): + # cut substring 'name' from 'name (0xddd)' + v = val.split('(') + return v[0].strip() + +def getTs(it): + return it['ts'] diff --git a/tracetool/version.py b/tracetool/version.py new file mode 100644 index 00000000..8be9a29c --- /dev/null +++ b/tracetool/version.py @@ -0,0 +1,15 @@ +# +# Copyright (C) Intel Corporation. All rights reserved. +# Licensed under the MIT License. +# + +# tool version: .. +# increase the version for any new feature, major feature update +# increase the version for any function change (new/modify function, etc.) +# reset minor version to zero when major version is incremented +# increase the version for other change (new definition etc.) +# reset micro version to zero when minor version is incremented + +version = '2.5.1' + + diff --git a/tracetool/writeUI.py b/tracetool/writeUI.py new file mode 100644 index 00000000..af080de1 --- /dev/null +++ b/tracetool/writeUI.py @@ -0,0 +1,73 @@ +# +# Copyright (C) Intel Corporation. All rights reserved. +# Licensed under the MIT License. +# + +import os +import gzip +import json + +# chrome browser has limitation on trace file, should < 250MB +MAX_EVENTS_PER_FILE = 1500000 + +class writeUI: + + def __init__(self, name): + self.name = name + self.traceEvents = [] + self.metaEvents = [] + self.metaData = {} + self.book = None + self.num = 0 + self.idx = 1 + + def setupOutput(self): + if self.book == None: + self.book = gzip.open(self.name+'.json.gz', 'wt') + self.book.write('{"traceEvents":[\n') + + def AddMetaEvent(self, evt): + self.metaEvents.append(evt) + + def AddMetaData(self, evt): + self.metaData.update(evt) + + def AddEvent(self, evt): + self.setupOutput() + #cleanup event field + if 'op' in evt: + del evt['op'] + if 'sys' in evt: + del evt['sys'] + if 'data' in evt: + del evt['data'] + if 'surfaces' in evt: + del evt['surfaces'] + if self.num != 0: + self.book.write(',\n') + json.dump(evt, self.book) + self.num += 1 + if self.num > MAX_EVENTS_PER_FILE: + self.close() + self.book = gzip.open(self.name+str(self.idx)+'.json.gz', 'wt') + self.idx += 1 + self.num = 1 + self.book.write('{"traceEvents":[\n') + start = {'pid':evt['pid'], 'tid':evt['tid'], 'name':'start', 'ph':'R', 'ts':0} + json.dump(start, self.book) + + def close(self): + if self.num == 0: + return + # append meta event, which is process/thread name event + for e in self.metaEvents: + self.book.write(',\n') + json.dump(e, self.book) + self.book.write('],\n') + # append meta data, which is overall trace info event + line = json.dumps(self.metaData) + self.book.write(line[1:]) + self.book.close() + + def __del__(self): + self.close()