Index

lognestmonster / 824476c

A general-purpose single-header C logging library and parser for event-based logs. (Incomplete)

Latest Commit

{#}TimeHashSubjectAuthor#(+)(-)GPG?
19930 Mar 2020 15:46e573237Use matplotlib for graphs of performance test resultsJosh Stockin13012G

Blob @ lognestmonster / tests / performance.py

application/x-python4269 bytesdownload raw
1#!/usr/bin/env python3.7
2"""Compiles tests/header_only.c to test size, tests/header_unit*.c to test speed"""
3
4import sys
5import os
6import subprocess
7import re
8from statistics import median
9
10PROJECT_PATH = os.path.abspath(
11 os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")
12)
13BIN_PATH = os.path.join(PROJECT_PATH, "bin")
14INCLUDE_PATH = os.path.join(PROJECT_PATH, "src/c")
15HEADER_ONLY = os.path.join(PROJECT_PATH, "tests/header_only.c")
16HEADER_PERFORMANCE = os.path.join(PROJECT_PATH, "tests/header_memory.c")
17
18CC = "gcc"
19CFLAGS = ["-std=c11", "-pedantic", "-Wall", "-Wextra", "-Werror"]
20COUTFLAG = "-o"
21COPTIMIZATIONS = ["-O0", "-O1", "-O2", "-O3", "-Os"]
22CINCLUDES = ["-I", INCLUDE_PATH]
23
24TABLE_HEADER_1 = "Optimization Level"
25TABLE_HEADER_2 = "Header Binary Size (in bytes)"
26TABLE_HEADER_3 = "Memory Test Runtime (in µs)"
27
28RE_TRIAL_TIME = r"time elapsed \(us\): (\d*)"
29TRIAL_PASSES = 100
30
31
32def gcc_compile(out_file: str, in_files: list, optimization_level: str = "-O0"):
33 """Uses gcc subprocess to compile at a set optimization level"""
34 process_command = (
35 [CC]
36 + CFLAGS
37 + CINCLUDES
38 + [COUTFLAG, out_file]
39 + in_files
40 + [optimization_level]
41 )
42 process = subprocess.run(process_command, stdout=sys.stdout, stderr=sys.stderr)
43 if process.returncode:
44 print("[gcc_compile] error in compilation")
45 return 0
46 else:
47 print(f"[gcc_compile] finished compiling to {out_file}")
48 return 1
49
50
51def execute_file(executable: str):
52 """Executes the input file and returns the stdout"""
53 process = subprocess.run([executable], capture_output=True, text=True)
54 return process.stdout
55
56
57def get_size(file_name: str):
58 """Uses os.stat to get the file size in bytes of a specified file"""
59 return os.stat(file_name).st_size
60
61
62if __name__ == "__main__":
63 try:
64 os.mkdir(BIN_PATH)
65 except FileExistsError:
66 pass
67 else:
68 print("[main] created bin/")
69 print("[main] compiling...")
70 for optimization in COPTIMIZATIONS:
71 header_only_out = os.path.join(BIN_PATH, f"c-header-only{optimization}")
72 if not gcc_compile(header_only_out, [HEADER_ONLY], optimization):
73 sys.exit()
74 header_unit_out = os.path.join(BIN_PATH, f"c-performance{optimization}")
75 if not gcc_compile(header_unit_out, [HEADER_PERFORMANCE], optimization):
76 sys.exit()
77 print("[main] getting filesize data of header_only binaries")
78 EXECUTABLE_SIZES = {}
79 for optimization in COPTIMIZATIONS:
80 header_only_out = os.path.join(BIN_PATH, f"c-header-only{optimization}")
81 EXECUTABLE_SIZES[optimization] = get_size(header_only_out)
82 print("[main] beginning time trials")
83 EXECUTABLE_RUNTIMES = {}
84 import matplotlib.pyplot as plt
85 plt.xlabel("trial")
86 plt.ylabel("time (µs)")
87 for optimization in COPTIMIZATIONS:
88 print(f"[main/trials] running trial on {optimization}")
89 header_unit_out = os.path.join(BIN_PATH, f"c-performance{optimization}")
90 trial_runtimes = []
91 for trial_num in range(TRIAL_PASSES):
92 trial_output = execute_file(header_unit_out)
93 trial_time = re.search(RE_TRIAL_TIME, trial_output).group(1)
94 trial_runtimes.append(int(trial_time))
95 plt.plot(trial_runtimes)
96 trial_runtimes.sort()
97 trial_median = int(median(trial_runtimes))
98 trial_mid = int(TRIAL_PASSES/2)
99 trial_iqr = int(median(trial_runtimes[trial_mid:TRIAL_PASSES]) - median(trial_runtimes[0:trial_mid]))
100 trial_moe = int(trial_iqr/2)
101 EXECUTABLE_RUNTIMES[optimization] = f"{trial_median} ± {trial_moe}"
102 plt.legend(COPTIMIZATIONS)
103 print("[main] finished trials:")
104 print(f"{TABLE_HEADER_1} | {TABLE_HEADER_2} | {TABLE_HEADER_3}")
105 print(
106 f"{len(TABLE_HEADER_1)*'-'} | {len(TABLE_HEADER_2)*'-'} | {len(TABLE_HEADER_3)*'-'}"
107 )
108 for optimization in COPTIMIZATIONS:
109 executable_size = EXECUTABLE_SIZES[optimization]
110 executable_runtime = EXECUTABLE_RUNTIMES[optimization]
111 print(
112 f"{optimization.ljust(len(TABLE_HEADER_1))} | "
113 + f"{str(executable_size).ljust(len(TABLE_HEADER_2))} | {executable_runtime}"
114 )
115 plt.show()
116