aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--main.c147
-rw-r--r--memory.c11
-rw-r--r--memory.h1
4 files changed, 143 insertions, 18 deletions
diff --git a/README.md b/README.md
index 7083968..d9cdf05 100644
--- a/README.md
+++ b/README.md
@@ -6,10 +6,10 @@
- Fix tests in release
- Benchmark 100MB file
- json.loads: 526 ms ± 77 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
+ - self: 348 ms (mean of 7 runs, 1 loop each). 2079 MB/s
- More modern include pragma (once)
- File structure
- Static functions for private?
-- JSON: tagged union for memory, remove pointer and use bitflag
- `valgrind --leak-check=full ./your_program`
- assert with error msg?
- negative numbers
diff --git a/main.c b/main.c
index 3f63be0..19e8c20 100644
--- a/main.c
+++ b/main.c
@@ -1,17 +1,138 @@
-/*
-Inspirations:
-- https://nullprogram.com/
-*/
-#include <assert.h>
-#include <stddef.h>
-#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <time.h>
+#include "json.h"
#include "memory.h"
-#include "string.h"
-#include "vec.h"
+#include "types.h"
-typedef struct {
- int age;
-} User;
+// 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;
+ }
-int main() { return 0; }
+ // 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
+ double total_time = 0.0;
+ double min_time = 1e9;
+ double max_time = 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();
+
+ double elapsed = end_time - start_time;
+ total_time += elapsed;
+
+ if (elapsed < min_time) min_time = elapsed;
+ if (elapsed > max_time) max_time = elapsed;
+
+ 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
+ double avg_time = total_time / iterations;
+ double avg_time_ms = avg_time / 1000000.0;
+ double min_time_ms = min_time / 1000000.0;
+ double max_time_ms = max_time / 1000000.0;
+
+ // Calculate throughput
+ double avg_throughput_mb_s =
+ (file_size / (1024.0 * 1024.0)) / (avg_time / 1000000000.0);
+
+ printf("\n=== Benchmark Results ===\n");
+ printf("Iterations: %d\n", iterations);
+ printf("File size: %zu bytes (%.2f MB)\n", file_size,
+ file_size / (1024.0 * 1024.0));
+ printf("\nTiming (milliseconds):\n");
+ printf(" Average: %.3f ms\n", avg_time_ms);
+ printf(" Minimum: %.3f ms\n", min_time_ms);
+ printf(" Maximum: %.3f ms\n", max_time_ms);
+ printf(" Range: %.3f ms\n", max_time_ms - min_time_ms);
+ printf("\nThroughput:\n");
+ printf(" Average: %.2f MB/s\n", avg_throughput_mb_s);
+ printf(" Parse rate: %.0f parses/second\n", 1000.0 / avg_time_ms);
+}
+
+i32 main(i32 argc, char *argv[]) {
+ const char *filename = "out.json";
+ i32 iterations = 7;
+
+ // 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;
+}
diff --git a/memory.c b/memory.c
index 73d6345..f60f044 100644
--- a/memory.c
+++ b/memory.c
@@ -18,10 +18,13 @@ Arena Arena_new(size cap) {
// alloc_align(3)))
void *alloc(Arena *a, size count, size tsize, size align) {
size padding = -(uptr)a->beg & (align - 1);
- assert(count < (a->end - a->beg - padding) / tsize);
- void *cursor = a->beg + padding;
- a->beg += padding + count * tsize;
- return memset(cursor, 0, count * tsize);
+ byte *beg = a->beg + padding;
+ size alloc_size = count * tsize;
+ assert(beg + alloc_size < a->end);
+ a->beg = beg + alloc_size;
+ return memset(beg, 0, count * tsize);
}
+void Arena_reset(Arena *a) { a->beg = a->end - a->cap; }
+
size Arena_get_used(Arena a) { return a.cap - (a.end - a.beg); }
diff --git a/memory.h b/memory.h
index db48773..1a33452 100644
--- a/memory.h
+++ b/memory.h
@@ -13,4 +13,5 @@ Arena Arena_new(size cap);
#define new(a, T, n) (T *)alloc(a, n, sizeof(T), _Alignof(T))
void *alloc(Arena *a, size count, size tsize, size align);
size Arena_get_used(Arena a);
+void Arena_reset(Arena *a);
#endif