Added benchmark program
This commit is contained in:
4
.github/workflows/clang-build.yml
vendored
4
.github/workflows/clang-build.yml
vendored
@@ -17,3 +17,7 @@ jobs:
|
|||||||
- name: Run unit tests
|
- name: Run unit tests
|
||||||
run: |
|
run: |
|
||||||
./test_vector && ./test_map && ./test_bigint
|
./test_vector && ./test_map && ./test_bigint
|
||||||
|
|
||||||
|
- name: Run benchmarks
|
||||||
|
run: |
|
||||||
|
./benchmark_datum
|
||||||
4
.github/workflows/gcc-build.yml
vendored
4
.github/workflows/gcc-build.yml
vendored
@@ -14,3 +14,7 @@ jobs:
|
|||||||
- name: Run unit tests
|
- name: Run unit tests
|
||||||
run: |
|
run: |
|
||||||
./test_vector && ./test_map && ./test_bigint
|
./test_vector && ./test_map && ./test_bigint
|
||||||
|
|
||||||
|
- name: Run benchmarks
|
||||||
|
run: |
|
||||||
|
./benchmark_datum
|
||||||
25
Makefile
25
Makefile
@@ -3,21 +3,29 @@ CFLAGS = -Wall -Wextra -Werror -pedantic-errors -fstack-protector-strong \
|
|||||||
-fsanitize=address -fsanitize=undefined -fstack-clash-protection \
|
-fsanitize=address -fsanitize=undefined -fstack-clash-protection \
|
||||||
-Wwrite-strings -g -std=c99
|
-Wwrite-strings -g -std=c99
|
||||||
|
|
||||||
|
BENCH_FLAGS = -Wall -Wextra -Werror -O3
|
||||||
|
|
||||||
SRC_DIR = src
|
SRC_DIR = src
|
||||||
|
BENCH_SRC = benchmark
|
||||||
|
|
||||||
OBJ_DIR = obj
|
OBJ_DIR = obj
|
||||||
|
BENCH_OBJ_DIR = bench_obj
|
||||||
|
|
||||||
TESTS_SRC = tests
|
TESTS_SRC = tests
|
||||||
|
|
||||||
TARGET = usage
|
TARGET = usage
|
||||||
TEST_V_TARGET = test_vector
|
TEST_V_TARGET = test_vector
|
||||||
TEST_M_TARGET = test_map
|
TEST_M_TARGET = test_map
|
||||||
TEST_B_TARGET = test_bigint
|
TEST_B_TARGET = test_bigint
|
||||||
|
BENCH_TARGET = benchmark_datum
|
||||||
|
|
||||||
LIB_OBJS = $(OBJ_DIR)/vector.o $(OBJ_DIR)/map.o $(OBJ_DIR)/bigint.o
|
LIB_OBJS = $(OBJ_DIR)/vector.o $(OBJ_DIR)/map.o $(OBJ_DIR)/bigint.o
|
||||||
PROG_OBJS = $(OBJ_DIR)/usage.o
|
PROG_OBJS = $(OBJ_DIR)/usage.o
|
||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
|
|
||||||
all: $(TARGET) $(TEST_V_TARGET) $(TEST_M_TARGET) $(TEST_B_TARGET)
|
all: $(TARGET) $(TEST_V_TARGET) $(TEST_M_TARGET) $(TEST_B_TARGET) $(BENCH_TARGET)
|
||||||
|
bench: $(BENCH_TARGET)
|
||||||
|
|
||||||
$(TARGET): $(PROG_OBJS) $(LIB_OBJS)
|
$(TARGET): $(PROG_OBJS) $(LIB_OBJS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^
|
$(CC) $(CFLAGS) -o $@ $^
|
||||||
@@ -43,5 +51,18 @@ $(OBJ_DIR)/%.o: $(TESTS_SRC)/%.c | $(OBJ_DIR)
|
|||||||
$(OBJ_DIR):
|
$(OBJ_DIR):
|
||||||
mkdir -p $(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
|
||||||
|
$(CC) $(BENCH_FLAGS) -o $@ $^
|
||||||
|
|
||||||
|
$(BENCH_OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(BENCH_OBJ_DIR)
|
||||||
|
$(CC) $(BENCH_FLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
$(BENCH_OBJ_DIR)/bench.o: $(BENCH_SRC)/benchmark.c | $(BENCH_OBJ_DIR)
|
||||||
|
$(CC) $(BENCH_FLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
$(BENCH_OBJ_DIR):
|
||||||
|
mkdir -p $(BENCH_OBJ_DIR)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(OBJ_DIR) $(TARGET) $(TEST_V_TARGET) $(TEST_M_TARGET) $(TEST_B_TARGET)
|
rm -rf $(OBJ_DIR) $(BENCH_OBJ_DIR) $(TARGET) $(TEST_V_TARGET) $(TEST_M_TARGET) $(TEST_B_TARGET) $(BENCH_TARGET)
|
||||||
|
|||||||
11
README.md
11
README.md
@@ -133,7 +133,7 @@ and a sample usage for every available method. To run it, first issue the follow
|
|||||||
$ make clean all
|
$ make clean all
|
||||||
```
|
```
|
||||||
|
|
||||||
This will compile the library as well as the `usage.c` file and the unit tests. After that, you can run it by typing `./usage`.
|
This will compile the library as well as the `usage.c` file, the unit tests and the benchmark. After that, you can run it by typing `./usage`.
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
For additional details about this library (internal design, memory
|
For additional details about this library (internal design, memory
|
||||||
@@ -149,6 +149,15 @@ $ ./test_map
|
|||||||
$ ./test_bigint
|
$ ./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:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ ./benchmark_datum
|
||||||
|
Computing Vector average time...average time: 18 ms
|
||||||
|
Computing Map average time...average time: 31 ms
|
||||||
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
This library is released under the GPLv3 license. You can find a copy of the license with this repository or by visiting
|
This library is released under the GPLv3 license. You can find a copy of the license with this repository or by visiting
|
||||||
[the following link](https://choosealicense.com/licenses/gpl-3.0/).
|
[the following link](https://choosealicense.com/licenses/gpl-3.0/).
|
||||||
|
|||||||
92
benchmark/benchmark.c
Normal file
92
benchmark/benchmark.c
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "../src/vector.h"
|
||||||
|
#include "../src/map.h"
|
||||||
|
|
||||||
|
typedef void (*test_fn_t)(size_t iterations);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
volatile uint64_t sum = 0; // prevent the compiler from optimizing away the sum
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_map(size_t iterations) {
|
||||||
|
map_t *map = map_new().value.map;
|
||||||
|
char key[64];
|
||||||
|
|
||||||
|
for (size_t idx = 0; idx < iterations; idx++) {
|
||||||
|
snprintf(key, sizeof(key), "key_%zu", idx);
|
||||||
|
|
||||||
|
int *value = malloc(sizeof(int));
|
||||||
|
*value = (int)idx;
|
||||||
|
|
||||||
|
map_add(map, key, (void*)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
volatile uint64_t sum = 0; // prevent the compiler from optimizing away the sum
|
||||||
|
for (size_t idx = 0; idx < iterations; idx++) {
|
||||||
|
snprintf(key, sizeof(key), "key_%zu", idx);
|
||||||
|
|
||||||
|
const int *val = (const int*)map_get(map, key).value.element;
|
||||||
|
sum += *val;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
map_destroy(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
fun(iterations);
|
||||||
|
clock_t end = clock();
|
||||||
|
|
||||||
|
total += (long long)((end - start) * 1000 / CLOCKS_PER_SEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
return total / runs;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
// Do a warmup run
|
||||||
|
test_vector(1000);
|
||||||
|
test_map(1000);
|
||||||
|
|
||||||
|
printf("Computing Vector average time...");
|
||||||
|
fflush(stdout);
|
||||||
|
printf("average time: %lld ms\n", benchmark(test_vector, 1e6, 30));
|
||||||
|
|
||||||
|
printf("Computing Map average time...");
|
||||||
|
fflush(stdout);
|
||||||
|
printf("average time: %lld ms\n", benchmark(test_map, 1e5, 30));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user