| #!/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( |
| "Scanning for dxcompiler events in dumpfile: %s" % (dumpfile,), |
| file=sys.stderr, |
| ) |
| 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() |