1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <time.h>
#include "include/json.h"
#include "include/memory.h"
#include "include/types.h"
#include "include/vec.h"
// Load entire file into memory
byte *load_file(const char *filename, size *file_size) {
FILE *file = fopen(filename, "rb");
if (!file) {
fprintf(stderr, "Error: Could not open file '%s'\n", filename);
return NULL;
}
// Get file size
fseek(file, 0, SEEK_END);
*file_size = ftell(file);
fseek(file, 0, SEEK_SET);
// Allocate buffer and read file
byte *buffer = malloc(*file_size + 1);
if (!buffer) {
fprintf(stderr, "Error: Could not allocate memory for file\n");
fclose(file);
return NULL;
}
size bytes_read = fread(buffer, 1, *file_size, file);
if (bytes_read != *file_size) {
fprintf(stderr, "Error: Could not read entire file\n");
free(buffer);
fclose(file);
return NULL;
}
buffer[*file_size] = '\0'; // Null terminate
fclose(file);
return buffer;
}
// Get high resolution time in nanoseconds
double get_time_ns(void) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * 1000000000.0 + ts.tv_nsec;
}
void run_benchmark(const char *filename, i32 iterations) {
printf("Loading file: %s\n", filename);
size file_size;
byte *content = load_file(filename, &file_size);
if (!content) return;
printf("File size: %zu bytes\n", file_size);
printf("Running %d iterations...\n\n", iterations);
// Statistics tracking
f32 timings[iterations] = {};
f32 timing_avg = 0.0;
Arena arena = Arena_new(8e9);
printf("Benchmarking...\n");
for (i32 i = 0; i < iterations; i++) {
Arena_reset(&arena);
size used = Arena_get_used(arena);
double start_time = get_time_ns();
JSON result = JSON_parse(&arena, content);
double end_time = get_time_ns();
timings[i] = end_time - start_time;
timing_avg += timings[i];
size new_used = Arena_get_used(arena);
size allocated = new_used - used;
printf("Iteration %d: %td MB allocated\n", i + 1,
allocated / 1024 / 1024);
if ((i + 1) % 100 == 0) {
printf("Completed %d/%d iterations\n", i + 1, iterations);
}
}
// Calculate statistics
timing_avg /= iterations;
f32 timing_var = 0.0;
for (i32 i = 0; i < iterations; i++) {
timing_var += (timings[i] - timing_avg) * (timings[i] - timing_avg);
}
timing_var /= iterations;
f32 timing_stddev = sqrt(timing_var);
double avg_throughput_mb_s =
(file_size / (1024.0 * 1024.0)) / (timing_avg / 1000000000.0);
printf("\n=== Benchmark Results ===\n");
printf("%3.f ms ± %3.f ms per loop (mean ± std. dev. of %d runs, 1 loop "
"each)\n",
timing_avg / 1000000, timing_stddev / 1000000, iterations);
printf("Throughput: %.2f MB/s\n", avg_throughput_mb_s);
}
i32 main(i32 argc, char *argv[]) {
const char *filename = "out.json";
i32 iterations = 1;
// Parse command line arguments
if (argc >= 2) {
filename = argv[1];
}
if (argc >= 3) {
iterations = atoi(argv[2]);
if (iterations <= 0) {
fprintf(stderr, "Error: Invalid number of iterations\n");
return 1;
}
}
printf("JSON Parser Benchmark\n");
printf("====================\n");
run_benchmark(filename, iterations);
return 0;
}
|