From 912faca62007bb51f0a2e92a0d06fb589be002c0 Mon Sep 17 00:00:00 2001 From: Marco Cetica Date: Mon, 12 Jan 2026 15:58:42 +0100 Subject: [PATCH] Added benchmark for `String` type --- Makefile | 2 +- README.md | 8 +++-- benchmark/benchmark.c | 72 +++++++++++++++++++++++++++++++++---------- 3 files changed, 61 insertions(+), 21 deletions(-) diff --git a/Makefile b/Makefile index 21eb0ac..98a03b4 100644 --- a/Makefile +++ b/Makefile @@ -56,7 +56,7 @@ $(OBJ_DIR): mkdir -p $(OBJ_DIR) # Benchmark rules -$(BENCH_TARGET): $(BENCH_OBJ_DIR)/bench.o $(BENCH_OBJ_DIR)/vector.o $(BENCH_OBJ_DIR)/map.o +$(BENCH_TARGET): $(BENCH_OBJ_DIR)/bench.o $(BENCH_OBJ_DIR)/vector.o $(BENCH_OBJ_DIR)/map.o $(BENCH_OBJ_DIR)/string.o $(CC) $(BENCH_FLAGS) -o $@ $^ $(BENCH_OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(BENCH_OBJ_DIR) diff --git a/README.md b/README.md index 63e7eac..c8dbf17 100644 --- a/README.md +++ b/README.md @@ -232,12 +232,14 @@ $ ./test_bigint ``` ## Benchmark -Under the [`benchmark/`](/benchmark/) folder, you can find a simple benchmark program that stress the `Vector` and the `Map` data structures. You can run it by issuing the following command: +Under the [`benchmark/`](/benchmark/) folder, you can find a simple benchmark program that stress the `Vector`, `Map` and the `String` data structures. +You can run it by issuing the following command: ```sh $ ./benchmark_datum -Computing Vector average time...average time: 18 ms -Computing Map average time...average time: 31 ms +Computing Vector average time...average time: 19 ms +Computing Map average time...average time: 55 ms +Computing String average time...average time: 24 ms ``` diff --git a/benchmark/benchmark.c b/benchmark/benchmark.c index 913f4cd..57a1a1a 100644 --- a/benchmark/benchmark.c +++ b/benchmark/benchmark.c @@ -1,3 +1,5 @@ +#define _POSIX_C_SOURCE 200809L + #include #include #include @@ -6,6 +8,7 @@ #include "../src/vector.h" #include "../src/map.h" +#include "../src/string.h" typedef void (*test_fn_t)(size_t iterations); @@ -13,20 +16,15 @@ void test_vector(size_t iterations) { vector_t *vec = vector_new(16, sizeof(int)).value.vector; for (size_t idx = 0; idx < iterations; idx++) { - vector_push(vec, &idx); + vector_push(vec, &(int){idx}); } - volatile uint64_t sum = 0; // prevent the compiler from optimizing away the sum + volatile uint64_t sum = 0; for (size_t idx = 0; idx < iterations; idx++) { const int *val = (int*)vector_get(vec, idx).value.element; sum += *val; } - // Another trick to prevent compiler optimization - if (sum == 0xB00B5) { - printf("sum = %llu\n", (unsigned long long)sum); - } - vector_destroy(vec); } @@ -43,7 +41,7 @@ void test_map(size_t iterations) { map_add(map, key, (void*)value); } - volatile uint64_t sum = 0; // prevent the compiler from optimizing away the sum + volatile uint64_t sum = 0; for (size_t idx = 0; idx < iterations; idx++) { snprintf(key, sizeof(key), "key_%zu", idx); @@ -53,32 +51,68 @@ void test_map(size_t iterations) { // Cleanup values for (size_t idx = 0; idx < map->capacity; idx++) { - if (map->elements[idx].state == ENTRY_OCCUPIED) { - int *val = (int*)map->elements[idx].value; - free(val); - } + snprintf(key, sizeof(key), "key_%zu", idx); + + int *val = (int*)map_get(map, key).value.element; + free(val); + + map_remove(map, key); } map_destroy(map); } +void test_string(size_t iterations) { + volatile size_t total_len = 0; + + for (size_t idx = 0; idx < iterations; idx++) { + string_t *str1 = string_new("hello").value.string; + string_t *str2 = string_new(" World").value.string; + + string_result_t concat = string_concat(str1, str2); + string_result_t upper = string_to_upper(concat.value.string); + total_len += string_size(upper.value.string); + string_result_t needle = string_new("WORLD"); + string_result_t contains = string_contains(upper.value.string, needle.value.string); + + if (contains.value.idx >= 0) { + total_len += contains.value.idx; + } + + string_destroy(str1); + string_destroy(str2); + string_destroy(concat.value.string); + string_destroy(upper.value.string); + string_destroy(needle.value.string); + } +} + +static inline uint64_t now_ns(void) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + + return (uint64_t)ts.tv_sec * 1000000000ULL + ts.tv_nsec; +} + long long benchmark(test_fn_t fun, size_t iterations, size_t runs) { long long total = 0; + for (size_t idx = 0; idx < runs; idx++) { - clock_t start = clock(); + uint64_t start = now_ns(); fun(iterations); - clock_t end = clock(); + uint64_t end = now_ns(); - total += (long long)((end - start) * 1000 / CLOCKS_PER_SEC); + total += (end - start); } - return total / runs; + return (long long)(total / runs / 1000000); } int main(void) { // Do a warmup run test_vector(1000); test_map(1000); + test_string(1000); printf("Computing Vector average time..."); fflush(stdout); @@ -88,5 +122,9 @@ int main(void) { fflush(stdout); printf("average time: %lld ms\n", benchmark(test_map, 1e5, 30)); + printf("Computing String average time..."); + fflush(stdout); + printf("average time: %lld ms\n", benchmark(test_string, 1e5, 30)); + return 0; -} \ No newline at end of file +}