authorgravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2019-08-21 21:54:12-10:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2019-08-21 21:54:12-10:00
log0e75fef1decdaba918b2abc84977ecadb010ad32
tree5dc1aedf188a2f8ce93109fab349cd54b31597da
parentec7d7a5b14540ea3b2bab9f11318630338467965
parent16fa255f48ae2d290bc26ceb41489f2c3e21b96d
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #3106 from ziglang/hash-tooling-changes

Hash tooling changes

9 files changed, 492 insertions(+), 362 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);...@@ -269,8 +269,8 @@ pub const Blake2b512 = Blake2b(512);
269fn Blake2b(comptime out_len: usize) type {269fn Blake2b(comptime out_len: usize) type {
270 return struct {270 return struct {
271 const Self = @This();271 const Self = @This();
272 const block_length = 128;272 pub const block_length = 128;
273 const digest_length = out_len / 8;273 pub const digest_length = out_len / 8;
274274
275 const iv = [8]u64{275 const iv = [8]u64{
276 0x6a09e667f3bcc908,276 0x6a09e667f3bcc908,
std/crypto/sha2.zig+2-2
...@@ -420,8 +420,8 @@ pub const Sha512 = Sha2_64(Sha512Params);...@@ -420,8 +420,8 @@ pub const Sha512 = Sha2_64(Sha512Params);
420fn Sha2_64(comptime params: Sha2Params64) type {420fn Sha2_64(comptime params: Sha2Params64) type {
421 return struct {421 return struct {
422 const Self = @This();422 const Self = @This();
423 const block_length = 128;423 pub const block_length = 128;
424 const digest_length = params.out_len / 8;424 pub const digest_length = params.out_len / 8;
425425
426 s: [8]u64,426 s: [8]u64,
427 // Streaming Cache427 // 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+273
...@@ -0,0 +1,273 @@
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 has_iterative_api: bool = true,
19 init_u8s: ?[]const u8 = null,
20 init_u64: ?u64 = null,
21};
22
23const siphash_key = "0123456789abcdef";
24
25const hashes = [_]Hash{
26 Hash{
27 .ty = hash.Wyhash,
28 .name = "wyhash",
29 .init_u64 = 0,
30 },
31 Hash{
32 .ty = hash.SipHash64(1, 3),
33 .name = "siphash(1,3)",
34 .init_u8s = siphash_key,
35 },
36 Hash{
37 .ty = hash.SipHash64(2, 4),
38 .name = "siphash(2,4)",
39 .init_u8s = siphash_key,
40 },
41 Hash{
42 .ty = hash.Fnv1a_64,
43 .name = "fnv1a",
44 },
45 Hash{
46 .ty = hash.Adler32,
47 .name = "adler32",
48 },
49 Hash{
50 .ty = hash.crc.Crc32WithPoly(.IEEE),
51 .name = "crc32-slicing-by-8",
52 },
53 Hash{
54 .ty = hash.crc.Crc32SmallWithPoly(.IEEE),
55 .name = "crc32-half-byte-lookup",
56 },
57 Hash{
58 .ty = hash.CityHash32,
59 .name = "cityhash-32",
60 .has_iterative_api = false,
61 },
62 Hash{
63 .ty = hash.CityHash64,
64 .name = "cityhash-64",
65 .has_iterative_api = false,
66 },
67 Hash{
68 .ty = hash.Murmur2_32,
69 .name = "murmur2-32",
70 .has_iterative_api = false,
71 },
72 Hash{
73 .ty = hash.Murmur2_64,
74 .name = "murmur2-64",
75 .has_iterative_api = false,
76 },
77 Hash{
78 .ty = hash.Murmur3_32,
79 .name = "murmur3-32",
80 .has_iterative_api = false,
81 },
82};
83
84const Result = struct {
85 hash: u64,
86 throughput: u64,
87};
88
89const block_size: usize = 8192;
90
91pub fn benchmarkHash(comptime H: var, bytes: usize) !Result {
92 var h = blk: {
93 if (H.init_u8s) |init| {
94 break :blk H.ty.init(init);
95 }
96 if (H.init_u64) |init| {
97 break :blk H.ty.init(init);
98 }
99 break :blk H.ty.init();
100 };
101
102 var block: [block_size]u8 = undefined;
103 prng.random.bytes(block[0..]);
104
105 var offset: usize = 0;
106 var timer = try Timer.start();
107 const start = timer.lap();
108 while (offset < bytes) : (offset += block.len) {
109 h.update(block[0..]);
110 }
111 const end = timer.read();
112
113 const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
114 const throughput = @floatToInt(u64, @intToFloat(f64, bytes) / elapsed_s);
115
116 return Result{
117 .hash = h.final(),
118 .throughput = throughput,
119 };
120}
121
122pub fn benchmarkHashSmallKeys(comptime H: var, key_size: usize, bytes: usize) !Result {
123 const key_count = bytes / key_size;
124 var block: [block_size]u8 = undefined;
125 prng.random.bytes(block[0..]);
126
127 var i: usize = 0;
128 var timer = try Timer.start();
129 const start = timer.lap();
130
131 var sum: u64 = 0;
132 while (i < key_count) : (i += 1) {
133 const small_key = block[0..key_size];
134 sum +%= blk: {
135 if (H.init_u8s) |init| {
136 break :blk H.ty.hash(init, small_key);
137 }
138 if (H.init_u64) |init| {
139 break :blk H.ty.hash(init, small_key);
140 }
141 break :blk H.ty.hash(small_key);
142 };
143 }
144 const end = timer.read();
145
146 const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
147 const throughput = @floatToInt(u64, @intToFloat(f64, bytes) / elapsed_s);
148
149 return Result{
150 .hash = sum,
151 .throughput = throughput,
152 };
153}
154
155fn usage() void {
156 std.debug.warn(
157 \\throughput_test [options]
158 \\
159 \\Options:
160 \\ --filter [test-name]
161 \\ --seed [int]
162 \\ --count [int]
163 \\ --key-size [int]
164 \\ --iterative-only
165 \\ --help
166 \\
167 );
168}
169
170fn mode(comptime x: comptime_int) comptime_int {
171 return if (builtin.mode == builtin.Mode.Debug) x / 64 else x;
172}
173
174// TODO(#1358): Replace with builtin formatted padding when available.
175fn printPad(stdout: var, s: []const u8) !void {
176 var i: usize = 0;
177 while (i < 12 - s.len) : (i += 1) {
178 try stdout.print(" ");
179 }
180 try stdout.print("{}", s);
181}
182
183pub fn main() !void {
184 var stdout_file = try std.io.getStdOut();
185 var stdout_out_stream = stdout_file.outStream();
186 const stdout = &stdout_out_stream.stream;
187
188 var buffer: [1024]u8 = undefined;
189 var fixed = std.heap.FixedBufferAllocator.init(buffer[0..]);
190 const args = try std.process.argsAlloc(&fixed.allocator);
191
192 var filter: ?[]u8 = "";
193 var count: usize = mode(128 * MiB);
194 var key_size: usize = 32;
195 var seed: u32 = 0;
196 var test_iterative_only = false;
197
198 var i: usize = 1;
199 while (i < args.len) : (i += 1) {
200 if (std.mem.eql(u8, args[i], "--mode")) {
201 try stdout.print("{}\n", builtin.mode);
202 return;
203 } else if (std.mem.eql(u8, args[i], "--seed")) {
204 i += 1;
205 if (i == args.len) {
206 usage();
207 std.os.exit(1);
208 }
209
210 seed = try std.fmt.parseUnsigned(u32, args[i], 10);
211 // we seed later
212 } else if (std.mem.eql(u8, args[i], "--filter")) {
213 i += 1;
214 if (i == args.len) {
215 usage();
216 std.os.exit(1);
217 }
218
219 filter = args[i];
220 } else if (std.mem.eql(u8, args[i], "--count")) {
221 i += 1;
222 if (i == args.len) {
223 usage();
224 std.os.exit(1);
225 }
226
227 const c = try std.fmt.parseUnsigned(usize, args[i], 10);
228 count = c * MiB;
229 } else if (std.mem.eql(u8, args[i], "--key-size")) {
230 i += 1;
231 if (i == args.len) {
232 usage();
233 std.os.exit(1);
234 }
235
236 key_size = try std.fmt.parseUnsigned(usize, args[i], 10);
237 if (key_size > block_size) {
238 try stdout.print("key_size cannot exceed block size of {}\n", block_size);
239 std.os.exit(1);
240 }
241 } else if (std.mem.eql(u8, args[i], "--iterative-only")) {
242 test_iterative_only = true;
243 } else if (std.mem.eql(u8, args[i], "--help")) {
244 usage();
245 return;
246 } else {
247 usage();
248 std.os.exit(1);
249 }
250 }
251
252 inline for (hashes) |H| {
253 if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) {
254 if (!test_iterative_only or H.has_iterative_api) {
255 try stdout.print("{}\n", H.name);
256
257 // Always reseed prior to every call so we are hashing the same buffer contents.
258 // This allows easier comparison between different implementations.
259 if (H.has_iterative_api) {
260 prng.seed(seed);
261 const result = try benchmarkHash(H, count);
262 try stdout.print(" iterative: {:4} MiB/s [{x:0<16}]\n", result.throughput / (1 * MiB), result.hash);
263 }
264
265 if (!test_iterative_only) {
266 prng.seed(seed);
267 const result_small = try benchmarkHashSmallKeys(H, key_size, count);
268 try stdout.print(" small keys: {:4} MiB/s [{x:0<16}]\n", result_small.throughput / (1 * MiB), result_small.hash);
269 }
270 }
271 }
272 }
273}
std/hash/crc.zig+13-13
...@@ -9,17 +9,17 @@ const std = @import("../std.zig");...@@ -9,17 +9,17 @@ const std = @import("../std.zig");
9const debug = std.debug;9const debug = std.debug;
10const testing = std.testing;10const testing = std.testing;
1111
12pub const Polynomial = struct {12pub const Polynomial = enum(u32) {
13 const IEEE = 0xedb88320;13 IEEE = 0xedb88320,
14 const Castagnoli = 0x82f63b78;14 Castagnoli = 0x82f63b78,
15 const Koopman = 0xeb31d82e;15 Koopman = 0xeb31d82e,
16};16};
1717
18// IEEE is by far the most common CRC and so is aliased by default.18// IEEE is by far the most common CRC and so is aliased by default.
19pub const Crc32 = Crc32WithPoly(Polynomial.IEEE);19pub const Crc32 = Crc32WithPoly(.IEEE);
2020
21// slicing-by-8 crc32 implementation.21// slicing-by-8 crc32 implementation.
22pub fn Crc32WithPoly(comptime poly: u32) type {22pub fn Crc32WithPoly(comptime poly: Polynomial) type {
23 return struct {23 return struct {
24 const Self = @This();24 const Self = @This();
25 const lookup_tables = comptime block: {25 const lookup_tables = comptime block: {
...@@ -31,7 +31,7 @@ pub fn Crc32WithPoly(comptime poly: u32) type {...@@ -31,7 +31,7 @@ pub fn Crc32WithPoly(comptime poly: u32) type {
31 var j: usize = 0;31 var j: usize = 0;
32 while (j < 8) : (j += 1) {32 while (j < 8) : (j += 1) {
33 if (crc & 1 == 1) {33 if (crc & 1 == 1) {
34 crc = (crc >> 1) ^ poly;34 crc = (crc >> 1) ^ @enumToInt(poly);
35 } else {35 } else {
36 crc = (crc >> 1);36 crc = (crc >> 1);
37 }37 }
...@@ -100,7 +100,7 @@ pub fn Crc32WithPoly(comptime poly: u32) type {...@@ -100,7 +100,7 @@ pub fn Crc32WithPoly(comptime poly: u32) type {
100}100}
101101
102test "crc32 ieee" {102test "crc32 ieee" {
103 const Crc32Ieee = Crc32WithPoly(Polynomial.IEEE);103 const Crc32Ieee = Crc32WithPoly(.IEEE);
104104
105 testing.expect(Crc32Ieee.hash("") == 0x00000000);105 testing.expect(Crc32Ieee.hash("") == 0x00000000);
106 testing.expect(Crc32Ieee.hash("a") == 0xe8b7be43);106 testing.expect(Crc32Ieee.hash("a") == 0xe8b7be43);
...@@ -108,7 +108,7 @@ test "crc32 ieee" {...@@ -108,7 +108,7 @@ test "crc32 ieee" {
108}108}
109109
110test "crc32 castagnoli" {110test "crc32 castagnoli" {
111 const Crc32Castagnoli = Crc32WithPoly(Polynomial.Castagnoli);111 const Crc32Castagnoli = Crc32WithPoly(.Castagnoli);
112112
113 testing.expect(Crc32Castagnoli.hash("") == 0x00000000);113 testing.expect(Crc32Castagnoli.hash("") == 0x00000000);
114 testing.expect(Crc32Castagnoli.hash("a") == 0xc1d04330);114 testing.expect(Crc32Castagnoli.hash("a") == 0xc1d04330);
...@@ -116,7 +116,7 @@ test "crc32 castagnoli" {...@@ -116,7 +116,7 @@ test "crc32 castagnoli" {
116}116}
117117
118// half-byte lookup table implementation.118// half-byte lookup table implementation.
119pub fn Crc32SmallWithPoly(comptime poly: u32) type {119pub fn Crc32SmallWithPoly(comptime poly: Polynomial) type {
120 return struct {120 return struct {
121 const Self = @This();121 const Self = @This();
122 const lookup_table = comptime block: {122 const lookup_table = comptime block: {
...@@ -127,7 +127,7 @@ pub fn Crc32SmallWithPoly(comptime poly: u32) type {...@@ -127,7 +127,7 @@ pub fn Crc32SmallWithPoly(comptime poly: u32) type {
127 var j: usize = 0;127 var j: usize = 0;
128 while (j < 8) : (j += 1) {128 while (j < 8) : (j += 1) {
129 if (crc & 1 == 1) {129 if (crc & 1 == 1) {
130 crc = (crc >> 1) ^ poly;130 crc = (crc >> 1) ^ @enumToInt(poly);
131 } else {131 } else {
132 crc = (crc >> 1);132 crc = (crc >> 1);
133 }133 }
...@@ -164,7 +164,7 @@ pub fn Crc32SmallWithPoly(comptime poly: u32) type {...@@ -164,7 +164,7 @@ pub fn Crc32SmallWithPoly(comptime poly: u32) type {
164}164}
165165
166test "small crc32 ieee" {166test "small crc32 ieee" {
167 const Crc32Ieee = Crc32SmallWithPoly(Polynomial.IEEE);167 const Crc32Ieee = Crc32SmallWithPoly(.IEEE);
168168
169 testing.expect(Crc32Ieee.hash("") == 0x00000000);169 testing.expect(Crc32Ieee.hash("") == 0x00000000);
170 testing.expect(Crc32Ieee.hash("a") == 0xe8b7be43);170 testing.expect(Crc32Ieee.hash("a") == 0xe8b7be43);
...@@ -172,7 +172,7 @@ test "small crc32 ieee" {...@@ -172,7 +172,7 @@ test "small crc32 ieee" {
172}172}
173173
174test "small crc32 castagnoli" {174test "small crc32 castagnoli" {
175 const Crc32Castagnoli = Crc32SmallWithPoly(Polynomial.Castagnoli);175 const Crc32Castagnoli = Crc32SmallWithPoly(.Castagnoli);
176176
177 testing.expect(Crc32Castagnoli.hash("") == 0x00000000);177 testing.expect(Crc32Castagnoli.hash("") == 0x00000000);
178 testing.expect(Crc32Castagnoli.hash("a") == 0xc1d04330);178 testing.expect(Crc32Castagnoli.hash("a") == 0xc1d04330);
std/hash/siphash.zig+2-2
...@@ -152,8 +152,8 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)...@@ -152,8 +152,8 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
152152
153 pub fn hash(key: []const u8, input: []const u8) T {153 pub fn hash(key: []const u8, input: []const u8) T {
154 var c = Self.init(key);154 var c = Self.init(key);
155 c.update(input);155 @inlineCall(c.update, input);
156 return c.final();156 return @inlineCall(c.final);
157 }157 }
158 };158 };
159}159}
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}
std/hash/wyhash.zig+2-2
...@@ -116,8 +116,8 @@ pub const Wyhash = struct {...@@ -116,8 +116,8 @@ pub const Wyhash = struct {
116116
117 pub fn hash(seed: u64, input: []const u8) u64 {117 pub fn hash(seed: u64, input: []const u8) u64 {
118 var c = Wyhash.init(seed);118 var c = Wyhash.init(seed);
119 c.update(input);119 @inlineCall(c.update, input);
120 return c.final();120 return @inlineCall(c.final);
121 }121 }
122};122};
123123