authorgravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2019-07-01 23:23:40+12:00
committergravatar for sahnvour@pm.meSahnvour <sahnvour@pm.me> 2019-08-04 12:34:05+02:00
log4c93ccab5ad48ce61e4136c646b3123a06150083
tree256394346723773b1bd948c254c68db63f96fd1f
parent83dffc70afe4956c56f570ce5c854b17cbd6f218

Add throughput test program for hash functions


1 files changed, 148 insertions(+), 0 deletions(-)

std/hash/throughput_test.zig created+148
......@@ -0,0 +1,148 @@
1const builtin = @import("builtin");
2const std = @import("std");
3const time = std.time;
4const Timer = time.Timer;
5const hash = std.hash;
6
7const KiB = 1024;
8const MiB = 1024 * KiB;
9const GiB = 1024 * MiB;
10
11var prng = std.rand.DefaultPrng.init(0);
12
13const Hash = struct {
14 ty: type,
15 name: []const u8,
16 init_u8s: ?[]const u8 = null,
17 init_u64: ?u64 = null,
18};
19
20const siphash_key = "0123456789abcdef";
21
22const hashes = [_]Hash{
23 Hash{ .ty = hash.Wyhash, .name = "wyhash", .init_u64 = 0 },
24 Hash{ .ty = hash.SipHash64(1, 3), .name = "siphash(1,3)", .init_u8s = siphash_key },
25 Hash{ .ty = hash.SipHash64(2, 4), .name = "siphash(2,4)", .init_u8s = siphash_key },
26 Hash{ .ty = hash.Fnv1a_64, .name = "fnv1a" },
27 Hash{ .ty = hash.Crc32, .name = "crc32" },
28};
29
30const Result = struct {
31 hash: u64,
32 throughput: u64,
33};
34
35pub fn benchmarkHash(comptime H: var, bytes: usize) !Result {
36 var h = blk: {
37 if (H.init_u8s) |init| {
38 break :blk H.ty.init(init);
39 }
40 if (H.init_u64) |init| {
41 break :blk H.ty.init(init);
42 }
43 break :blk H.ty.init();
44 };
45
46 var block: [8192]u8 = undefined;
47 prng.random.bytes(block[0..]);
48
49 var offset: usize = 0;
50 var timer = try Timer.start();
51 const start = timer.lap();
52 while (offset < bytes) : (offset += block.len) {
53 h.update(block[0..]);
54 }
55 const end = timer.read();
56
57 const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
58 const throughput = @floatToInt(u64, @intToFloat(f64, bytes) / elapsed_s);
59
60 return Result{
61 .hash = h.final(),
62 .throughput = throughput,
63 };
64}
65
66fn usage() void {
67 std.debug.warn(
68 \\throughput_test [options]
69 \\
70 \\Options:
71 \\ --filter [test-name]
72 \\ --seed [int]
73 \\ --count [int]
74 \\ --help
75 \\
76 );
77}
78
79fn mode(comptime x: comptime_int) comptime_int {
80 return if (builtin.mode == builtin.Mode.Debug) x / 64 else x;
81}
82
83// TODO(#1358): Replace with builtin formatted padding when available.
84fn printPad(stdout: var, s: []const u8) !void {
85 var i: usize = 0;
86 while (i < 12 - s.len) : (i += 1) {
87 try stdout.print(" ");
88 }
89 try stdout.print("{}", s);
90}
91
92pub fn main() !void {
93 var stdout_file = try std.io.getStdOut();
94 var stdout_out_stream = stdout_file.outStream();
95 const stdout = &stdout_out_stream.stream;
96
97 var buffer: [1024]u8 = undefined;
98 var fixed = std.heap.FixedBufferAllocator.init(buffer[0..]);
99 const args = try std.process.argsAlloc(&fixed.allocator);
100
101 var filter: ?[]u8 = "";
102 var count: usize = mode(128 * MiB);
103
104 var i: usize = 1;
105 while (i < args.len) : (i += 1) {
106 if (std.mem.eql(u8, args[i], "--seed")) {
107 i += 1;
108 if (i == args.len) {
109 usage();
110 std.os.exit(1);
111 }
112
113 const seed = try std.fmt.parseUnsigned(u32, args[i], 10);
114 prng.seed(seed);
115 } else if (std.mem.eql(u8, args[i], "--filter")) {
116 i += 1;
117 if (i == args.len) {
118 usage();
119 std.os.exit(1);
120 }
121
122 filter = args[i];
123 } else if (std.mem.eql(u8, args[i], "--count")) {
124 i += 1;
125 if (i == args.len) {
126 usage();
127 std.os.exit(1);
128 }
129
130 const c = try std.fmt.parseUnsigned(u32, args[i], 10);
131 count = c * MiB;
132 } else if (std.mem.eql(u8, args[i], "--help")) {
133 usage();
134 return;
135 } else {
136 usage();
137 std.os.exit(1);
138 }
139 }
140
141 inline for (hashes) |H| {
142 if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) {
143 const result = try benchmarkHash(H, count);
144 try printPad(stdout, H.name);
145 try stdout.print(": {:4} MiB/s [{:16}]\n", result.throughput / (1 * MiB), result.hash);
146 }
147 }
148}