Browse Source

Factor benchmarks out into tests\benchmark\<pkg>

Jeroen van Rijn 1 year ago
parent
commit
8d93379e29

+ 23 - 0
.github/workflows/ci.yml

@@ -34,6 +34,7 @@ jobs:
           (cd tests/core; gmake all_bsd)
           (cd tests/internal; gmake all_bsd)
           (cd tests/issues; ./run.sh)
+          (cd tests/benchmark; gmake all)
   build_linux:
     name: Ubuntu Build, Check, and Test
     runs-on: ubuntu-latest
@@ -80,6 +81,11 @@ jobs:
           cd tests/internal
           make
         timeout-minutes: 10
+      - name: Odin core library benchmarks
+        run: |
+          cd tests/benchmark
+          make
+        timeout-minutes: 10
       - name: Odin check examples/all for Linux i386
         run: ./odin check examples/all -vet -strict-style -target:linux_i386
         timeout-minutes: 10
@@ -131,6 +137,11 @@ jobs:
           cd tests/internal
           make
         timeout-minutes: 10
+      - name: Odin core library benchmarks
+        run: |
+          cd tests/benchmark
+          make
+        timeout-minutes: 10
   build_macOS_arm:
     name: MacOS ARM Build, Check, and Test
     runs-on: macos-14 # This is an arm/m1 runner.
@@ -170,6 +181,11 @@ jobs:
           cd tests/internal
           make
         timeout-minutes: 10
+      - name: Odin core library benchmarks
+        run: |
+          cd tests/benchmark
+          make
+        timeout-minutes: 10
   build_windows:
     name: Windows Build, Check, and Test
     runs-on: windows-2022
@@ -245,6 +261,13 @@ jobs:
           cd tests\core\math\big
           call build.bat
         timeout-minutes: 10
+      - name: core library benchmarks
+        shell: cmd
+        run: |
+          call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
+          cd tests\benchmark
+          call build.bat
+        timeout-minutes: 10
       - name: Odin check examples/all for Windows 32bits
         shell: cmd
         run: |

+ 14 - 0
tests/benchmark/Makefile

@@ -0,0 +1,14 @@
+ODIN=../../odin
+COMMON=-no-bounds-check -vet -strict-style
+
+all: crypto_bench \
+     hash_bench
+
+crypto_bench:
+	$(ODIN) test crypto $(COMMON) -o:speed -out:bench_crypto
+
+hash_bench:
+	$(ODIN) test hash $(COMMON) -o:speed -out:bench_hash
+
+clean:
+	rm bench_*

+ 356 - 0
tests/benchmark/crypto/benchmark_crypto.odin

