Created
April 19, 2022 14:15
-
-
Save nh2/19e92530b51338959615af19d9759c5b to your computer and use it in GitHub Desktop.
Process `ghc -v` output, summarising where time is spent.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ./ghc-performance-categorizer.py ghci-v-output-1.txt --sort-by time | |
TASK time ms mem MB | |
------------------------------------------------ | |
systool:cpp 4 2 | |
systool:merge-objects 11 3 | |
Simplify 38 68 | |
ByteCodeGen 70 164 | |
initializing 72 119 | |
systool:as 175 68 | |
Chasing 705 1453 | |
Parser 775 1964 | |
systool:linker 812 357 | |
CoreTidy 1149 1405 | |
systool:cc 1489 58 | |
CorePrep 1821 2203 | |
Simplifier 8040 11801 | |
Renamer/typechecker 20184 26724 | |
CodeGen 43917 81220 | |
Desugar 58124 117565 | |
------------------------------------------------ | |
TOTAL 137387 245175 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/env python3 | |
import argparse | |
import fileinput | |
import re | |
from collections import defaultdict | |
from operator import itemgetter | |
def main(): | |
parser = argparse.ArgumentParser(description='Process `ghc -v` output, summarising where time is spent.') | |
parser.add_argument('files', metavar='FILE', nargs='*', help='files to read, if empty, stdin is used') | |
parser.add_argument('--sort-by', dest='sort_by', choices=['time', 'memory'], help='Sort table by this column') | |
args = parser.parse_args() | |
# Example lines: | |
# !!! ByteCodeGen [Ghci1]: finished in 0.02 milliseconds, allocated 0.037 megabytes | |
# !!! Desugar [Test.MallocInfo]: finished in 1.46 milliseconds, allocated 3.290 megabytes | |
# !!! Simplify [expr]: finished in 0.72 milliseconds, allocated 2.717 megabytes | |
# !!! systool:as: finished in 0.37 milliseconds, allocated 0.219 megabytes | |
r = re.compile(r'!!! (?P<task>\S+).* finished in (?P<time_milliseconds>\S+) milliseconds, allocated (?P<memory_megabytes>\S+) megabytes') | |
times = defaultdict(float) | |
memories = defaultdict(float) | |
# If you would call fileinput.input() without files it would try to process all arguments. | |
# We pass '-' as only file when argparse got no files which will cause fileinput to read from stdin | |
# From: https://gist.github.com/martinth/ed991fb8cdcac3dfadf7 | |
for line in fileinput.input(files=args.files if len(args.files) > 0 else ('-', )): | |
l = line.strip('\n') | |
res = r.match(l) | |
if res is not None: | |
d = res.groupdict() | |
task = d['task'].rstrip(':') | |
time_milliseconds = float(d['time_milliseconds']) | |
memory_megabytes = float(d['memory_megabytes']) | |
times[task] += time_milliseconds | |
memories[task] += memory_megabytes | |
total_time = sum([t for _, t in times.items()]) | |
total_mem = sum([t for _, t in memories.items()]) | |
tasks = times.keys() | |
if args.sort_by == 'time': | |
tasks = sorted(times.keys(), key=lambda t: times[t]) | |
elif args.sort_by == 'memory': | |
tasks = sorted(times.keys(), key=lambda t: memories[t]) | |
def format_line(task: str, time_milliseconds: float, memory_megabytes: float): | |
time = f"{time_milliseconds:4.0f}" | |
mem = f"{memory_megabytes:4.0f}" | |
return f"{task.ljust(30)} {time.rjust(8)} {mem.rjust(8)}" | |
print("TASK time ms mem MB") | |
print("------------------------------------------------") | |
for task in tasks: | |
print(format_line(task, times[task], memories[task])) | |
print("------------------------------------------------") | |
print(format_line("TOTAL", total_time, total_mem)) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment