Index

lognestmonster / 50316cb

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

Latest Commit

{#}TimeHashSubjectAuthor#(+)(-)GPG?
17901 Feb 2020 21:541a7420fModify testing chain for convenienceJosh Stockin1980G

Blob @ lognestmonster / tests / performance.py

application/x-python3522 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_MAIN = os.path.join(PROJECT_PATH, "tests/header_unit.c")
17HEADER_MAIN_2 = os.path.join(PROJECT_PATH, "tests/header_unit_2.c")
18
19CC = "gcc"
20CFLAGS = ["-pedantic", "-Wall", "-Wextra", "-Werror"]
21COUTFLAG = "-o"
22COPTIMIZATIONS = ["-O0", "-O1", "-O2", "-O3", "-Os"]
23CINCLUDES = ["-I", INCLUDE_PATH]
24
25TABLE_HEADER_1 = "Optimization Level"
26TABLE_HEADER_2 = "Header Binary Size (in bytes)"
27TABLE_HEADER_3 = "Unit Test Runtime (in µs)"
28
29RE_TRIAL_TIME = r"time elapsed \(us\): (\d*)"
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 return 1
47
48
49def execute_file(executable: str):
50 """Executes the input file and returns the stdout"""
51 process = subprocess.run([executable], capture_output=True, text=True)
52 return process.stdout
53
54
55def get_size(file_name: str):
56 """Uses os.stat to get the file size in bytes of a specified file"""
57 return os.stat(file_name).st_size
58
59
60if __name__ == "__main__":
61 try:
62 os.mkdir(BIN_PATH)
63 except FileExistsError:
64 pass
65 print("running compiler")
66 for optimization in COPTIMIZATIONS:
67 header_only_out = os.path.join(BIN_PATH, f"header_only{optimization}")
68 if not gcc_compile(header_only_out, [HEADER_ONLY], optimization):
69 sys.exit()
70 header_unit_out = os.path.join(BIN_PATH, f"c{optimization}")
71 if not gcc_compile(header_unit_out, [HEADER_MAIN, HEADER_MAIN_2], optimization):
72 sys.exit()
73 print("getting results")
74 EXECUTABLE_SIZES = {}
75 EXECUTABLE_RUNTIMES = {}
76 for optimization in COPTIMIZATIONS:
77 header_only_out = os.path.join(BIN_PATH, f"header_only{optimization}")
78 header_unit_out = os.path.join(BIN_PATH, f"c{optimization}")
79 EXECUTABLE_SIZES[optimization] = get_size(header_only_out)
80 trial_runtimes = []
81 for trial_num in range(200):
82 trial_output = execute_file(header_unit_out)
83 trial_time = re.search(RE_TRIAL_TIME, trial_output).group(1)
84 trial_runtimes.append(int(trial_time))
85 EXECUTABLE_RUNTIMES[optimization] = int(median(trial_runtimes))
86 print("done. printing...")
87 print()
88 print(f"{TABLE_HEADER_1} | {TABLE_HEADER_2} | {TABLE_HEADER_3}")
89 print(
90 f"{len(TABLE_HEADER_1)*'-'} | {len(TABLE_HEADER_2)*'-'} | {len(TABLE_HEADER_3)*'-'}"
91 )
92 for optimization in COPTIMIZATIONS:
93 executable_size = EXECUTABLE_SIZES[optimization]
94 executable_runtime = EXECUTABLE_RUNTIMES[optimization]
95 print(
96 f"{optimization.ljust(len(TABLE_HEADER_1))} | "
97 + f"{str(executable_size).ljust(len(TABLE_HEADER_2))} | {executable_runtime}"
98 )
99