Index

lognestmonster / bd6bf7a

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

Latest Commit

{#}TimeHashSubjectAuthor#(+)(-)GPG?
19524 Mar 2020 23:323ce6207Add -std=c11 specificity to gcc callsJosh Stockin111G

Blob @ lognestmonster / tests / performance.py

application/x-python3469 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*)"
29
30
31def gcc_compile(out_file: str, in_files: list, optimization_level: str = "-O0"):
32 """Uses gcc subprocess to compile at a set optimization level"""
33 process_command = (
34 [CC]
35 + CFLAGS
36 + CINCLUDES
37 + [COUTFLAG, out_file]
38 + in_files
39 + [optimization_level]
40 )
41 process = subprocess.run(process_command, stdout=sys.stdout, stderr=sys.stderr)
42 if process.returncode:
43 print("gcc_compile: error in compilation")
44 return 0
45 return 1
46
47
48def execute_file(executable: str):
49 """Executes the input file and returns the stdout"""
50 process = subprocess.run([executable], capture_output=True, text=True)
51 return process.stdout
52
53
54def get_size(file_name: str):
55 """Uses os.stat to get the file size in bytes of a specified file"""
56 return os.stat(file_name).st_size
57
58
59if __name__ == "__main__":
60 try:
61 os.mkdir(BIN_PATH)
62 except FileExistsError:
63 pass
64 print("running compiler")
65 for optimization in COPTIMIZATIONS:
66 header_only_out = os.path.join(BIN_PATH, f"header_only{optimization}")
67 if not gcc_compile(header_only_out, [HEADER_ONLY], optimization):
68 sys.exit()
69 header_unit_out = os.path.join(BIN_PATH, f"c{optimization}")
70 if not gcc_compile(header_unit_out, [HEADER_PERFORMANCE], optimization):
71 sys.exit()
72 print("getting results")
73 EXECUTABLE_SIZES = {}
74 EXECUTABLE_RUNTIMES = {}
75 for optimization in COPTIMIZATIONS:
76 header_only_out = os.path.join(BIN_PATH, f"header_only{optimization}")
77 header_unit_out = os.path.join(BIN_PATH, f"c{optimization}")
78 EXECUTABLE_SIZES[optimization] = get_size(header_only_out)
79 trial_runtimes = []
80 for trial_num in range(100):
81 trial_output = execute_file(header_unit_out)
82 trial_time = re.search(RE_TRIAL_TIME, trial_output).group(1)
83 trial_runtimes.append(int(trial_time))
84 EXECUTABLE_RUNTIMES[optimization] = int(median(trial_runtimes))
85 print("done. printing...")
86 print()
87 print(f"{TABLE_HEADER_1} | {TABLE_HEADER_2} | {TABLE_HEADER_3}")
88 print(
89 f"{len(TABLE_HEADER_1)*'-'} | {len(TABLE_HEADER_2)*'-'} | {len(TABLE_HEADER_3)*'-'}"
90 )
91 for optimization in COPTIMIZATIONS:
92 executable_size = EXECUTABLE_SIZES[optimization]
93 executable_runtime = EXECUTABLE_RUNTIMES[optimization]
94 print(
95 f"{optimization.ljust(len(TABLE_HEADER_1))} | "
96 + f"{str(executable_size).ljust(len(TABLE_HEADER_2))} | {executable_runtime}"
97 )
98