From 637685316d747c538d50b8e82968a2c110b37d84 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 9 Sep 2021 16:01:44 +0200 Subject: [PATCH] Add xxhash tests to CI. --- core/hash/xxhash/common.odin | 83 +----------------- core/time/perf.odin | 3 +- tests/core/Makefile | 5 +- tests/core/build.bat | 5 ++ tests/core/hash/test_core_hash.odin | 131 ++++++++++++++++++++++++++++ 5 files changed, 143 insertions(+), 84 deletions(-) create mode 100644 tests/core/hash/test_core_hash.odin diff --git a/core/hash/xxhash/common.odin b/core/hash/xxhash/common.odin index fc86ea54b..a8a502035 100644 --- a/core/hash/xxhash/common.odin +++ b/core/hash/xxhash/common.odin @@ -79,85 +79,4 @@ XXH64_read64 :: #force_inline proc(buf: []u8, alignment: Alignment) -> (res: u64 mem_copy(&b, raw_data(buf[:]), 8) return u64(b) } -} - - -/* - Benchmarks -*/ - -setup_xxhash :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { - assert(options != nil) - - options.input = make([]u8, options.bytes, allocator) - return nil if len(options.input) == options.bytes else .Allocation_Error -} - -teardown_xxhash :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { - assert(options != nil) - - delete(options.input) - return nil -} - -benchmark_xxhash32 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { - buf := options.input - - for _ in 0..=options.rounds { - _ = XXH32(buf) - } - options.count = options.rounds - options.processed = options.rounds * options.bytes - return nil -} - -benchmark_xxhash64 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { - buf := options.input - - for _ in 0..=options.rounds { - _ = XXH64(buf) - } - options.count = options.rounds - options.processed = options.rounds * options.bytes - return nil -} - -benchmark_print :: proc(name: string, options: ^time.Benchmark_Options) { - fmt.printf("\t[%v] %v rounds, %v bytes procesed in %v ns\n\t\t%5.3f rounds/s, %5.3f MiB/s\n", - name, - options.rounds, - options.processed, - time.duration_nanoseconds(options.duration), - options.rounds_per_second, - options.megabytes_per_second, - ) -} - -@test -benchmark_runner :: proc(t: ^testing.T) { - fmt.println("Starting benchmarks:") - - options := &time.Benchmark_Options{ - rounds = 1_000, - bytes = 100, - setup = setup_xxhash, - bench = benchmark_xxhash32, - teardown = teardown_xxhash, - } - err := time.benchmark(options, context.allocator) - benchmark_print("xxhash32 100 bytes", options) - - options.bytes = 1_000_000 - err = time.benchmark(options, context.allocator) - benchmark_print("xxhash32 1_000_000 bytes", options) - - options.bytes = 100 - options.bench = benchmark_xxhash64 - err = time.benchmark(options, context.allocator) - benchmark_print("xxhash64 100 bytes", options) - - options.bytes = 1_000_000 - err = time.benchmark(options, context.allocator) - benchmark_print("xxhash64 1_000_000 bytes", options) -} - +} \ No newline at end of file diff --git a/core/time/perf.odin b/core/time/perf.odin index fcc626d57..f8d2765bb 100644 --- a/core/time/perf.odin +++ b/core/time/perf.odin @@ -60,7 +60,8 @@ Benchmark_Options :: struct { count: int, processed: int, - output: []u8, + output: []u8, // Unused for hash benchmarks + hash: u128, /* Performance diff --git a/tests/core/Makefile b/tests/core/Makefile index 65af21204..5bcb924b1 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -1,7 +1,7 @@ ODIN=../../odin PYTHON=$(shell which python3) -all: download_test_assets image_test compress_test strings_test +all: download_test_assets image_test compress_test strings_test hash_test download_test_assets: $(PYTHON) download_assets.py @@ -14,3 +14,6 @@ compress_test: strings_test: $(ODIN) run strings/test_core_strings.odin + +hash_test: + $(ODIN) run hash/test_core_hash.odin -o:size -no-bounds-check \ No newline at end of file diff --git a/tests/core/build.bat b/tests/core/build.bat index d298bfc3e..d7f7de902 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -16,3 +16,8 @@ echo --- echo Running core:strings tests echo --- %PATH_TO_ODIN% run strings %COMMON% + +echo --- +echo Running core:hash tests +echo --- +%PATH_TO_ODIN% run hash %COMMON% -o:size \ No newline at end of file diff --git a/tests/core/hash/test_core_hash.odin b/tests/core/hash/test_core_hash.odin new file mode 100644 index 000000000..44c7ef044 --- /dev/null +++ b/tests/core/hash/test_core_hash.odin @@ -0,0 +1,131 @@ +package test_core_image + +import "core:hash/xxhash" +import "core:time" +import "core:testing" +import "core:fmt" + +TEST_count := 0 +TEST_fail := 0 + +when ODIN_TEST { + expect :: testing.expect + log :: testing.log +} else { + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + fmt.printf("[%v] ", loc) + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.println(" FAIL:", message) + return + } + fmt.println(" PASS") + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] ", loc) + fmt.printf("log: %v\n", v) + } +} + +main :: proc() { + t := testing.T{} + test_benchmark_runner(&t) + fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) +} + +/* + Benchmarks +*/ + +setup_xxhash :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { + assert(options != nil) + + options.input = make([]u8, options.bytes, allocator) + return nil if len(options.input) == options.bytes else .Allocation_Error +} + +teardown_xxhash :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { + assert(options != nil) + + delete(options.input) + return nil +} + +benchmark_xxhash32 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { + buf := options.input + + h: u32 + for _ in 0..=options.rounds { + h = xxhash.XXH32(buf) + } + options.count = options.rounds + options.processed = options.rounds * options.bytes + options.hash = u128(h) + return nil +} + +benchmark_xxhash64 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { + buf := options.input + + h: u64 + for _ in 0..=options.rounds { + h = xxhash.XXH64(buf) + } + options.count = options.rounds + options.processed = options.rounds * options.bytes + options.hash = u128(h) + return nil +} + +benchmark_print :: proc(name: string, options: ^time.Benchmark_Options) { + fmt.printf("\t[%v] %v rounds, %v bytes procesed in %v ns\n\t\t%5.3f rounds/s, %5.3f MiB/s\n", + name, + options.rounds, + options.processed, + time.duration_nanoseconds(options.duration), + options.rounds_per_second, + options.megabytes_per_second, + ) +} + +@test +test_benchmark_runner :: proc(t: ^testing.T) { + fmt.println("Starting benchmarks:") + + name := "xxhash32 100 zero bytes" + options := &time.Benchmark_Options{ + rounds = 1_000, + bytes = 100, + setup = setup_xxhash, + bench = benchmark_xxhash32, + teardown = teardown_xxhash, + } + + err := time.benchmark(options, context.allocator) + expect(t, err == nil, name) + expect(t, options.hash == 0x85f6413c, name) + benchmark_print(name, options) + + name = "xxhash32 1 MiB zero bytes" + options.bytes = 1_048_576 + err = time.benchmark(options, context.allocator) + expect(t, err == nil, name) + expect(t, options.hash == 0x9430f97f, name) + benchmark_print(name, options) + + name = "xxhash64 100 zero bytes" + options.bytes = 100 + options.bench = benchmark_xxhash64 + err = time.benchmark(options, context.allocator) + expect(t, err == nil, name) + expect(t, options.hash == 0x17bb1103c92c502f, name) + benchmark_print(name, options) + + name = "xxhash64 1 MiB zero bytes" + options.bytes = 1_048_576 + err = time.benchmark(options, context.allocator) + expect(t, err == nil, name) + expect(t, options.hash == 0x87d2a1b6e1163ef1, name) + benchmark_print(name, options) +} \ No newline at end of file