aboutsummaryrefslogtreecommitdiff
path: root/main.c
blob: 5f40b38914789c954c56d8d5087e66e9720c437f (plain) (blame)
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;
}