@@ -0,0 +1,356 @@
+package benchmark_core_crypto
+
+import "base:runtime"
+import "core:encoding/hex"
+import "core:fmt"
+import "core:log"
+import "core:strings"
+import "core:testing"
+import "core:time"
+
+import "core:crypto/aes"
+import "core:crypto/chacha20"
+import "core:crypto/chacha20poly1305"
+import "core:crypto/ed25519"
+import "core:crypto/poly1305"
+import "core:crypto/x25519"
+
+// Cryptographic primitive benchmarks.
+
+@(test)
+benchmark_crypto :: proc(t: ^testing.T) {
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
+
+	str: strings.Builder
+	strings.builder_init(&str, context.allocator)
+	defer {
+		log.info(strings.to_string(str))
+		strings.builder_destroy(&str)
+	}
+
+	{
+		name := "ChaCha20 64 bytes"
+		options := &time.Benchmark_Options {
+			rounds = 1_000,
+			bytes = 64,
+			setup = _setup_sized_buf,
+			bench = _benchmark_chacha20,
+			teardown = _teardown_sized_buf,
+		}
+
+		err := time.benchmark(options, context.allocator)
+		testing.expect(t, err == nil, name)
+		benchmark_print(&str, name, options)
+
+		name = "ChaCha20 1024 bytes"
+		options.bytes = 1024
+		err = time.benchmark(options, context.allocator)
+		testing.expect(t, err == nil, name)
+		benchmark_print(&str, name, options)
+
+		name = "ChaCha20 65536 bytes"
+		options.bytes = 65536
+		err = time.benchmark(options, context.allocator)
+		testing.expect(t, err == nil, name)
+		benchmark_print(&str, name, options)
+	}
+	{
+		name := "Poly1305 64 zero bytes"
+		options := &time.Benchmark_Options {
+			rounds = 1_000,
+			bytes = 64,
+			setup = _setup_sized_buf,
+			bench = _benchmark_poly1305,
+			teardown = _teardown_sized_buf,
+		}
+
+		err := time.benchmark(options, context.allocator)
+		testing.expect(t, err == nil, name)
+		benchmark_print(&str, name, options)
+
+		name = "Poly1305 1024 zero bytes"
+		options.bytes = 1024
+		err = time.benchmark(options, context.allocator)
+		testing.expect(t, err == nil, name)
+		benchmark_print(&str, name, options)
+	}
+	{
+		name := "chacha20poly1305 64 bytes"
+		options := &time.Benchmark_Options {
+			rounds = 1_000,
+			bytes = 64,
+			setup = _setup_sized_buf,
+			bench = _benchmark_chacha20poly1305,
+			teardown = _teardown_sized_buf,
+		}
+
+		err := time.benchmark(options, context.allocator)
+		testing.expect(t, err == nil, name)
+		benchmark_print(&str, name, options)
+
+		name = "chacha20poly1305 1024 bytes"
+		options.bytes = 1024
+		err = time.benchmark(options, context.allocator)
+		testing.expect(t, err == nil, name)
+		benchmark_print(&str, name, options)
+
+		name = "chacha20poly1305 65536 bytes"
+		options.bytes = 65536
+		err = time.benchmark(options, context.allocator)
+		testing.expect(t, err == nil, name)
+		benchmark_print(&str, name, options)
+	}
+	{
+		name := "AES256-GCM 64 bytes"
+		options := &time.Benchmark_Options {
+			rounds = 1_000,
+			bytes = 64,
+			setup = _setup_sized_buf,
+			bench = _benchmark_aes256_gcm,
+			teardown = _teardown_sized_buf,
+		}
+
+		key := [aes.KEY_SIZE_256]byte {
+			0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
+			0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
+			0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
+			0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
+		}
+		ctx: aes.Context_GCM
+		aes.init_gcm(&ctx, key[:])
+
+		context.user_ptr = &ctx
+
+		err := time.benchmark(options, context.allocator)
+		testing.expect(t, err == nil, name)
+		benchmark_print(&str, name, options)
+
+		name = "AES256-GCM 1024 bytes"
+		options.bytes = 1024
+		err = time.benchmark(options, context.allocator)
+		testing.expect(t, err == nil, name)
+		benchmark_print(&str, name, options)
+
+		name = "AES256-GCM 65536 bytes"
+		options.bytes = 65536
+		err = time.benchmark(options, context.allocator)
+		testing.expect(t, err == nil, name)
+		benchmark_print(&str, name, options)
+	}
+	{
+		iters :: 10000
+
+		priv_str := "cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe"
+		priv_bytes, _ := hex.decode(transmute([]byte)(priv_str), context.temp_allocator)
+		priv_key: ed25519.Private_Key
+		start := time.now()
+		for i := 0; i < iters; i = i + 1 {
+			ok := ed25519.private_key_set_bytes(&priv_key, priv_bytes)
+			assert(ok, "private key should deserialize")
+		}
+		elapsed := time.since(start)
+		fmt.sbprintfln(&str,
+			"ed25519.private_key_set_bytes: ~%f us/op",
+			time.duration_microseconds(elapsed) / iters,
+		)
+
+		pub_bytes := priv_key._pub_key._b[:] // "I know what I am doing"
+		pub_key: ed25519.Public_Key
+		start = time.now()
+		for i := 0; i < iters; i = i + 1 {
+			ok := ed25519.public_key_set_bytes(&pub_key, pub_bytes[:])
+			assert(ok, "public key should deserialize")
+		}
+		elapsed = time.since(start)
+		fmt.sbprintfln(&str,
+			"ed25519.public_key_set_bytes: ~%f us/op",
+			time.duration_microseconds(elapsed) / iters,
+		)
+
+		msg := "Got a job for you, 621."
+		sig_bytes: [ed25519.SIGNATURE_SIZE]byte
+		msg_bytes := transmute([]byte)(msg)
+		start = time.now()
+		for i := 0; i < iters; i = i + 1 {
+			ed25519.sign(&priv_key, msg_bytes, sig_bytes[:])
+		}
+		elapsed = time.since(start)
+		fmt.sbprintfln(&str,
+		    "ed25519.sign: ~%f us/op",
+		    time.duration_microseconds(elapsed) / iters,
+		)
+
+		start = time.now()
+		for i := 0; i < iters; i = i + 1 {
+			ok := ed25519.verify(&pub_key, msg_bytes, sig_bytes[:])
+			assert(ok, "signature should validate")
+		}
+		elapsed = time.since(start)
+		fmt.sbprintfln(&str,
+			"ed25519.verify: ~%f us/op",
+			time.duration_microseconds(elapsed) / iters,
+		)
+	}
+	{
+		point_str := "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
+		scalar_str := "cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe"
+
+		point, _ := hex.decode(transmute([]byte)(point_str), context.temp_allocator)
+		scalar, _ := hex.decode(transmute([]byte)(scalar_str), context.temp_allocator)
+		out: [x25519.POINT_SIZE]byte = ---
+
+		iters :: 10000
+		start := time.now()
+		for i := 0; i < iters; i = i + 1 {
+			x25519.scalarmult(out[:], scalar[:], point[:])
+		}
+		elapsed := time.since(start)
+
+		fmt.sbprintfln(&str,
+			"x25519.scalarmult: ~%f us/op",
+			time.duration_microseconds(elapsed) / iters,
+		)
+	}
+}
+
+@(private)
+_setup_sized_buf :: 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
+}
+
+@(private)
+_teardown_sized_buf :: proc(
+	options: ^time.Benchmark_Options,
+	allocator := context.allocator,
+) -> (
+	err: time.Benchmark_Error,
+) {
+	assert(options != nil)
+
+	delete(options.input)
+	return nil
+}
+
+@(private)
+_benchmark_chacha20 :: proc(
+	options: ^time.Benchmark_Options,
+	allocator := context.allocator,
+) -> (
+	err: time.Benchmark_Error,
+) {
+	buf := options.input
+	key := [chacha20.KEY_SIZE]byte {
+		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
+		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
+		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
+		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
+	}
+	nonce := [chacha20.NONCE_SIZE]byte {
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00,
+	}
+
+	ctx: chacha20.Context = ---
+	chacha20.init(&ctx, key[:], nonce[:])
+
+	for _ in 0 ..= options.rounds {
+		chacha20.xor_bytes(&ctx, buf, buf)
+	}
+	options.count = options.rounds
+	options.processed = options.rounds * options.bytes
+	return nil
+}
+
+@(private)
+_benchmark_poly1305 :: proc(
+	options: ^time.Benchmark_Options,
+	allocator := context.allocator,
+) -> (
+	err: time.Benchmark_Error,
+) {
+	buf := options.input
+	key := [poly1305.KEY_SIZE]byte {
+		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
+		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
+		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
+		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
+	}
+
+	tag: [poly1305.TAG_SIZE]byte = ---
+	for _ in 0 ..= options.rounds {
+		poly1305.sum(tag[:], buf, key[:])
+	}
+	options.count = options.rounds
+	options.processed = options.rounds * options.bytes
+	//options.hash      = u128(h)
+	return nil
+}
+
+@(private)
+_benchmark_chacha20poly1305 :: proc(
+	options: ^time.Benchmark_Options,
+	allocator := context.allocator,
+) -> (
+	err: time.Benchmark_Error,
+) {
+	buf := options.input
+	key := [chacha20.KEY_SIZE]byte {
+		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
+		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
+		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
+		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
+	}
+	nonce := [chacha20.NONCE_SIZE]byte {
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00,
+	}
+
+	tag: [chacha20poly1305.TAG_SIZE]byte = ---
+
+	for _ in 0 ..= options.rounds {
+		chacha20poly1305.encrypt(buf, tag[:], key[:], nonce[:], nil, buf)
+	}
+	options.count = options.rounds
+	options.processed = options.rounds * options.bytes
+	return nil
+}
+
+_benchmark_aes256_gcm :: proc(
+	options: ^time.Benchmark_Options,
+	allocator := context.allocator,
+) -> (
+	err: time.Benchmark_Error,
+) {
+	buf := options.input
+	nonce: [aes.GCM_NONCE_SIZE]byte
+	tag: [aes.GCM_TAG_SIZE]byte = ---
+
+	ctx := transmute(^aes.Context_GCM)context.user_ptr
+
+	for _ in 0 ..= options.rounds {
+		aes.seal_gcm(ctx, buf, tag[:], nonce[:], nil, buf)
+	}
+	options.count = options.rounds
+	options.processed = options.rounds * options.bytes
+	return nil
+}
+
+@(private)
+benchmark_print :: proc(str: ^strings.Builder, name: string, options: ^time.Benchmark_Options, loc := #caller_location) {
+	fmt.sbprintfln(str, "[%v] %v rounds, %v bytes processed 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,
+	)
+}

