authorgravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2019-08-21 20:34:12+12:00
committergravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2019-08-21 20:34:12+12:00
logc050ec4e570caf53be924bcbbe4194512b6a022c
treea5029647e87850bdb9239662fcaf01da0476877b
parent81c441f8855d4c58f0b2ff86d3d007cf0bf395d3

Update hash/crypto benchmark scripts


6 files changed, 410 insertions(+), 345 deletions(-)

std/crypto/benchmark.zig created+198
......@@ -0,0 +1,198 @@
1// zig run benchmark.zig --release-fast --override-std-dir ..
2
3const builtin = @import("builtin");
4const std = @import("../std.zig");
5const time = std.time;
6const Timer = time.Timer;
7const crypto = std.crypto;
8
9const KiB = 1024;
10const MiB = 1024 * KiB;
11
12var prng = std.rand.DefaultPrng.init(0);
13
14const Crypto = struct {
15 ty: type,
16 name: []const u8,
17};
18
19const hashes = [_]Crypto{
20 Crypto{ .ty = crypto.Md5, .name = "md5" },
21 Crypto{ .ty = crypto.Sha1, .name = "sha1" },
22 Crypto{ .ty = crypto.Sha256, .name = "sha256" },
23 Crypto{ .ty = crypto.Sha512, .name = "sha512" },
24 Crypto{ .ty = crypto.Sha3_256, .name = "sha3-256" },
25 Crypto{ .ty = crypto.Sha3_512, .name = "sha3-512" },
26 Crypto{ .ty = crypto.Blake2s256, .name = "blake2s" },
27 Crypto{ .ty = crypto.Blake2b512, .name = "blake2b" },
28};
29
30pub fn benchmarkHash(comptime Hash: var, comptime bytes: comptime_int) !u64 {
31 var h = Hash.init();
32
33 var block: [Hash.digest_length]u8 = undefined;
34 prng.random.bytes(block[0..]);
35
36 var offset: usize = 0;
37 var timer = try Timer.start();
38 const start = timer.lap();
39 while (offset < bytes) : (offset += block.len) {
40 h.update(block[0..]);
41 }
42 const end = timer.read();
43
44 const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
45 const throughput = @floatToInt(u64, bytes / elapsed_s);
46
47 return throughput;
48}
49
50const macs = [_]Crypto{
51 Crypto{ .ty = crypto.Poly1305, .name = "poly1305" },
52 Crypto{ .ty = crypto.HmacMd5, .name = "hmac-md5" },
53 Crypto{ .ty = crypto.HmacSha1, .name = "hmac-sha1" },
54 Crypto{ .ty = crypto.HmacSha256, .name = "hmac-sha256" },
55};
56
57pub fn benchmarkMac(comptime Mac: var, comptime bytes: comptime_int) !u64 {
58 std.debug.assert(32 >= Mac.mac_length and 32 >= Mac.minimum_key_length);
59
60 var in: [1 * MiB]u8 = undefined;
61 prng.random.bytes(in[0..]);
62
63 var key: [32]u8 = undefined;
64 prng.random.bytes(key[0..]);
65
66 var offset: usize = 0;
67 var timer = try Timer.start();
68 const start = timer.lap();
69 while (offset < bytes) : (offset += in.len) {
70 Mac.create(key[0..], in[0..], key);
71 }
72 const end = timer.read();
73
74 const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
75 const throughput = @floatToInt(u64, bytes / elapsed_s);
76
77 return throughput;
78}
79
80const exchanges = [_]Crypto{Crypto{ .ty = crypto.X25519, .name = "x25519" }};
81
82pub fn benchmarkKeyExchange(comptime DhKeyExchange: var, comptime exchange_count: comptime_int) !u64 {
83 std.debug.assert(DhKeyExchange.minimum_key_length >= DhKeyExchange.secret_length);
84
85 var in: [DhKeyExchange.minimum_key_length]u8 = undefined;
86 prng.random.bytes(in[0..]);
87
88 var out: [DhKeyExchange.minimum_key_length]u8 = undefined;
89 prng.random.bytes(out[0..]);
90
91 var offset: usize = 0;
92 var timer = try Timer.start();
93 const start = timer.lap();
94 {
95 var i: usize = 0;
96 while (i < exchange_count) : (i += 1) {
97 _ = DhKeyExchange.create(out[0..], out, in);
98 }
99 }
100 const end = timer.read();
101
102 const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
103 const throughput = @floatToInt(u64, exchange_count / elapsed_s);
104
105 return throughput;
106}
107
108fn usage() void {
109 std.debug.warn(
110 \\throughput_test [options]
111 \\
112 \\Options:
113 \\ --filter [test-name]
114 \\ --seed [int]
115 \\ --help
116 \\
117 );
118}
119
120fn mode(comptime x: comptime_int) comptime_int {
121 return if (builtin.mode == builtin.Mode.Debug) x / 64 else x;
122}
123
124// TODO(#1358): Replace with builtin formatted padding when available.
125fn printPad(stdout: var, s: []const u8) !void {
126 var i: usize = 0;
127 while (i < 12 - s.len) : (i += 1) {
128 try stdout.print(" ");
129 }
130 try stdout.print("{}", s);
131}
132
133pub fn main() !void {
134 var stdout_file = try std.io.getStdOut();
135 var stdout_out_stream = stdout_file.outStream();
136 const stdout = &stdout_out_stream.stream;
137
138 var buffer: [1024]u8 = undefined;
139 var fixed = std.heap.FixedBufferAllocator.init(buffer[0..]);
140 const args = try std.process.argsAlloc(&fixed.allocator);
141
142 var filter: ?[]u8 = "";
143
144 var i: usize = 1;
145 while (i < args.len) : (i += 1) {
146 if (std.mem.eql(u8, args[i], "--mode")) {
147 try stdout.print("{}\n", builtin.mode);
148 return;
149 } else if (std.mem.eql(u8, args[i], "--seed")) {
150 i += 1;
151 if (i == args.len) {
152 usage();
153 std.os.exit(1);
154 }
155
156 const seed = try std.fmt.parseUnsigned(u32, args[i], 10);
157 prng.seed(seed);
158 } else if (std.mem.eql(u8, args[i], "--filter")) {
159 i += 1;
160 if (i == args.len) {
161 usage();
162 std.os.exit(1);
163 }
164
165 filter = args[i];
166 } else if (std.mem.eql(u8, args[i], "--help")) {
167 usage();
168 return;
169 } else {
170 usage();
171 std.os.exit(1);
172 }
173 }
174
175 inline for (hashes) |H| {
176 if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) {
177 const throughput = try benchmarkHash(H.ty, mode(32 * MiB));
178 try printPad(stdout, H.name);
179 try stdout.print(": {} MiB/s\n", throughput / (1 * MiB));
180 }
181 }
182
183 inline for (macs) |M| {
184 if (filter == null or std.mem.indexOf(u8, M.name, filter.?) != null) {
185 const throughput = try benchmarkMac(M.ty, mode(128 * MiB));
186 try printPad(stdout, M.name);
187 try stdout.print(": {} MiB/s\n", throughput / (1 * MiB));
188 }
189 }
190
191 inline for (exchanges) |E| {
192 if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
193 const throughput = try benchmarkKeyExchange(E.ty, mode(1000));
194 try printPad(stdout, E.name);
195 try stdout.print(": {} exchanges/s\n", throughput);
196 }
197 }
198}
std/crypto/blake2.zig+2-2
......@@ -269,8 +269,8 @@ pub const Blake2b512 = Blake2b(512);
269269fn Blake2b(comptime out_len: usize) type {
270270 return struct {
271271 const Self = @This();
272 const block_length = 128;
273 const digest_length = out_len / 8;
272 pub const block_length = 128;
273 pub const digest_length = out_len / 8;
274274
275275 const iv = [8]u64{
276276 0x6a09e667f3bcc908,
std/crypto/sha2.zig+2-2
......@@ -420,8 +420,8 @@ pub const Sha512 = Sha2_64(Sha512Params);
420420fn Sha2_64(comptime params: Sha2Params64) type {
421421 return struct {
422422 const Self = @This();
423 const block_length = 128;
424 const digest_length = params.out_len / 8;
423 pub const block_length = 128;
424 pub const digest_length = params.out_len / 8;
425425
426426 s: [8]u64,
427427 // Streaming Cache
std/crypto/throughput_test.zig deleted-193
......@@ -1,193 +0,0 @@
1const builtin = @import("builtin");
2const std = @import("std");
3const time = std.time;
4const Timer = time.Timer;
5const crypto = @import("../crypto.zig");
6
7const KiB = 1024;
8const MiB = 1024 * KiB;
9
10var prng = std.rand.DefaultPrng.init(0);
11
12const Crypto = struct {
13 ty: type,
14 name: []const u8,
15};
16
17const hashes = []Crypto{
18 Crypto{ .ty = crypto.Md5, .name = "md5" },
19 Crypto{ .ty = crypto.Sha1, .name = "sha1" },
20 Crypto{ .ty = crypto.Sha256, .name = "sha256" },
21 Crypto{ .ty = crypto.Sha512, .name = "sha512" },
22 Crypto{ .ty = crypto.Sha3_256, .name = "sha3-256" },
23 Crypto{ .ty = crypto.Sha3_512, .name = "sha3-512" },
24 Crypto{ .ty = crypto.Blake2s256, .name = "blake2s" },
25 Crypto{ .ty = crypto.Blake2b512, .name = "blake2b" },
26};
27
28pub fn benchmarkHash(comptime Hash: var, comptime bytes: comptime_int) !u64 {
29 var h = Hash.init();
30
31 var block: [Hash.digest_length]u8 = undefined;
32 prng.random.bytes(block[0..]);
33
34 var offset: usize = 0;
35 var timer = try Timer.start();
36 const start = timer.lap();
37 while (offset < bytes) : (offset += block.len) {
38 h.update(block[0..]);
39 }
40 const end = timer.read();
41
42 const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
43 const throughput = @floatToInt(u64, bytes / elapsed_s);
44
45 return throughput;
46}
47
48const macs = []Crypto{
49 Crypto{ .ty = crypto.Poly1305, .name = "poly1305" },
50 Crypto{ .ty = crypto.HmacMd5, .name = "hmac-md5" },
51 Crypto{ .ty = crypto.HmacSha1, .name = "hmac-sha1" },
52 Crypto{ .ty = crypto.HmacSha256, .name = "hmac-sha256" },
53};
54
55pub fn benchmarkMac(comptime Mac: var, comptime bytes: comptime_int) !u64 {
56 std.debug.assert(32 >= Mac.mac_length and 32 >= Mac.minimum_key_length);
57
58 var in: [1 * MiB]u8 = undefined;
59 prng.random.bytes(in[0..]);
60
61 var key: [32]u8 = undefined;
62 prng.random.bytes(key[0..]);
63
64 var offset: usize = 0;
65 var timer = try Timer.start();
66 const start = timer.lap();
67 while (offset < bytes) : (offset += in.len) {
68 Mac.create(key[0..], in[0..], key);
69 }
70 const end = timer.read();
71
72 const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
73 const throughput = @floatToInt(u64, bytes / elapsed_s);
74
75 return throughput;
76}
77
78const exchanges = []Crypto{Crypto{ .ty = crypto.X25519, .name = "x25519" }};
79
80pub fn benchmarkKeyExchange(comptime DhKeyExchange: var, comptime exchange_count: comptime_int) !u64 {
81 std.debug.assert(DhKeyExchange.minimum_key_length >= DhKeyExchange.secret_length);
82
83 var in: [DhKeyExchange.minimum_key_length]u8 = undefined;
84 prng.random.bytes(in[0..]);
85
86 var out: [DhKeyExchange.minimum_key_length]u8 = undefined;
87 prng.random.bytes(out[0..]);
88
89 var offset: usize = 0;
90 var timer = try Timer.start();
91 const start = timer.lap();
92 {
93 var i: usize = 0;
94 while (i < exchange_count) : (i += 1) {
95 _ = DhKeyExchange.create(out[0..], out, in);
96 }
97 }
98 const end = timer.read();
99
100 const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
101 const throughput = @floatToInt(u64, exchange_count / elapsed_s);
102
103 return throughput;
104}
105
106fn usage() void {
107 std.debug.warn(
108 \\throughput_test [options]
109 \\
110 \\Options:
111 \\ --filter [test-name]
112 \\ --seed [int]
113 \\ --help
114 \\
115 );
116}
117
118fn mode(comptime x: comptime_int) comptime_int {
119 return if (builtin.mode == builtin.Mode.Debug) x / 64 else x;
120}
121
122// TODO(#1358): Replace with builtin formatted padding when available.
123fn printPad(stdout: var, s: []const u8) !void {
124 var i: usize = 0;
125 while (i < 12 - s.len) : (i += 1) {
126 try stdout.print(" ");
127 }
128 try stdout.print("{}", s);
129}
130
131pub fn main() !void {
132 var stdout_file = try std.io.getStdOut();
133 var stdout_out_stream = stdout_file.outStream();
134 const stdout = &stdout_out_stream.stream;
135
136 var buffer: [1024]u8 = undefined;
137 var fixed = std.heap.FixedBufferAllocator.init(buffer[0..]);
138 const args = try std.os.argsAlloc(&fixed.allocator);
139
140 var filter: ?[]u8 = "";
141
142 var i: usize = 1;
143 while (i < args.len) : (i += 1) {
144 if (std.mem.eql(u8, args[i], "--seed")) {
145 i += 1;
146 if (i == args.len) {
147 usage();
148 std.os.exit(1);
149 }
150
151 const seed = try std.fmt.parseUnsigned(u32, args[i], 10);
152 prng.seed(seed);
153 } else if (std.mem.eql(u8, args[i], "--filter")) {
154 i += 1;
155 if (i == args.len) {
156 usage();
157 std.os.exit(1);
158 }
159
160 filter = args[i];
161 } else if (std.mem.eql(u8, args[i], "--help")) {
162 usage();
163 return;
164 } else {
165 usage();
166 std.os.exit(1);
167 }
168 }
169
170 inline for (hashes) |H| {
171 if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) {
172 const throughput = try benchmarkHash(H.ty, mode(32 * MiB));
173 try printPad(stdout, H.name);
174 try stdout.print(": {} MiB/s\n", throughput / (1 * MiB));
175 }
176 }
177
178 inline for (macs) |M| {
179 if (filter == null or std.mem.indexOf(u8, M.name, filter.?) != null) {
180 const throughput = try benchmarkMac(M.ty, mode(128 * MiB));
181 try printPad(stdout, M.name);
182 try stdout.print(": {} MiB/s\n", throughput / (1 * MiB));
183 }
184 }
185
186 inline for (exchanges) |E| {
187 if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
188 const throughput = try benchmarkKeyExchange(E.ty, mode(1000));
189 try printPad(stdout, E.name);
190 try stdout.print(": {} exchanges/s\n", throughput);
191 }
192 }
193}
std/hash/benchmark.zig created+208
......@@ -0,0 +1,208 @@
1// zig run benchmark.zig --release-fast --override-std-dir ..
2
3const builtin = @import("builtin");
4const std = @import("std");
5const time = std.time;
6const Timer = time.Timer;
7const hash = std.hash;
8
9const KiB = 1024;
10const MiB = 1024 * KiB;
11const GiB = 1024 * MiB;
12
13var prng = std.rand.DefaultPrng.init(0);
14
15const Hash = struct {
16 ty: type,
17 name: []const u8,
18 init_u8s: ?[]const u8 = null,
19 init_u64: ?u64 = null,
20};
21
22const siphash_key = "0123456789abcdef";
23
24const hashes = [_]Hash{
25 Hash{ .ty = hash.Wyhash, .name = "wyhash", .init_u64 = 0 },
26 Hash{ .ty = hash.SipHash64(1, 3), .name = "siphash(1,3)", .init_u8s = siphash_key },
27 Hash{ .ty = hash.SipHash64(2, 4), .name = "siphash(2,4)", .init_u8s = siphash_key },
28 Hash{ .ty = hash.Fnv1a_64, .name = "fnv1a" },
29 Hash{ .ty = hash.Crc32, .name = "crc32" },
30};
31
32const Result = struct {
33 hash: u64,
34 throughput: u64,
35};
36
37const block_size: usize = 8192;
38
39pub fn benchmarkHash(comptime H: var, bytes: usize) !Result {
40 var h = blk: {
41 if (H.init_u8s) |init| {
42 break :blk H.ty.init(init);
43 }
44 if (H.init_u64) |init| {
45 break :blk H.ty.init(init);
46 }
47 break :blk H.ty.init();
48 };
49
50 var block: [block_size]u8 = undefined;
51 prng.random.bytes(block[0..]);
52
53 var offset: usize = 0;
54 var timer = try Timer.start();
55 const start = timer.lap();
56 while (offset < bytes) : (offset += block.len) {
57 h.update(block[0..]);
58 }
59 const end = timer.read();
60
61 const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
62 const throughput = @floatToInt(u64, @intToFloat(f64, bytes) / elapsed_s);
63
64 return Result{
65 .hash = h.final(),
66 .throughput = throughput,
67 };
68}
69
70pub fn benchmarkHashSmallKeys(comptime H: var, key_size: usize, bytes: usize) !Result {
71 const key_count = bytes / key_size;
72 var block: [block_size]u8 = undefined;
73 prng.random.bytes(block[0..]);
74
75 var i: usize = 0;
76 var timer = try Timer.start();
77 const start = timer.lap();
78
79 var sum: u64 = 0;
80 while (i < key_count) : (i += 1) {
81 const o = i % (block_size - key_size);
82 const small_key = block[o .. key_size + o];
83
84 const result = blk: {
85 if (H.init_u8s) |init| {
86 break :blk H.ty.hash(init, small_key);
87 }
88 if (H.init_u64) |init| {
89 break :blk H.ty.hash(init, small_key);
90 }
91 break :blk H.ty.hash(small_key);
92 };
93
94 sum +%= result;
95 }
96 const end = timer.read();
97
98 const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
99 const throughput = @floatToInt(u64, @intToFloat(f64, bytes) / elapsed_s);
100
101 return Result{
102 .hash = sum,
103 .throughput = throughput,
104 };
105}
106
107fn usage() void {
108 std.debug.warn(
109 \\throughput_test [options]
110 \\
111 \\Options:
112 \\ --filter [test-name]
113 \\ --seed [int]
114 \\ --count [int]
115 \\ --help
116 \\
117 );
118}
119
120fn mode(comptime x: comptime_int) comptime_int {
121 return if (builtin.mode == builtin.Mode.Debug) x / 64 else x;
122}
123
124// TODO(#1358): Replace with builtin formatted padding when available.
125fn printPad(stdout: var, s: []const u8) !void {
126 var i: usize = 0;
127 while (i < 12 - s.len) : (i += 1) {
128 try stdout.print(" ");
129 }
130 try stdout.print("{}", s);
131}
132
133pub fn main() !void {
134 var stdout_file = try std.io.getStdOut();
135 var stdout_out_stream = stdout_file.outStream();
136 const stdout = &stdout_out_stream.stream;
137
138 var buffer: [1024]u8 = undefined;
139 var fixed = std.heap.FixedBufferAllocator.init(buffer[0..]);
140 const args = try std.process.argsAlloc(&fixed.allocator);
141
142 var filter: ?[]u8 = "";
143 var count: usize = mode(128 * MiB);
144 var key_size: usize = 32;
145
146 var i: usize = 1;
147 while (i < args.len) : (i += 1) {
148 if (std.mem.eql(u8, args[i], "--mode")) {
149 try stdout.print("{}\n", builtin.mode);
150 return;
151 } else if (std.mem.eql(u8, args[i], "--seed")) {
152 i += 1;
153 if (i == args.len) {
154 usage();
155 std.os.exit(1);
156 }
157
158 const seed = try std.fmt.parseUnsigned(u32, args[i], 10);
159 prng.seed(seed);
160 } else if (std.mem.eql(u8, args[i], "--filter")) {
161 i += 1;
162 if (i == args.len) {
163 usage();
164 std.os.exit(1);
165 }
166
167 filter = args[i];
168 } else if (std.mem.eql(u8, args[i], "--count")) {
169 i += 1;
170 if (i == args.len) {
171 usage();
172 std.os.exit(1);
173 }
174
175 const c = try std.fmt.parseUnsigned(usize, args[i], 10);
176 count = c * MiB;
177 } else if (std.mem.eql(u8, args[i], "--key-size")) {
178 i += 1;
179 if (i == args.len) {
180 usage();
181 std.os.exit(1);
182 }
183
184 key_size = try std.fmt.parseUnsigned(usize, args[i], 10);
185 if (key_size > block_size) {
186 try stdout.print("key_size cannot exceed block size of {}\n", block_size);
187 std.os.exit(1);
188 }
189 } else if (std.mem.eql(u8, args[i], "--help")) {
190 usage();
191 return;
192 } else {
193 usage();
194 std.os.exit(1);
195 }
196 }
197
198 inline for (hashes) |H| {
199 if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) {
200 const result = try benchmarkHash(H, count);
201 const result_small = try benchmarkHashSmallKeys(H, key_size, count);
202
203 try stdout.print("{}\n", H.name);
204 try stdout.print(" iterative: {:4} MiB/s [{x:0<16}]\n", result.throughput / (1 * MiB), result.hash);
205 try stdout.print(" small keys: {:4} MiB/s [{x:0<16}]\n", result_small.throughput / (1 * MiB), result_small.hash);
206 }
207 }
208}
std/hash/throughput_test.zig deleted-148
......@@ -1,148 +0,0 @@
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}