blob: 0dc2d18430d2095b42e2c9cdc36e489f3dbbe69e [file] [log] [blame] [edit]
#!/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()