+ 218 - 0
tests/benchmark/hash/benchmark_hash.odin

@@ -0,0 +1,218 @@
+package benchmark_core_hash
+
+import "core:fmt"
+import "core:hash/xxhash"
+import "base:intrinsics"
+import "core:strings"
+import "core:testing"
+import "core:time"
+
+@(test)
+benchmark_hash :: proc(t: ^testing.T) {
+	str: strings.Builder
+	strings.builder_init(&str, context.allocator)
+	defer {
+		fmt.println(strings.to_string(str))
+		strings.builder_destroy(&str)
+	}
+
+	{
+		name := "XXH32 100 zero bytes"
+		options := &time.Benchmark_Options{
+			rounds   = 1_000,
+			bytes    = 100,
+			setup    = setup_xxhash,
+			bench    = benchmark_xxh32,
+			teardown = teardown_xxhash,
+		}
+		err := time.benchmark(options, context.allocator)
+		testing.expectf(t, err == nil, "%s failed with err %v", name, err)
+		hash := u128(0x85f6413c)
+		testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash)
+		benchmark_print(&str, name, options)
+	}
+	{
+		name := "XXH32 1 MiB zero bytes"
+		options := &time.Benchmark_Options{
+			rounds   = 1_000,
+			bytes    = 1_048_576,
+			setup    = setup_xxhash,
+			bench    = benchmark_xxh32,
+			teardown = teardown_xxhash,
+		}
+		err := time.benchmark(options, context.allocator)
+		testing.expectf(t, err == nil, "%s failed with err %v", name, err)
+		hash := u128(0x9430f97f)
+		testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash)
+		benchmark_print(&str, name, options)
+	}
+	{
+		name := "XXH64 100 zero bytes"
+		options := &time.Benchmark_Options{
+			rounds   = 1_000,
+			bytes    = 100,
+			setup    = setup_xxhash,
+			bench    = benchmark_xxh64,
+			teardown = teardown_xxhash,
+		}
+		err := time.benchmark(options, context.allocator)
+		testing.expectf(t, err == nil, "%s failed with err %v", name, err)
+		hash := u128(0x17bb1103c92c502f)
+		testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash)
+		benchmark_print(&str, name, options)
+	}
+	{
+		name := "XXH64 1 MiB zero bytes"
+		options := &time.Benchmark_Options{
+			rounds   = 1_000,
+			bytes    = 1_048_576,
+			setup    = setup_xxhash,
+			bench    = benchmark_xxh64,
+			teardown = teardown_xxhash,
+		}
+		err := time.benchmark(options, context.allocator)
+		testing.expectf(t, err == nil, "%s failed with err %v", name, err)
+		hash := u128(0x87d2a1b6e1163ef1)
+		testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash)
+		benchmark_print(&str, name, options)
+	}
+	{
+		name := "XXH3_64 100 zero bytes"
+		options := &time.Benchmark_Options{
+			rounds   = 1_000,
+			bytes    = 100,
+			setup    = setup_xxhash,
+			bench    = benchmark_xxh3_64,
+			teardown = teardown_xxhash,
+		}
+		err := time.benchmark(options, context.allocator)
+		testing.expectf(t, err == nil, "%s failed with err %v", name, err)
+		hash := u128(0x801fedc74ccd608c)
+		testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash)
+		benchmark_print(&str, name, options)
+	}
+	{
+		name := "XXH3_64 1 MiB zero bytes"
+		options := &time.Benchmark_Options{
+			rounds   = 1_000,
+			bytes    = 1_048_576,
+			setup    = setup_xxhash,
+			bench    = benchmark_xxh3_64,
+			teardown = teardown_xxhash,
+		}
+		err := time.benchmark(options, context.allocator)
+		testing.expectf(t, err == nil, "%s failed with err %v", name, err)
+		hash := u128(0x918780b90550bf34)
+		testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash)
+		benchmark_print(&str, name, options)
+	}
+	{
+		name := "XXH3_128 100 zero bytes"
+		options := &time.Benchmark_Options{
+			rounds   = 1_000,
+			bytes    = 100,
+			setup    = setup_xxhash,
+			bench    = benchmark_xxh3_128,
+			teardown = teardown_xxhash,
+		}
+		err := time.benchmark(options, context.allocator)
+		testing.expectf(t, err == nil, "%s failed with err %v", name, err)
+		hash := u128(0x6ba30a4e9dffe1ff801fedc74ccd608c)
+		testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash)
+		benchmark_print(&str, name, options)
+	}
+	{
+		name := "XXH3_128 1 MiB zero bytes"
+		options := &time.Benchmark_Options{
+			rounds   = 1_000,
+			bytes    = 1_048_576,
+			setup    = setup_xxhash,
+			bench    = benchmark_xxh3_128,
+			teardown = teardown_xxhash,
+		}
+		err := time.benchmark(options, context.allocator)
+		testing.expectf(t, err == nil, "%s failed with err %v", name, err)
+		hash := u128(0xb6ef17a3448492b6918780b90550bf34)
+		testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash)
+		benchmark_print(&str, name, options)
+	}
+}
+
+// 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_xxh32 :: 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_xxh64 :: 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_xxh3_64 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) {
+	buf := options.input
+
+	h: u64
+	for _ in 0..=options.rounds {
+		h = xxhash.XXH3_64(buf)
+	}
+	options.count     = options.rounds
+	options.processed = options.rounds * options.bytes
+	options.hash      = u128(h)
+	return nil
+}
+
+benchmark_xxh3_128 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) {
+	buf := options.input
+
+	h: u128
+	for _ in 0..=options.rounds {
+		h = xxhash.XXH3_128(buf)
+	}
+	options.count     = options.rounds
+	options.processed = options.rounds * options.bytes
+	options.hash      = h
+	return nil
+}
+
+benchmark_print :: proc(str: ^strings.Builder, name: string, options: ^time.Benchmark_Options, loc := #caller_location) {
+	fmt.sbprintfln(str, "[%v] %v rounds, %v bytes processed 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,
+	)
+}

