diff --git a/tracetool/README.md b/tracetool/README.md new file mode 100644 index 00000000..4bde6e98 --- /dev/null +++ b/tracetool/README.md @@ -0,0 +1,157 @@ +# Linux trace tool + + +## Introduction + +This 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 + +Trace tool uses manifests to decode trace data. Each trace module available in trace tool +needs to have a manifest file in manifests folder. The manifest file could be either in +MSFT ETW XML manifest format or in json format. Current supported traces: + +* [libva_trace.man](./manifests/libva_trace.man) - libva trace manifest in MSFT ETW XML +* [Intel-Media-Open.json](./manifests/Intel-Media-Open.json) - iHD media driver trace manifest in json + +## Trace Modules + +Trace tool loads trace modules from the [modules](./modules) folder. Two types of modules +are supported: + +* Trace readers +* Trace handlers + +Readers support reading data from the trace without performing any action on the read data. +Handlers perform actions over read data. Effectively trace readers provide input to trace +handlers. + +Trace tool loads modules by class names. + +### Trace core + +Trace core loads trace modules making them available for trace tool. Key interfaces: + +| Interface | Description | +| --------- | ----------- | +| `core.regParser(id, parser) -> int` | Registers trace header `parser` to the core. `id` is 4bytes trace identifier. | +| `core.regHandler(sys, name, handler) -> None` | Registers event handler. Set name to None for common trace handler. | +| `core.getContext() -> dict` | Get share context from the core. | + +### Trace readers + +Trace reader module is responsible for parsing trace file into trace events and call +trace handlers one by one in event timestamp order. + +Trace reader is driven by trace core. The following interfaces are required to be +provide by the trace reader module implentation: + +| Interface | Description | +| --------- | ----------- | +| `open(self, file, options) -> int` | Open trace file, returns 0 for sucess, < 0 for failures. User command line options are provided in args. | +| `setParser(self, parsers) -> None` | Set trace header parsers. Since all Linux user space traces 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` | Starts trace event process with filter and handler callbacks. Filter callback could speed up event process. | + +Currently supported trace reader modules: + +| Module | Description | +| ---------- | ----------- | +| ftrace.py | Linux ftace file reader, trace file from trace-cmd | + +### Trace handlers + +Trace event handler module customizes events handling. Since all handler modules are +seperate instances, trace core provides shared context to share data between modules. + +By default, shared context provides the following: + +| Name in context | Description | +| --------------- | ----------- | +| `UI` | Instance of class `writeUI` (see [writeUI.py](./writeUI.py). Class writes events for chrome://tracing. | +| `Stack` | Instance of class `callStack` (see [callStack.py](./callStack.py). Class provides call stack of trace event. Call stack is built from event sequence from the same process id and thread id. | +| `Stat` | Instance of class `statistic` (see [statistic.py](./statistic.py). Class provides statistics for specific events. | +| `Output` | Output path string in case module needs to create its own output file. | + +Handler module only interact with core, should not export interface to external directly. Module register its own event handlers to core through `core.regHandler(sys, name, handler)`. + +It is possible that multi modules register their own handlers for the same event. Core will call these callbacks one by one when target event occurs. + +Handler module could write output into `UI` or `Stat` in share context, also could create and write its own output file and format. Output file path is available in share context `Output`. + +In case a handler module is targeted to provide a common service, it could export its name and instance in share context. Its name in share context should be unique, other module use this name to get service instance. The service interface is defined by module itself. see example [surface.py](./modules/surface.py). + +To add new trace support, handler module for this new trace MUST register event header parser to core, through `core.regParser(id, parser)`. This event header parser is to detect and parse trace header, otherwise trace reader could not recognize this new trace. The id for this new trace should be unique. refer example [libva.py](./modules/libva.py). + +Currently supported handler modules: +| Module | Description | +| ---------- | ----------- | +| 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 | Handler tracks 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..4f76b13c --- /dev/null +++ b/tracetool/version.py @@ -0,0 +1,33 @@ +# +# 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 + +import os + +version = '2.5.1' +# get version from external if have +if os.path.isfile('..'+os.sep+'meson.build'): + with open('..'+os.sep+'meson.build', 'r') as file: + proj = '' + for line in file: + line = line.strip() + if line.startswith('project'): + proj = line + continue + if proj: + if line.endswith(')'): + break + proj += line + for field in proj.split(','): + if field.startswith('version'): + version = field.split(':')[1].strip().replace("'", '') + + 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()