| #!/usr/bin/env python2.7 |
| # Copyright (C) Microsoft Corporation. All rights reserved. |
| # This file is distributed under the University of Illinois Open Source License. See LICENSE.TXT for details. |
| |
| """Analyses the ETW dump file fors dxcompiler output as generated by hcttrace.""" |
| |
| import argparse |
| import datetime |
| import xml.etree.ElementTree as ET |
| |
| # Task values. |
| DXCompilerInitialization = 1; |
| DXCompilerShutdown = 2; |
| DXCompilerCreateInstance = 3; |
| DXCompilerIntelliSenseParse = 4; |
| DXCompilerCompile = 5; |
| DXCompilerPreprocess = 6; |
| DXCompilerDisassemble = 7; |
| |
| # Opcode values |
| OpcodeStart = 1; |
| OpcodeStop = 2; |
| |
| # Namespace dictionary. |
| ns = {'e': 'http://schemas.microsoft.com/win/2004/08/events/event'} |
| |
| def write_basic_info(node): |
| '''Writes computer information''' |
| print("Basic information:") |
| print("CPU Speed: %s" % node.find("e:Data[@Name='CPUSpeed']", ns). text) |
| print("Processor count: %s" % node.find("e:Data[@Name='NumberOfProcessors']", ns). text) |
| print("Events lost: %s" % node.find("e:Data[@Name='EventsLost']", ns). text) |
| print("Pointer size: %s" % node.find("e:Data[@Name='PointerSize']", ns). text) |
| |
| |
| def write_compile_times(root): |
| '''Prints out compilation times.''' |
| compilations = {} |
| for e in root: |
| system_node = e.find("e:System", ns) |
| if system_node is None: |
| continue |
| channel = system_node.find("e:Channel", ns) |
| if channel is None or channel.text <> "Microsoft-Windows-DXCompiler-API/Analytic": |
| continue |
| task = int(system_node.find("e:Task", ns).text) |
| opcode = int(system_node.find("e:Opcode", ns).text) |
| pid = int(system_node.find("e:Execution", ns).attrib['ProcessID']) |
| tid = int(system_node.find("e:Execution", ns).attrib['ThreadID']) |
| time_created = system_node.find("e:TimeCreated", ns).attrib['SystemTime'] |
| # Something like: |
| # 2016-02-02T00:10:51.619434100Z |
| # Unfortunately datetime doesn't have enough precision, so we make do with this: |
| # 2016-02-02T00:10:39.630081 |
| if task == DXCompilerCompile: |
| time_created = time_created[:26] |
| cid = '{0},{1}'.format(pid, tid) |
| parsed_time_created = datetime.datetime.strptime(time_created, "%Y-%m-%dT%H:%M:%S.%f") |
| if opcode == OpcodeStart: |
| #print "Start at %s" % time_created |
| compilations[cid] = parsed_time_created |
| else: |
| old_parsed_time_created = compilations[cid] |
| print "Compilation took %s" % str(parsed_time_created - old_parsed_time_created) |
| |
| |
| def main(): |
| parser = argparse.ArgumentParser(description=__doc__) |
| parser.add_argument('-v', '--verbose', action='store_true', |
| help='Show verbose output') |
| parser.add_argument('dumpfiles', nargs='+') |
| args = parser.parse_args() |
| |
| for dumpfile in args.dumpfiles: |
| if args.verbose: |
| print >>sys.stderr, 'Scanning for dxcompiler events in dumpfile: %s' % (dumpfile,) |
| tree = ET.parse(dumpfile) |
| root = tree.getroot() |
| write_basic_info(root.find('e:Event/e:EventData', ns)) |
| write_compile_times(root) |
| # Other interesting things: |
| # errors, working set, additional stats |
| |
| if __name__ == '__main__': |
| main() |