+ 0 - 353
tests/core/crypto/test_crypto_benchmark.odin

@@ -1,353 +0,0 @@
-package test_core_crypto
-
-import "base:runtime"
-import "core:encoding/hex"
-import "core:log"
-import "core:testing"
-import "core:time"
-
-import "core:crypto/aes"
-import "core:crypto/chacha20"
-import "core:crypto/chacha20poly1305"
-import "core:crypto/ed25519"
-import "core:crypto/poly1305"
-import "core:crypto/x25519"
-
-// Cryptographic primitive benchmarks.
-
-@(test)
-bench_crypto :: proc(t: ^testing.T) {
-	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
-	bench_chacha20(t)
-	bench_poly1305(t)
-	bench_chacha20poly1305(t)
-	bench_aes256_gcm(t)
-	bench_ed25519(t)
-	bench_x25519(t)
-}
-
-_setup_sized_buf :: 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_sized_buf :: proc(
-	options: ^time.Benchmark_Options,
-	allocator := context.allocator,
-) -> (
-	err: time.Benchmark_Error,
-) {
-	assert(options != nil)
-
-	delete(options.input)
-	return nil
-}
-
-_benchmark_chacha20 :: proc(
-	options: ^time.Benchmark_Options,
-	allocator := context.allocator,
-) -> (
-	err: time.Benchmark_Error,
-) {
-	buf := options.input
-	key := [chacha20.KEY_SIZE]byte {
-		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
-		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
-		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
-		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
-	}
-	nonce := [chacha20.NONCE_SIZE]byte {
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00,
-	}
-
-	ctx: chacha20.Context = ---
-	chacha20.init(&ctx, key[:], nonce[:])
-
-	for _ in 0 ..= options.rounds {
-		chacha20.xor_bytes(&ctx, buf, buf)
-	}
-	options.count = options.rounds
-	options.processed = options.rounds * options.bytes
-	return nil
-}
-
-_benchmark_poly1305 :: proc(
-	options: ^time.Benchmark_Options,
-	allocator := context.allocator,
-) -> (
-	err: time.Benchmark_Error,
-) {
-	buf := options.input
-	key := [poly1305.KEY_SIZE]byte {
-		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
-		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
-		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
-		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
-	}
-
-	tag: [poly1305.TAG_SIZE]byte = ---
-	for _ in 0 ..= options.rounds {
-		poly1305.sum(tag[:], buf, key[:])
-	}
-	options.count = options.rounds
-	options.processed = options.rounds * options.bytes
-	//options.hash      = u128(h)
-	return nil
-}
-
-_benchmark_chacha20poly1305 :: proc(
-	options: ^time.Benchmark_Options,
-	allocator := context.allocator,
-) -> (
-	err: time.Benchmark_Error,
-) {
-	buf := options.input
-	key := [chacha20.KEY_SIZE]byte {
-		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
-		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
-		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
-		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
-	}
-	nonce := [chacha20.NONCE_SIZE]byte {
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00,
-	}
-
-	tag: [chacha20poly1305.TAG_SIZE]byte = ---
-
-	for _ in 0 ..= options.rounds {
-		chacha20poly1305.encrypt(buf, tag[:], key[:], nonce[:], nil, buf)
-	}
-	options.count = options.rounds
-	options.processed = options.rounds * options.bytes
-	return nil
-}
-
-_benchmark_aes256_gcm :: proc(
-	options: ^time.Benchmark_Options,
-	allocator := context.allocator,
-) -> (
-	err: time.Benchmark_Error,
-) {
-	buf := options.input
-	nonce: [aes.GCM_NONCE_SIZE]byte
-	tag: [aes.GCM_TAG_SIZE]byte = ---
-
-	ctx := transmute(^aes.Context_GCM)context.user_ptr
-
-	for _ in 0 ..= options.rounds {
-		aes.seal_gcm(ctx, buf, tag[:], nonce[:], nil, buf)
-	}
-	options.count = options.rounds
-	options.processed = options.rounds * options.bytes
-	return nil
-}
-
-benchmark_print :: proc(name: string, options: ^time.Benchmark_Options) {
-	log.infof(
-		"\n\t[%v] %v rounds, %v bytes processed in %v ns\n\t\t%5.3f rounds/s, %5.3f MiB/s",
-		name,
-		options.rounds,
-		options.processed,
-		time.duration_nanoseconds(options.duration),
-		options.rounds_per_second,
-		options.megabytes_per_second,
-	)
-}
-
-bench_chacha20 :: proc(t: ^testing.T) {
-	name := "ChaCha20 64 bytes"
-	options := &time.Benchmark_Options {
-		rounds = 1_000,
-		bytes = 64,
-		setup = _setup_sized_buf,
-		bench = _benchmark_chacha20,
-		teardown = _teardown_sized_buf,
-	}
-
-	err := time.benchmark(options, context.allocator)
-	testing.expect(t, err == nil, name)
-	benchmark_print(name, options)
-
-	name = "ChaCha20 1024 bytes"
-	options.bytes = 1024
-	err = time.benchmark(options, context.allocator)
-	testing.expect(t, err == nil, name)
-	benchmark_print(name, options)
-
-	name = "ChaCha20 65536 bytes"
-	options.bytes = 65536
-	err = time.benchmark(options, context.allocator)
-	testing.expect(t, err == nil, name)
-	benchmark_print(name, options)
-}
-
-bench_poly1305 :: proc(t: ^testing.T) {
-	name := "Poly1305 64 zero bytes"
-	options := &time.Benchmark_Options {
-		rounds = 1_000,
-		bytes = 64,
-		setup = _setup_sized_buf,
-		bench = _benchmark_poly1305,
-		teardown = _teardown_sized_buf,
-	}
-
-	err := time.benchmark(options, context.allocator)
-	testing.expect(t, err == nil, name)
-	benchmark_print(name, options)
-
-	name = "Poly1305 1024 zero bytes"
-	options.bytes = 1024
-	err = time.benchmark(options, context.allocator)
-	testing.expect(t, err == nil, name)
-	benchmark_print(name, options)
-}
-
-bench_chacha20poly1305 :: proc(t: ^testing.T) {
-	name := "chacha20poly1305 64 bytes"
-	options := &time.Benchmark_Options {
-		rounds = 1_000,
-		bytes = 64,
-		setup = _setup_sized_buf,
-		bench = _benchmark_chacha20poly1305,
-		teardown = _teardown_sized_buf,
-	}
-
-	err := time.benchmark(options, context.allocator)
-	testing.expect(t, err == nil, name)
-	benchmark_print(name, options)
-
-	name = "chacha20poly1305 1024 bytes"
-	options.bytes = 1024
-	err = time.benchmark(options, context.allocator)
-	testing.expect(t, err == nil, name)
-	benchmark_print(name, options)
-
-	name = "chacha20poly1305 65536 bytes"
-	options.bytes = 65536
-	err = time.benchmark(options, context.allocator)
-	testing.expect(t, err == nil, name)
-	benchmark_print(name, options)
-}
-
-bench_aes256_gcm :: proc(t: ^testing.T) {
-	name := "AES256-GCM 64 bytes"
-	options := &time.Benchmark_Options {
-		rounds = 1_000,
-		bytes = 64,
-		setup = _setup_sized_buf,
-		bench = _benchmark_aes256_gcm,
-		teardown = _teardown_sized_buf,
-	}
-
-	key := [aes.KEY_SIZE_256]byte {
-		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
-		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
-		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
-		0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
-	}
-	ctx: aes.Context_GCM
-	aes.init_gcm(&ctx, key[:])
-
-	context.user_ptr = &ctx
-
-	err := time.benchmark(options, context.allocator)
-	testing.expect(t, err == nil, name)
-	benchmark_print(name, options)
-
-	name = "AES256-GCM 1024 bytes"
-	options.bytes = 1024
-	err = time.benchmark(options, context.allocator)
-	testing.expect(t, err == nil, name)
-	benchmark_print(name, options)
-
-	name = "AES256-GCM 65536 bytes"
-	options.bytes = 65536
-	err = time.benchmark(options, context.allocator)
-	testing.expect(t, err == nil, name)
-	benchmark_print(name, options)
-}
-
-bench_ed25519 :: proc(t: ^testing.T) {
-	iters :: 10000
-
-	priv_str := "cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe"
-	priv_bytes, _ := hex.decode(transmute([]byte)(priv_str), context.temp_allocator)
-	priv_key: ed25519.Private_Key
-	start := time.now()
-	for i := 0; i < iters; i = i + 1 {
-		ok := ed25519.private_key_set_bytes(&priv_key, priv_bytes)
-		assert(ok, "private key should deserialize")
-	}
-	elapsed := time.since(start)
-	log.infof(
-		"ed25519.private_key_set_bytes: ~%f us/op",
-		time.duration_microseconds(elapsed) / iters,
-	)
-
-	pub_bytes := priv_key._pub_key._b[:] // "I know what I am doing"
-	pub_key: ed25519.Public_Key
-	start = time.now()
-	for i := 0; i < iters; i = i + 1 {
-		ok := ed25519.public_key_set_bytes(&pub_key, pub_bytes[:])
-		assert(ok, "public key should deserialize")
-	}
-	elapsed = time.since(start)
-	log.infof(
-		"ed25519.public_key_set_bytes: ~%f us/op",
-		time.duration_microseconds(elapsed) / iters,
-	)
-
-	msg := "Got a job for you, 621."
-	sig_bytes: [ed25519.SIGNATURE_SIZE]byte
-	msg_bytes := transmute([]byte)(msg)
-	start = time.now()
-	for i := 0; i < iters; i = i + 1 {
-		ed25519.sign(&priv_key, msg_bytes, sig_bytes[:])
-	}
-	elapsed = time.since(start)
-	log.infof(
-	    "ed25519.sign: ~%f us/op",
-	    time.duration_microseconds(elapsed) / iters,
-	)
-
-	start = time.now()
-	for i := 0; i < iters; i = i + 1 {
-		ok := ed25519.verify(&pub_key, msg_bytes, sig_bytes[:])
-		assert(ok, "signature should validate")
-	}
-	elapsed = time.since(start)
-	log.infof(
-		"ed25519.verify: ~%f us/op",
-		time.duration_microseconds(elapsed) / iters,
-	)
-}
-
-bench_x25519 :: proc(t: ^testing.T) {
-	point_str := "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
-	scalar_str := "cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe"
-
-	point, _ := hex.decode(transmute([]byte)(point_str), context.temp_allocator)
-	scalar, _ := hex.decode(transmute([]byte)(scalar_str), context.temp_allocator)
-	out: [x25519.POINT_SIZE]byte = ---
-
-	iters :: 10000
-	start := time.now()
-	for i := 0; i < iters; i = i + 1 {
-		x25519.scalarmult(out[:], scalar[:], point[:])
-	}
-	elapsed := time.since(start)
-
-	log.infof(
-		"x25519.scalarmult: ~%f us/op",
-		time.duration_microseconds(elapsed) / iters,
-	)
-}

