Make benchmarking use std.Io.Clock.awake for timing (#31553)

In #31086, the `std.time.Timer` struct was removed, but this broke the last few programs that used it, those being the benchmarking programs for `std.Random`, `std.hash`, `std.crypto` and `std.unicode`. One more is `zig/perf_test.zig`, but as far as I can tell, that one is broken due to changes in file import rules too, unless I'm launching it wrong.

I also spotted some performance and benchmarking issues with the RNGs, detailed in #31554.

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31553
Reviewed-by: Andrew Kelley <andrew@ziglang.org>
Co-authored-by: UraniaZPM <uraniazpm@noreply.codeberg.org>
Co-committed-by: UraniaZPM <uraniazpm@noreply.codeberg.org>
This commit is contained in:
UraniaZPM
2026-03-18 21:00:08 +01:00
committed by Andrew Kelley
parent ce1f7136ae
commit 485b996b61
4 changed files with 95 additions and 97 deletions
+11 -9
View File
@@ -5,7 +5,6 @@ const builtin = @import("builtin");
const std = @import("std");
const Io = std.Io;
const time = std.time;
const Timer = time.Timer;
const Random = std.Random;
const KiB = 1024;
@@ -72,7 +71,11 @@ const Result = struct {
const long_block_size: usize = 8 * 8192;
const short_block_size: usize = 8;
pub fn benchmark(comptime H: anytype, bytes: usize, comptime block_size: usize) !Result {
pub fn benchTime(io: Io) i96 {
return Io.Clock.awake.now(io).nanoseconds;
}
pub fn benchmark(comptime H: anytype, io: Io, bytes: usize, comptime block_size: usize) !Result {
var rng = blk: {
if (H.init_u8s) |init| {
break :blk H.ty.init(init[0..].*);
@@ -86,12 +89,11 @@ pub fn benchmark(comptime H: anytype, bytes: usize, comptime block_size: usize)
var block: [block_size]u8 = undefined;
var offset: usize = 0;
var timer = try Timer.start();
const start = timer.lap();
const start = benchTime(io);
while (offset < bytes) : (offset += block.len) {
rng.fill(block[0..]);
}
const end = timer.read();
const end = benchTime(io);
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
const throughput = @as(u64, @intFromFloat(@as(f64, @floatFromInt(bytes)) / elapsed_s));
@@ -187,7 +189,7 @@ pub fn main(init: std.process.Init) !void {
try stdout.print("{s} (long outputs)\n", .{R.name});
try stdout.flush();
const result_long = try benchmark(R, count, long_block_size);
const result_long = try benchmark(R, io, count, long_block_size);
try stdout.print(" {:5} MiB/s\n", .{result_long.throughput / (1 * MiB)});
}
}
@@ -198,7 +200,7 @@ pub fn main(init: std.process.Init) !void {
try stdout.print("{s} (short outputs)\n", .{R.name});
try stdout.flush();
const result_short = try benchmark(R, count, short_block_size);
const result_short = try benchmark(R, io, count, short_block_size);
try stdout.print(" {:5} MiB/s\n", .{result_short.throughput / (1 * MiB)});
}
}
@@ -211,7 +213,7 @@ pub fn main(init: std.process.Init) !void {
try stdout.print("{s} (cryptographic, long outputs)\n", .{R.name});
try stdout.flush();
const result_long = try benchmark(R, count, long_block_size);
const result_long = try benchmark(R, io, count, long_block_size);
try stdout.print(" {:5} MiB/s\n", .{result_long.throughput / (1 * MiB)});
}
}
@@ -222,7 +224,7 @@ pub fn main(init: std.process.Init) !void {
try stdout.print("{s} (cryptographic, short outputs)\n", .{R.name});
try stdout.flush();
const result_short = try benchmark(R, count, short_block_size);
const result_short = try benchmark(R, io, count, short_block_size);
try stdout.print(" {:5} MiB/s\n", .{result_short.throughput / (1 * MiB)});
}
}
+44 -55
View File
@@ -6,7 +6,6 @@ const std = @import("std");
const Io = std.Io;
const mem = std.mem;
const time = std.time;
const Timer = std.time.Timer;
const crypto = std.crypto;
const KiB = 1024;
@@ -45,15 +44,18 @@ const parallel_hashes = [_]Crypto{
const block_size: usize = 8 * 8192;
pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64 {
pub fn benchTime(io: Io) i96 {
return Io.Clock.awake.now(io).nanoseconds;
}
pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int, io: Io) !u64 {
const blocks_count = bytes / block_size;
var block: [block_size]u8 = undefined;
random.bytes(&block);
var h = Hash.init(.{});
var timer = try Timer.start();
const start = timer.lap();
const start = benchTime(io);
for (0..blocks_count) |_| {
h.update(&block);
}
@@ -61,7 +63,7 @@ pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64
h.final(&final);
std.mem.doNotOptimizeAway(final);
const end = timer.read();
const end = benchTime(io);
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
const throughput = @as(u64, @intFromFloat(bytes / elapsed_s));
@@ -74,13 +76,12 @@ pub fn benchmarkHashParallel(comptime Hash: anytype, comptime bytes: comptime_in
defer allocator.free(data);
random.bytes(data);
var timer = try Timer.start();
const start = timer.lap();
const start = benchTime(io);
var final: [Hash.digest_length]u8 = undefined;
try Hash.hashParallel(data, &final, .{}, allocator, io);
std.mem.doNotOptimizeAway(final);
const end = timer.read();
const end = benchTime(io);
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
const throughput = @as(u64, @intFromFloat(bytes / elapsed_s));
@@ -109,7 +110,7 @@ const macs = [_]Crypto{
Crypto{ .ty = crypto.auth.cmac.CmacAes128, .name = "aes-cmac" },
};
pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 {
pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int, io: Io) !u64 {
var in: [512 * KiB]u8 = undefined;
random.bytes(in[0..]);
@@ -119,13 +120,12 @@ pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 {
var mac: [Mac.mac_length]u8 = undefined;
var offset: usize = 0;
var timer = try Timer.start();
const start = timer.lap();
const start = benchTime(io);
while (offset < bytes) : (offset += in.len) {
Mac.create(mac[0..], in[0..], key[0..]);
mem.doNotOptimizeAway(&mac);
}
const end = timer.read();
const end = benchTime(io);
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
const throughput = @as(u64, @intFromFloat(bytes / elapsed_s));
@@ -135,7 +135,7 @@ pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 {
const exchanges = [_]Crypto{Crypto{ .ty = crypto.dh.X25519, .name = "x25519" }};
pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_count: comptime_int) !u64 {
pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_count: comptime_int, io: Io) !u64 {
std.debug.assert(DhKeyExchange.shared_length >= DhKeyExchange.secret_length);
var secret: [DhKeyExchange.shared_length]u8 = undefined;
@@ -144,8 +144,7 @@ pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_c
var public: [DhKeyExchange.shared_length]u8 = undefined;
random.bytes(public[0..]);
var timer = try Timer.start();
const start = timer.lap();
const start = benchTime(io);
{
var i: usize = 0;
while (i < exchange_count) : (i += 1) {
@@ -155,7 +154,7 @@ pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_c
mem.doNotOptimizeAway(&out);
}
}
const end = timer.read();
const end = benchTime(io);
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
const throughput = @as(u64, @intFromFloat(exchange_count / elapsed_s));
@@ -177,8 +176,7 @@ pub fn benchmarkSignature(comptime Signature: anytype, comptime signatures_count
const msg = [_]u8{0} ** 64;
const key_pair = Signature.KeyPair.generate(io);
var timer = try Timer.start();
const start = timer.lap();
const start = benchTime(io);
{
var i: usize = 0;
while (i < signatures_count) : (i += 1) {
@@ -186,7 +184,7 @@ pub fn benchmarkSignature(comptime Signature: anytype, comptime signatures_count
mem.doNotOptimizeAway(&sig);
}
}
const end = timer.read();
const end = benchTime(io);
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
const throughput = @as(u64, @intFromFloat(signatures_count / elapsed_s));
@@ -206,8 +204,7 @@ pub fn benchmarkSignatureVerification(comptime Signature: anytype, comptime sign
const key_pair = Signature.KeyPair.generate(io);
const sig = try key_pair.sign(&msg, null);
var timer = try Timer.start();
const start = timer.lap();
const start = benchTime(io);
{
var i: usize = 0;
while (i < signatures_count) : (i += 1) {
@@ -215,7 +212,7 @@ pub fn benchmarkSignatureVerification(comptime Signature: anytype, comptime sign
mem.doNotOptimizeAway(&sig);
}
}
const end = timer.read();
const end = benchTime(io);
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
const throughput = @as(u64, @intFromFloat(signatures_count / elapsed_s));
@@ -235,8 +232,7 @@ pub fn benchmarkBatchSignatureVerification(comptime Signature: anytype, comptime
element.* = Signature.BatchElement{ .sig = sig, .msg = &msg, .public_key = key_pair.public_key };
}
var timer = try Timer.start();
const start = timer.lap();
const start = benchTime(io);
{
var i: usize = 0;
while (i < signatures_count) : (i += 1) {
@@ -244,7 +240,7 @@ pub fn benchmarkBatchSignatureVerification(comptime Signature: anytype, comptime
mem.doNotOptimizeAway(&sig);
}
}
const end = timer.read();
const end = benchTime(io);
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
const throughput = batch.len * @as(u64, @intFromFloat(signatures_count / elapsed_s));
@@ -261,8 +257,7 @@ const kems = [_]Crypto{
pub fn benchmarkKem(comptime Kem: anytype, comptime kems_count: comptime_int, io: std.Io) !u64 {
const key_pair = Kem.KeyPair.generate(io);
var timer = try Timer.start();
const start = timer.lap();
const start = benchTime(io);
{
var i: usize = 0;
while (i < kems_count) : (i += 1) {
@@ -270,7 +265,7 @@ pub fn benchmarkKem(comptime Kem: anytype, comptime kems_count: comptime_int, io
mem.doNotOptimizeAway(&e);
}
}
const end = timer.read();
const end = benchTime(io);
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
const throughput = @as(u64, @intFromFloat(kems_count / elapsed_s));
@@ -283,8 +278,7 @@ pub fn benchmarkKemDecaps(comptime Kem: anytype, comptime kems_count: comptime_i
const e = key_pair.public_key.encaps(io);
var timer = try Timer.start();
const start = timer.lap();
const start = benchTime(io);
{
var i: usize = 0;
while (i < kems_count) : (i += 1) {
@@ -292,7 +286,7 @@ pub fn benchmarkKemDecaps(comptime Kem: anytype, comptime kems_count: comptime_i
mem.doNotOptimizeAway(&ss2);
}
}
const end = timer.read();
const end = benchTime(io);
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
const throughput = @as(u64, @intFromFloat(kems_count / elapsed_s));
@@ -301,8 +295,7 @@ pub fn benchmarkKemDecaps(comptime Kem: anytype, comptime kems_count: comptime_i
}
pub fn benchmarkKemKeyGen(comptime Kem: anytype, comptime kems_count: comptime_int, io: std.Io) !u64 {
var timer = try Timer.start();
const start = timer.lap();
const start = benchTime(io);
{
var i: usize = 0;
while (i < kems_count) : (i += 1) {
@@ -310,7 +303,7 @@ pub fn benchmarkKemKeyGen(comptime Kem: anytype, comptime kems_count: comptime_i
mem.doNotOptimizeAway(&key_pair);
}
}
const end = timer.read();
const end = benchTime(io);
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
const throughput = @as(u64, @intFromFloat(kems_count / elapsed_s));
@@ -337,7 +330,7 @@ const aeads = [_]Crypto{
Crypto{ .ty = crypto.aead.isap.IsapA128A, .name = "isapa128a" },
};
pub fn benchmarkAead(comptime Aead: anytype, comptime bytes: comptime_int) !u64 {
pub fn benchmarkAead(comptime Aead: anytype, comptime bytes: comptime_int, io: Io) !u64 {
var in: [512 * KiB]u8 = undefined;
random.bytes(in[0..]);
@@ -350,14 +343,13 @@ pub fn benchmarkAead(comptime Aead: anytype, comptime bytes: comptime_int) !u64
random.bytes(nonce[0..]);
var offset: usize = 0;
var timer = try Timer.start();
const start = timer.lap();
const start = benchTime(io);
while (offset < bytes) : (offset += in.len) {
Aead.encrypt(in[0..], tag[0..], in[0..], &[_]u8{}, nonce, key);
try Aead.decrypt(in[0..], in[0..], tag, &[_]u8{}, nonce, key);
}
mem.doNotOptimizeAway(&in);
const end = timer.read();
const end = benchTime(io);
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
const throughput = @as(u64, @intFromFloat(2 * bytes / elapsed_s));
@@ -370,15 +362,14 @@ const aes = [_]Crypto{
Crypto{ .ty = crypto.core.aes.Aes256, .name = "aes256-single" },
};
pub fn benchmarkAes(comptime Aes: anytype, comptime count: comptime_int) !u64 {
pub fn benchmarkAes(comptime Aes: anytype, comptime count: comptime_int, io: Io) !u64 {
var key: [Aes.key_bits / 8]u8 = undefined;
random.bytes(key[0..]);
const ctx = Aes.initEnc(key);
var in = [_]u8{0} ** 16;
var timer = try Timer.start();
const start = timer.lap();
const start = benchTime(io);
{
var i: usize = 0;
while (i < count) : (i += 1) {
@@ -386,7 +377,7 @@ pub fn benchmarkAes(comptime Aes: anytype, comptime count: comptime_int) !u64 {
}
}
mem.doNotOptimizeAway(&in);
const end = timer.read();
const end = benchTime(io);
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
const throughput = @as(u64, @intFromFloat(count / elapsed_s));
@@ -399,15 +390,14 @@ const aes8 = [_]Crypto{
Crypto{ .ty = crypto.core.aes.Aes256, .name = "aes256-8" },
};
pub fn benchmarkAes8(comptime Aes: anytype, comptime count: comptime_int) !u64 {
pub fn benchmarkAes8(comptime Aes: anytype, comptime count: comptime_int, io: Io) !u64 {
var key: [Aes.key_bits / 8]u8 = undefined;
random.bytes(key[0..]);
const ctx = Aes.initEnc(key);
var in = [_]u8{0} ** (8 * 16);
var timer = try Timer.start();
const start = timer.lap();
const start = benchTime(io);
{
var i: usize = 0;
while (i < count) : (i += 1) {
@@ -415,7 +405,7 @@ pub fn benchmarkAes8(comptime Aes: anytype, comptime count: comptime_int) !u64 {
}
}
mem.doNotOptimizeAway(&in);
const end = timer.read();
const end = benchTime(io);
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
const throughput = @as(u64, @intFromFloat(8 * count / elapsed_s));
@@ -468,8 +458,7 @@ fn benchmarkPwhash(
const needs_salt = strHashFnInfo.params.len == 4 and strHashFnInfo.params[3].type != std.Io;
const salt: [16]u8 = .{0} ** 16;
var timer = try Timer.start();
const start = timer.lap();
const start = benchTime(io);
{
var i: usize = 0;
while (i < count) : (i += 1) {
@@ -483,7 +472,7 @@ fn benchmarkPwhash(
mem.doNotOptimizeAway(&buf);
}
}
const end = timer.read();
const end = benchTime(io);
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
const throughput = elapsed_s / count;
@@ -554,7 +543,7 @@ pub fn main(init: std.process.Init) !void {
inline for (hashes) |H| {
if (filter == null or std.mem.find(u8, H.name, filter.?) != null) {
const throughput = try benchmarkHash(H.ty, mode(128 * MiB));
const throughput = try benchmarkHash(H.ty, mode(128 * MiB), io);
try stdout.print("{s:>17}: {:10} MiB/s\n", .{ H.name, throughput / (1 * MiB) });
try stdout.flush();
}
@@ -570,7 +559,7 @@ pub fn main(init: std.process.Init) !void {
inline for (macs) |M| {
if (filter == null or std.mem.find(u8, M.name, filter.?) != null) {
const throughput = try benchmarkMac(M.ty, mode(128 * MiB));
const throughput = try benchmarkMac(M.ty, mode(128 * MiB), io);
try stdout.print("{s:>17}: {:10} MiB/s\n", .{ M.name, throughput / (1 * MiB) });
try stdout.flush();
}
@@ -578,7 +567,7 @@ pub fn main(init: std.process.Init) !void {
inline for (exchanges) |E| {
if (filter == null or std.mem.find(u8, E.name, filter.?) != null) {
const throughput = try benchmarkKeyExchange(E.ty, mode(1000));
const throughput = try benchmarkKeyExchange(E.ty, mode(1000), io);
try stdout.print("{s:>17}: {:10} exchanges/s\n", .{ E.name, throughput });
try stdout.flush();
}
@@ -610,7 +599,7 @@ pub fn main(init: std.process.Init) !void {
inline for (aeads) |E| {
if (filter == null or std.mem.find(u8, E.name, filter.?) != null) {
const throughput = try benchmarkAead(E.ty, mode(128 * MiB));
const throughput = try benchmarkAead(E.ty, mode(128 * MiB), io);
try stdout.print("{s:>17}: {:10} MiB/s\n", .{ E.name, throughput / (1 * MiB) });
try stdout.flush();
}
@@ -618,7 +607,7 @@ pub fn main(init: std.process.Init) !void {
inline for (aes) |E| {
if (filter == null or std.mem.find(u8, E.name, filter.?) != null) {
const throughput = try benchmarkAes(E.ty, mode(100000000));
const throughput = try benchmarkAes(E.ty, mode(100000000), io);
try stdout.print("{s:>17}: {:10} ops/s\n", .{ E.name, throughput });
try stdout.flush();
}
@@ -626,7 +615,7 @@ pub fn main(init: std.process.Init) !void {
inline for (aes8) |E| {
if (filter == null or std.mem.find(u8, E.name, filter.?) != null) {
const throughput = try benchmarkAes8(E.ty, mode(10000000));
const throughput = try benchmarkAes8(E.ty, mode(10000000), io);
try stdout.print("{s:>17}: {:10} ops/s\n", .{ E.name, throughput });
try stdout.flush();
}
+26 -21
View File
@@ -4,7 +4,6 @@ const builtin = @import("builtin");
const std = @import("std");
const Io = std.Io;
const time = std.time;
const Timer = time.Timer;
const hash = std.hash;
const KiB = 1024;
@@ -111,7 +110,11 @@ const Result = struct {
const block_size: usize = 8 * 8192;
pub fn benchmarkHash(comptime H: anytype, bytes: usize, allocator: std.mem.Allocator) !Result {
pub fn benchTime(io: Io) i96 {
return Io.Clock.awake.now(io).nanoseconds;
}
pub fn benchmarkHash(comptime H: anytype, bytes: usize, allocator: std.mem.Allocator, io: Io) !Result {
var blocks = try allocator.alloc(u8, bytes);
defer allocator.free(blocks);
random.bytes(blocks);
@@ -131,7 +134,7 @@ pub fn benchmarkHash(comptime H: anytype, bytes: usize, allocator: std.mem.Alloc
break :blk .init();
};
var timer = try Timer.start();
const start = benchTime(io);
for (0..block_count) |i| {
h.update(blocks[i * block_size ..][0..block_size]);
}
@@ -143,7 +146,7 @@ pub fn benchmarkHash(comptime H: anytype, bytes: usize, allocator: std.mem.Alloc
h.final();
std.mem.doNotOptimizeAway(final);
const elapsed_ns = timer.read();
const elapsed_ns = benchTime(io) - start;
const elapsed_s = @as(f64, @floatFromInt(elapsed_ns)) / time.ns_per_s;
const size_float: f64 = @floatFromInt(block_size * block_count);
@@ -155,14 +158,14 @@ pub fn benchmarkHash(comptime H: anytype, bytes: usize, allocator: std.mem.Alloc
};
}
pub fn benchmarkHashSmallKeys(comptime H: anytype, key_size: usize, bytes: usize, allocator: std.mem.Allocator) !Result {
pub fn benchmarkHashSmallKeys(comptime H: anytype, key_size: usize, bytes: usize, allocator: std.mem.Allocator, io: Io) !Result {
var blocks = try allocator.alloc(u8, bytes);
defer allocator.free(blocks);
random.bytes(blocks);
const key_count = bytes / key_size;
var timer = try Timer.start();
const start = benchTime(io);
var sum: u64 = 0;
for (0..key_count) |i| {
@@ -182,7 +185,7 @@ pub fn benchmarkHashSmallKeys(comptime H: anytype, key_size: usize, bytes: usize
};
sum +%= final;
}
const elapsed_ns = timer.read();
const elapsed_ns = benchTime(io) - start;
const elapsed_s = @as(f64, @floatFromInt(elapsed_ns)) / time.ns_per_s;
const size_float: f64 = @floatFromInt(key_count * key_size);
@@ -204,6 +207,7 @@ pub fn benchmarkHashSmallKeysArrayPtr(
comptime key_size: usize,
bytes: usize,
allocator: std.mem.Allocator,
io: Io,
) !Result {
var blocks = try allocator.alloc(u8, bytes);
defer allocator.free(blocks);
@@ -211,7 +215,7 @@ pub fn benchmarkHashSmallKeysArrayPtr(
const key_count = bytes / key_size;
var timer = try Timer.start();
const start = benchTime(io);
var sum: u64 = 0;
for (0..key_count) |i| {
@@ -231,7 +235,7 @@ pub fn benchmarkHashSmallKeysArrayPtr(
};
sum +%= final;
}
const elapsed_ns = timer.read();
const elapsed_ns = benchTime(io) - start;
const elapsed_s = @as(f64, @floatFromInt(elapsed_ns)) / time.ns_per_s;
const throughput: u64 = @intFromFloat(@as(f64, @floatFromInt(bytes)) / elapsed_s);
@@ -252,6 +256,7 @@ pub fn benchmarkHashSmallKeysArray(
comptime key_size: usize,
bytes: usize,
allocator: std.mem.Allocator,
io: Io,
) !Result {
var blocks = try allocator.alloc(u8, bytes);
defer allocator.free(blocks);
@@ -260,7 +265,7 @@ pub fn benchmarkHashSmallKeysArray(
const key_count = bytes / key_size;
var i: usize = 0;
var timer = try Timer.start();
const start = benchTime(io);
var sum: u64 = 0;
while (i < key_count) : (i += 1) {
@@ -280,7 +285,7 @@ pub fn benchmarkHashSmallKeysArray(
};
sum +%= final;
}
const elapsed_ns = timer.read();
const elapsed_ns = benchTime(io) - start;
const elapsed_s = @as(f64, @floatFromInt(elapsed_ns)) / time.ns_per_s;
const throughput: u64 = @intFromFloat(@as(f64, @floatFromInt(bytes)) / elapsed_s);
@@ -293,14 +298,14 @@ pub fn benchmarkHashSmallKeysArray(
};
}
pub fn benchmarkHashSmallApi(comptime H: anytype, key_size: usize, bytes: usize, allocator: std.mem.Allocator) !Result {
pub fn benchmarkHashSmallApi(comptime H: anytype, key_size: usize, bytes: usize, allocator: std.mem.Allocator, io: Io) !Result {
var blocks = try allocator.alloc(u8, bytes);
defer allocator.free(blocks);
random.bytes(blocks);
const key_count = bytes / key_size;
var timer = try Timer.start();
const start = benchTime(io);
var sum: u64 = 0;
for (0..key_count) |i| {
@@ -320,7 +325,7 @@ pub fn benchmarkHashSmallApi(comptime H: anytype, key_size: usize, bytes: usize,
};
sum +%= final;
}
const elapsed_ns = timer.read();
const elapsed_ns = benchTime(io) - start;
const elapsed_s = @as(f64, @floatFromInt(elapsed_ns)) / time.ns_per_s;
const throughput: u64 = @intFromFloat(@as(f64, @floatFromInt(bytes)) / elapsed_s);
@@ -454,7 +459,7 @@ pub fn main(init: std.process.Init) !void {
// This allows easier comparison between different implementations.
if (H.has_iterative_api and !test_small_key_only) {
prng.seed(seed);
const result = try benchmarkHash(H, count, allocator);
const result = try benchmarkHash(H, count, allocator, io);
try stdout.print(" iterative: {:5} MiB/s [{x:0<16}]\n", .{ result.throughput / (1 * MiB), result.hash });
try stdout.flush();
}
@@ -462,7 +467,7 @@ pub fn main(init: std.process.Init) !void {
if (!test_iterative_only) {
if (key_size) |size| {
prng.seed(seed);
const result_small = try benchmarkHashSmallKeys(H, size, count, allocator);
const result_small = try benchmarkHashSmallKeys(H, size, count, allocator, io);
try stdout.print(" small keys: {:3}B {:5} MiB/s {} Hashes/s [{x:0<16}]\n", .{
size,
result_small.throughput / (1 * MiB),
@@ -476,9 +481,9 @@ pub fn main(init: std.process.Init) !void {
inline for (sizes) |exact_size| {
if (size == exact_size) {
prng.seed(seed);
const result_array = try benchmarkHashSmallKeysArray(H, exact_size, count, allocator);
const result_array = try benchmarkHashSmallKeysArray(H, exact_size, count, allocator, io);
prng.seed(seed);
const result_ptr = try benchmarkHashSmallKeysArrayPtr(H, exact_size, count, allocator);
const result_ptr = try benchmarkHashSmallKeysArrayPtr(H, exact_size, count, allocator, io);
try stdout.print(" array: {:5} MiB/s [{x:0<16}]\n", .{
result_array.throughput / (1 * MiB),
result_array.hash,
@@ -493,7 +498,7 @@ pub fn main(init: std.process.Init) !void {
}
} else {
prng.seed(seed);
const result_small = try benchmarkHashSmallKeys(H, default_small_key_size, count, allocator);
const result_small = try benchmarkHashSmallKeys(H, default_small_key_size, count, allocator, io);
try stdout.print(" small keys: {:3}B {:5} MiB/s {} Hashes/s [{x:0<16}]\n", .{
default_small_key_size,
result_small.throughput / (1 * MiB),
@@ -507,7 +512,7 @@ pub fn main(init: std.process.Init) !void {
try stdout.print(" array:\n", .{});
inline for (sizes) |exact_size| {
prng.seed(seed);
const result = try benchmarkHashSmallKeysArray(H, exact_size, count, allocator);
const result = try benchmarkHashSmallKeysArray(H, exact_size, count, allocator, io);
try stdout.print(" {d: >3}B {:5} MiB/s [{x:0<16}]\n", .{
exact_size,
result.throughput / (1 * MiB),
@@ -518,7 +523,7 @@ pub fn main(init: std.process.Init) !void {
try stdout.print(" array ptr: \n", .{});
inline for (sizes) |exact_size| {
prng.seed(seed);
const result = try benchmarkHashSmallKeysArrayPtr(H, exact_size, count, allocator);
const result = try benchmarkHashSmallKeysArrayPtr(H, exact_size, count, allocator, io);
try stdout.print(" {d: >3}B {:5} MiB/s [{x:0<16}]\n", .{
exact_size,
result.throughput / (1 * MiB),
+14 -12
View File
@@ -2,7 +2,6 @@ const std = @import("std");
const Io = std.Io;
const time = std.time;
const unicode = std.unicode;
const Timer = std.time.Timer;
const N = 1_000_000;
@@ -15,12 +14,14 @@ const ResultCount = struct {
throughput: u64,
};
fn benchmarkCodepointCount(buf: []const u8) !ResultCount {
var timer = try Timer.start();
fn benchTime(io: Io) i96 {
return Io.Clock.awake.now(io).nanoseconds;
}
fn benchmarkCodepointCount(buf: []const u8, io: Io) !ResultCount {
const bytes = N * buf.len;
const start = timer.lap();
const start = benchTime(io);
var i: usize = 0;
var r: usize = undefined;
while (i < N) : (i += 1) {
@@ -30,7 +31,7 @@ fn benchmarkCodepointCount(buf: []const u8) !ResultCount {
.{buf},
);
}
const end = timer.read();
const end = benchTime(io);
const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s;
const throughput = @as(u64, @intFromFloat(@as(f64, @floatFromInt(bytes)) / elapsed_s));
@@ -38,44 +39,45 @@ fn benchmarkCodepointCount(buf: []const u8) !ResultCount {
return ResultCount{ .count = r, .throughput = throughput };
}
pub fn main() !void {
pub fn main(init: std.process.Init) !void {
// Size of buffer is about size of printed message.
const io = init.io;
var stdout_buffer: [0x100]u8 = undefined;
var stdout_writer = Io.File.stdout().writer(&stdout_buffer);
var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer);
const stdout = &stdout_writer.interface;
try stdout.print("short ASCII strings\n", .{});
try stdout.flush();
{
const result = try benchmarkCodepointCount("abc");
const result = try benchmarkCodepointCount("abc", io);
try stdout.print(" count: {:5} MiB/s [{d}]\n", .{ result.throughput / (1 * MiB), result.count });
}
try stdout.print("short Unicode strings\n", .{});
try stdout.flush();
{
const result = try benchmarkCodepointCount("ŌŌŌ");
const result = try benchmarkCodepointCount("ŌŌŌ", io);
try stdout.print(" count: {:5} MiB/s [{d}]\n", .{ result.throughput / (1 * MiB), result.count });
}
try stdout.print("pure ASCII strings\n", .{});
try stdout.flush();
{
const result = try benchmarkCodepointCount("hello" ** 16);
const result = try benchmarkCodepointCount("hello" ** 16, io);
try stdout.print(" count: {:5} MiB/s [{d}]\n", .{ result.throughput / (1 * MiB), result.count });
}
try stdout.print("pure Unicode strings\n", .{});
try stdout.flush();
{
const result = try benchmarkCodepointCount("こんにちは" ** 16);
const result = try benchmarkCodepointCount("こんにちは" ** 16, io);
try stdout.print(" count: {:5} MiB/s [{d}]\n", .{ result.throughput / (1 * MiB), result.count });
}
try stdout.print("mixed ASCII/Unicode strings\n", .{});
try stdout.flush();
{
const result = try benchmarkCodepointCount("Hyvää huomenta" ** 16);
const result = try benchmarkCodepointCount("Hyvää huomenta" ** 16, io);
try stdout.print(" count: {:5} MiB/s [{d}]\n", .{ result.throughput / (1 * MiB), result.count });
}
try stdout.flush();