From 0538a6d11a703a3aa23fb484c21986aa29c6b15b Mon Sep 17 00:00:00 2001
From: chylex <contact@chylex.com>
Date: Thu, 10 Feb 2022 18:23:49 +0100
Subject: [PATCH] Add benchmark timing to ASM projects

---
 2015/01/CMakeLists.txt |  2 +-
 2015/01/main.asm       |  6 ++--
 2015/utils/benchmark.h | 67 ++++++++++++++++++++++++++++++++++++++++++
 2015/utils/main.c      | 21 +++++++++++--
 4 files changed, 89 insertions(+), 7 deletions(-)
 create mode 100644 2015/utils/benchmark.h

diff --git a/2015/01/CMakeLists.txt b/2015/01/CMakeLists.txt
index c1732d1..027e16f 100644
--- a/2015/01/CMakeLists.txt
+++ b/2015/01/CMakeLists.txt
@@ -6,4 +6,4 @@ enable_language(ASM_NASM)
 set(CMAKE_NASM_LINK_EXECUTABLE "ld <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
 set(CAN_USE_ASSEMBLER TRUE)
 
-add_executable(${PROJECT_NAME} main.asm ../utils/main.c ../utils/file.h)
+add_executable(${PROJECT_NAME} main.asm ../utils/main.c ../utils/file.h ../utils/benchmark.h)
diff --git a/2015/01/main.asm b/2015/01/main.asm
index ba04711..7e7d282 100644
--- a/2015/01/main.asm
+++ b/2015/01/main.asm
@@ -1,5 +1,5 @@
 bits 32
-extern _printf
+extern _print
 
 section .data
 
@@ -51,11 +51,11 @@ _entryPoint:
 .end:
   push eax
   push dword print_final_floor
-  call _printf
+  call _print
 
   push edi
   push dword print_first_entered_basement
-  call _printf
+  call _print
 
   pop edi
   pop ebx
diff --git a/2015/utils/benchmark.h b/2015/utils/benchmark.h
new file mode 100644
index 0000000..8f92a01
--- /dev/null
+++ b/2015/utils/benchmark.h
@@ -0,0 +1,67 @@
+#ifndef ADVENTOFCODE_BENCHMARK_H
+#define ADVENTOFCODE_BENCHMARK_H
+
+#include "stdio.h"
+
+#if WIN32
+#include "windows.h"
+#else
+#include "time.h"
+#endif
+
+static int sortDoubles(const void* a, const void* b) {
+	double x = *(double*) a;
+	double y = *(double*) b;
+	
+	if (x > y) {
+		return 1;
+	}
+	else if (x < y) {
+		return -1;
+	}
+	else {
+		return 0;
+	}
+}
+
+static void formatMillis(const char* text, const double ms) {
+	if (ms >= 0.1) {
+		printf("\n%s: %.2f ms", text, ms);
+	}
+	else {
+		printf("\n%s: %.2f us", text, ms * 1000.0);
+	}
+}
+
+typedef void (*entryPointCallback)(char* input);
+
+#define BENCHMARK_RUNS 50001
+
+void runBenchmark(const entryPointCallback ep, char* input) {
+	double benchmarkResults[BENCHMARK_RUNS];
+	for (int run = 0; run < BENCHMARK_RUNS; run++) {
+		#if WIN32
+		LARGE_INTEGER startTime, endTime, frequency;
+		QueryPerformanceFrequency(&frequency);
+		QueryPerformanceCounter(&startTime);
+		ep(input);
+		QueryPerformanceCounter(&endTime);
+		benchmarkResults[run] = (double) (endTime.QuadPart - startTime.QuadPart) * 1000.0 / (double) frequency.QuadPart;
+		#else
+		clock_t startTime = clock();
+		ep(input);
+		clock_t endTime = clock();
+		benchmarkResults[run] = ((endTime - startTime) * 1000.0) / CLOCKS_PER_SEC;
+		#endif
+	}
+	
+	qsort(benchmarkResults, BENCHMARK_RUNS, sizeof(double), sortDoubles);
+	
+	formatMillis("Median elapsed time", benchmarkResults[BENCHMARK_RUNS / 2]);
+	formatMillis("Q1 elapsed time", benchmarkResults[(BENCHMARK_RUNS * 25) / 100]);
+	formatMillis("Q3 elapsed time", benchmarkResults[(BENCHMARK_RUNS * 75) / 100]);
+}
+
+#undef BENCHMARK_RUNS
+
+#endif //ADVENTOFCODE_BENCHMARK_H
diff --git a/2015/utils/main.c b/2015/utils/main.c
index 0e1ea8d..dd69ba5 100644
--- a/2015/utils/main.c
+++ b/2015/utils/main.c
@@ -1,15 +1,30 @@
+#include "stdarg.h"
 #include "file.h"
+#include "benchmark.h"
 
-void entryPoint(char* input);
+void entryPoint(char *input);
 
-int main() {
-	char* input = readFile("input/1.txt");
+int enableOutput = 1;
+
+extern void print(const char *format, ...) {
+	if (enableOutput) {
+		va_list args;
+		va_start(args, format);
+		vprintf(format, args);
+		va_end(args);
+	}
+}
+
+int main(void) {
+	char *input = readFile("input/1.txt");
 	
 	if (input == NULL) {
 		return 1;
 	}
 	else {
 		entryPoint(input);
+		enableOutput = 0;
+		runBenchmark(entryPoint, input);
 		return 0;
 	}
 }