+ 4 - 228
tests/core/hash/test_core_hash.odin

@@ -2,10 +2,7 @@ package test_core_hash
 
 import "core:hash/xxhash"
 import "core:hash"
-import "core:time"
 import "core:testing"
-import "core:fmt"
-import "core:log"
 import "core:math/rand"
 import "base:intrinsics"
 
@@ -78,15 +75,10 @@ test_xxhash_zero_streamed_random_updates :: proc(t: ^testing.T) {
 		xxh3_64  := xxhash.XXH3_64_digest(xxh3_64_state)
 		xxh3_128 := xxhash.XXH3_128_digest(xxh3_128_state)
 
-		xxh32_error     := fmt.tprintf("[   XXH32(%03d) ] Expected: %08x, got: %08x", i,   v.xxh_32,   xxh32)
-		xxh64_error     := fmt.tprintf("[   XXH64(%03d) ] Expected: %16x, got: %16x", i,   v.xxh_64,   xxh64)
-		xxh3_64_error   := fmt.tprintf("[XXH3_64(%03d)  ] Expected: %16x, got: %16x", i,  v.xxh3_64, xxh3_64)
-		xxh3_128_error  := fmt.tprintf("[XXH3_128(%03d) ] Expected: %32x, got: %32x", i, v.xxh3_128, xxh3_128)
-
-		testing.expect(t, xxh32     == v.xxh_32,   xxh32_error)
-		testing.expect(t, xxh64     == v.xxh_64,   xxh64_error)
-		testing.expect(t, xxh3_64   == v.xxh3_64,  xxh3_64_error)
-		testing.expect(t, xxh3_128  == v.xxh3_128, xxh3_128_error)
+		testing.expectf(t, xxh32     == v.xxh_32,   "[   XXH32(%03d) ] Expected: %08x, got: %08x", i,   v.xxh_32,   xxh32)
+		testing.expectf(t, xxh64     == v.xxh_64,   "[   XXH64(%03d) ] Expected: %16x, got: %16x", i,   v.xxh_64,   xxh64)
+		testing.expectf(t, xxh3_64   == v.xxh3_64,  "[XXH3_64(%03d)  ] Expected: %16x, got: %16x", i,  v.xxh3_64, xxh3_64)
+		testing.expectf(t, xxh3_128  == v.xxh3_128, "[XXH3_128(%03d) ] Expected: %32x, got: %32x", i, v.xxh3_128, xxh3_128)
 	}
 }
 
@@ -174,220 +166,4 @@ test_crc64_vectors :: proc(t: ^testing.T) {
 		testing.expectf(t, iso  == expected[2], "[ CRC-64 ISO 3306] Expected: %016x, got: %016x", expected[2], iso)
 		testing.expectf(t, iso2 == expected[3], "[~CRC-64 ISO 3306] Expected: %016x, got: %016x", expected[3], iso2)
 	}
-}
-
-@(test)
-test_benchmark_xxh32 :: proc(t: ^testing.T) {
-	name := "XXH32 100 zero bytes"
-	options := &time.Benchmark_Options{
-		rounds   = 1_000,
-		bytes    = 100,
-		setup    = setup_xxhash,
-		bench    = benchmark_xxh32,
-		teardown = teardown_xxhash,
-	}
-	err := time.benchmark(options, context.allocator)
-	testing.expectf(t, err == nil, "%s failed with err %v", name, err)
-	hash := u128(0x85f6413c)
-	testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash)
-	benchmark_print(name, options)
-}
-
-@(test)
-test_benchmark_xxh32_1MB :: proc(t: ^testing.T) {
-	name := "XXH32 1 MiB zero bytes"
-	options := &time.Benchmark_Options{
-		rounds   = 1_000,
-		bytes    = 1_048_576,
-		setup    = setup_xxhash,
-		bench    = benchmark_xxh32,
-		teardown = teardown_xxhash,
-	}
-	err := time.benchmark(options, context.allocator)
-	testing.expectf(t, err == nil, "%s failed with err %v", name, err)
-	hash := u128(0x9430f97f)
-	testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash)
-	benchmark_print(name, options)
-}
-
-@(test)
-test_benchmark_xxh64 :: proc(t: ^testing.T) {
-	name := "XXH64 100 zero bytes"
-	options := &time.Benchmark_Options{
-		rounds   = 1_000,
-		bytes    = 100,
-		setup    = setup_xxhash,
-		bench    = benchmark_xxh64,
-		teardown = teardown_xxhash,
-	}
-	err := time.benchmark(options, context.allocator)
-	testing.expectf(t, err == nil, "%s failed with err %v", name, err)
-	hash := u128(0x17bb1103c92c502f)
-	testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash)
-	benchmark_print(name, options)
-}
-
-@(test)
-test_benchmark_xxh64_1MB :: proc(t: ^testing.T) {
-	name := "XXH64 1 MiB zero bytes"
-	options := &time.Benchmark_Options{
-		rounds   = 1_000,
-		bytes    = 1_048_576,
-		setup    = setup_xxhash,
-		bench    = benchmark_xxh64,
-		teardown = teardown_xxhash,
-	}
-	err := time.benchmark(options, context.allocator)
-	testing.expectf(t, err == nil, "%s failed with err %v", name, err)
-	hash := u128(0x87d2a1b6e1163ef1)
-	testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash)
-	benchmark_print(name, options)
-}
-
-@(test)
-test_benchmark_xxh3_64 :: proc(t: ^testing.T) {
-	name := "XXH3_64 100 zero bytes"
-	options := &time.Benchmark_Options{
-		rounds   = 1_000,
-		bytes    = 100,
-		setup    = setup_xxhash,
-		bench    = benchmark_xxh3_64,
-		teardown = teardown_xxhash,
-	}
-	err := time.benchmark(options, context.allocator)
-	testing.expectf(t, err == nil, "%s failed with err %v", name, err)
-	hash := u128(0x801fedc74ccd608c)
-	testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash)
-	benchmark_print(name, options)
-}
-
-@(test)
-test_benchmark_xxh3_64_1MB :: proc(t: ^testing.T) {
-	name := "XXH3_64 1 MiB zero bytes"
-	options := &time.Benchmark_Options{
-		rounds   = 1_000,
-		bytes    = 1_048_576,
-		setup    = setup_xxhash,
-		bench    = benchmark_xxh3_64,
-		teardown = teardown_xxhash,
-	}
-	err := time.benchmark(options, context.allocator)
-	testing.expectf(t, err == nil, "%s failed with err %v", name, err)
-	hash := u128(0x918780b90550bf34)
-	testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash)
-	benchmark_print(name, options)
-}
-
-@(test)
-test_benchmark_xxh3_128 :: proc(t: ^testing.T) {
-	name := "XXH3_128 100 zero bytes"
-	options := &time.Benchmark_Options{
-		rounds   = 1_000,
-		bytes    = 100,
-		setup    = setup_xxhash,
-		bench    = benchmark_xxh3_128,
-		teardown = teardown_xxhash,
-	}
-	err := time.benchmark(options, context.allocator)
-	testing.expectf(t, err == nil, "%s failed with err %v", name, err)
-	hash := u128(0x6ba30a4e9dffe1ff801fedc74ccd608c)
-	testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash)
-	benchmark_print(name, options)
-}
-
-@(test)
-test_benchmark_xxh3_128_1MB :: proc(t: ^testing.T) {
-	name := "XXH3_128 1 MiB zero bytes"
-	options := &time.Benchmark_Options{
-		rounds   = 1_000,
-		bytes    = 1_048_576,
-		setup    = setup_xxhash,
-		bench    = benchmark_xxh3_128,
-		teardown = teardown_xxhash,
-	}
-	err := time.benchmark(options, context.allocator)
-	testing.expectf(t, err == nil, "%s failed with err %v", name, err)
-	hash := u128(0xb6ef17a3448492b6918780b90550bf34)
-	testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash)
-	benchmark_print(name, options)
-}
-
-// 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_xxh32 :: 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_xxh64 :: 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_xxh3_64 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) {
-	buf := options.input
-
-	h: u64
-	for _ in 0..=options.rounds {
-		h = xxhash.XXH3_64(buf)
-	}
-	options.count     = options.rounds
-	options.processed = options.rounds * options.bytes
-	options.hash      = u128(h)
-	return nil
-}
-
-benchmark_xxh3_128 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) {
-	buf := options.input
-
-	h: u128
-	for _ in 0..=options.rounds {
-		h = xxhash.XXH3_128(buf)
-	}
-	options.count     = options.rounds
-	options.processed = options.rounds * options.bytes
-	options.hash      = h
-	return nil
-}
-
-benchmark_print :: proc(name: string, options: ^time.Benchmark_Options, loc := #caller_location) {
-	log.infof("\n\t[%v] %v rounds, %v bytes processed in %v ns\n\t\t%5.3f rounds/s, %5.3f MiB/s",
-		name,
-		options.rounds,
-		options.processed,
-		time.duration_nanoseconds(options.duration),
-		options.rounds_per_second,
-		options.megabytes_per_second,
-		location=loc,
-	)
 }