| ... | @@ -21,6 +21,14 @@ const Crypto = struct { | ... | @@ -21,6 +21,14 @@ const Crypto = struct { |
| 21 | name: []const u8, | 21 | name: []const u8, |
| 22 | }; | 22 | }; |
| 23 | | 23 | |
| | 24 | fn blackBox(x: anytype) void { |
| | 25 | asm volatile ("" |
| | 26 | : |
| | 27 | : [x] "rm" (x) |
| | 28 | : "memory" |
| | 29 | ); |
| | 30 | } |
| | 31 | |
| 24 | const hashes = [_]Crypto{ | 32 | const hashes = [_]Crypto{ |
| 25 | Crypto{ .ty = crypto.hash.Md5, .name = "md5" }, | 33 | Crypto{ .ty = crypto.hash.Md5, .name = "md5" }, |
| 26 | Crypto{ .ty = crypto.hash.Sha1, .name = "sha1" }, | 34 | Crypto{ .ty = crypto.hash.Sha1, .name = "sha1" }, |
| ... | @@ -46,6 +54,7 @@ pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64 | ... | @@ -46,6 +54,7 @@ pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64 |
| 46 | while (offset < bytes) : (offset += block.len) { | 54 | while (offset < bytes) : (offset += block.len) { |
| 47 | h.update(block[0..]); | 55 | h.update(block[0..]); |
| 48 | } | 56 | } |
| | 57 | blackBox(&h); |
| 49 | const end = timer.read(); | 58 | const end = timer.read(); |
| 50 | | 59 | |
| 51 | const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s; | 60 | const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s; |
| ... | @@ -67,19 +76,20 @@ const macs = [_]Crypto{ | ... | @@ -67,19 +76,20 @@ const macs = [_]Crypto{ |
| 67 | }; | 76 | }; |
| 68 | | 77 | |
| 69 | pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 { | 78 | pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 { |
| 70 | std.debug.assert(64 >= Mac.mac_length and 32 >= Mac.minimum_key_length); | 79 | var in: [512 * KiB]u8 = undefined; |
| 71 | | | |
| 72 | var in: [1 * MiB]u8 = undefined; | | |
| 73 | prng.random.bytes(in[0..]); | 80 | prng.random.bytes(in[0..]); |
| 74 | | 81 | |
| 75 | var key: [64]u8 = undefined; | 82 | const key_length = if (Mac.minimum_key_length == 0) 32 else Mac.minimum_key_length; |
| | 83 | var key: [key_length]u8 = undefined; |
| 76 | prng.random.bytes(key[0..]); | 84 | prng.random.bytes(key[0..]); |
| 77 | | 85 | |
| | 86 | var mac: [Mac.mac_length]u8 = undefined; |
| 78 | var offset: usize = 0; | 87 | var offset: usize = 0; |
| 79 | var timer = try Timer.start(); | 88 | var timer = try Timer.start(); |
| 80 | const start = timer.lap(); | 89 | const start = timer.lap(); |
| 81 | while (offset < bytes) : (offset += in.len) { | 90 | while (offset < bytes) : (offset += in.len) { |
| 82 | Mac.create(key[0..], in[0..], key[0..]); | 91 | Mac.create(mac[0..], in[0..], key[0..]); |
| | 92 | blackBox(&mac); |
| 83 | } | 93 | } |
| 84 | const end = timer.read(); | 94 | const end = timer.read(); |
| 85 | | 95 | |
| ... | @@ -106,6 +116,7 @@ pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_c | ... | @@ -106,6 +116,7 @@ pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_c |
| 106 | var i: usize = 0; | 116 | var i: usize = 0; |
| 107 | while (i < exchange_count) : (i += 1) { | 117 | while (i < exchange_count) : (i += 1) { |
| 108 | _ = DhKeyExchange.create(out[0..], out[0..], in[0..]); | 118 | _ = DhKeyExchange.create(out[0..], out[0..], in[0..]); |
| | 119 | blackBox(&out); |
| 109 | } | 120 | } |
| 110 | } | 121 | } |
| 111 | const end = timer.read(); | 122 | const end = timer.read(); |
| ... | @@ -118,7 +129,7 @@ pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_c | ... | @@ -118,7 +129,7 @@ pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_c |
| 118 | | 129 | |
| 119 | const signatures = [_]Crypto{Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" }}; | 130 | const signatures = [_]Crypto{Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" }}; |
| 120 | | 131 | |
| 121 | pub fn benchmarkSignatures(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 { | 132 | pub fn benchmarkSignature(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 { |
| 122 | var seed: [Signature.seed_length]u8 = undefined; | 133 | var seed: [Signature.seed_length]u8 = undefined; |
| 123 | prng.random.bytes(seed[0..]); | 134 | prng.random.bytes(seed[0..]); |
| 124 | const msg = [_]u8{0} ** 64; | 135 | const msg = [_]u8{0} ** 64; |
| ... | @@ -129,7 +140,8 @@ pub fn benchmarkSignatures(comptime Signature: anytype, comptime signatures_coun | ... | @@ -129,7 +140,8 @@ pub fn benchmarkSignatures(comptime Signature: anytype, comptime signatures_coun |
| 129 | { | 140 | { |
| 130 | var i: usize = 0; | 141 | var i: usize = 0; |
| 131 | while (i < signatures_count) : (i += 1) { | 142 | while (i < signatures_count) : (i += 1) { |
| 132 | _ = try Signature.sign(&msg, key_pair, null); | 143 | const s = try Signature.sign(&msg, key_pair, null); |
| | 144 | blackBox(&s); |
| 133 | } | 145 | } |
| 134 | } | 146 | } |
| 135 | const end = timer.read(); | 147 | const end = timer.read(); |
| ... | @@ -140,6 +152,40 @@ pub fn benchmarkSignatures(comptime Signature: anytype, comptime signatures_coun | ... | @@ -140,6 +152,40 @@ pub fn benchmarkSignatures(comptime Signature: anytype, comptime signatures_coun |
| 140 | return throughput; | 152 | return throughput; |
| 141 | } | 153 | } |
| 142 | | 154 | |
| | 155 | const aeads = [_]Crypto{ |
| | 156 | Crypto{ .ty = crypto.aead.ChaCha20Poly1305, .name = "chacha20Poly1305" }, |
| | 157 | Crypto{ .ty = crypto.aead.XChaCha20Poly1305, .name = "xchacha20Poly1305" }, |
| | 158 | Crypto{ .ty = crypto.aead.Gimli, .name = "gimli-aead" }, |
| | 159 | }; |
| | 160 | |
| | 161 | pub fn benchmarkAead(comptime Aead: anytype, comptime bytes: comptime_int) !u64 { |
| | 162 | var in: [512 * KiB]u8 = undefined; |
| | 163 | prng.random.bytes(in[0..]); |
| | 164 | |
| | 165 | var tag: [Aead.tag_length]u8 = undefined; |
| | 166 | |
| | 167 | var key: [Aead.key_length]u8 = undefined; |
| | 168 | prng.random.bytes(key[0..]); |
| | 169 | |
| | 170 | var nonce: [Aead.nonce_length]u8 = undefined; |
| | 171 | prng.random.bytes(nonce[0..]); |
| | 172 | |
| | 173 | var offset: usize = 0; |
| | 174 | var timer = try Timer.start(); |
| | 175 | const start = timer.lap(); |
| | 176 | while (offset < bytes) : (offset += in.len) { |
| | 177 | Aead.encrypt(in[0..], tag[0..], in[0..], &[_]u8{}, nonce, key); |
| | 178 | Aead.decrypt(in[0..], in[0..], tag, &[_]u8{}, nonce, key) catch unreachable; |
| | 179 | } |
| | 180 | blackBox(&in); |
| | 181 | const end = timer.read(); |
| | 182 | |
| | 183 | const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s; |
| | 184 | const throughput = @floatToInt(u64, 2 * bytes / elapsed_s); |
| | 185 | |
| | 186 | return throughput; |
| | 187 | } |
| | 188 | |
| 143 | fn usage() void { | 189 | fn usage() void { |
| 144 | std.debug.warn( | 190 | std.debug.warn( |
| 145 | \\throughput_test [options] | 191 | \\throughput_test [options] |
| ... | @@ -198,29 +244,36 @@ pub fn main() !void { | ... | @@ -198,29 +244,36 @@ pub fn main() !void { |
| 198 | | 244 | |
| 199 | inline for (hashes) |H| { | 245 | inline for (hashes) |H| { |
| 200 | if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) { | 246 | if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) { |
| 201 | const throughput = try benchmarkHash(H.ty, mode(32 * MiB)); | 247 | const throughput = try benchmarkHash(H.ty, mode(128 * MiB)); |
| 202 | try stdout.print("{:>11}: {:5} MiB/s\n", .{ H.name, throughput / (1 * MiB) }); | 248 | try stdout.print("{:>17}: {:7} MiB/s\n", .{ H.name, throughput / (1 * MiB) }); |
| 203 | } | 249 | } |
| 204 | } | 250 | } |
| 205 | | 251 | |
| 206 | inline for (macs) |M| { | 252 | inline for (macs) |M| { |
| 207 | if (filter == null or std.mem.indexOf(u8, M.name, filter.?) != null) { | 253 | if (filter == null or std.mem.indexOf(u8, M.name, filter.?) != null) { |
| 208 | const throughput = try benchmarkMac(M.ty, mode(128 * MiB)); | 254 | const throughput = try benchmarkMac(M.ty, mode(128 * MiB)); |
| 209 | try stdout.print("{:>11}: {:5} MiB/s\n", .{ M.name, throughput / (1 * MiB) }); | 255 | try stdout.print("{:>17}: {:7} MiB/s\n", .{ M.name, throughput / (1 * MiB) }); |
| 210 | } | 256 | } |
| 211 | } | 257 | } |
| 212 | | 258 | |
| 213 | inline for (exchanges) |E| { | 259 | inline for (exchanges) |E| { |
| 214 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { | 260 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { |
| 215 | const throughput = try benchmarkKeyExchange(E.ty, mode(1000)); | 261 | const throughput = try benchmarkKeyExchange(E.ty, mode(1000)); |
| 216 | try stdout.print("{:>11}: {:5} exchanges/s\n", .{ E.name, throughput }); | 262 | try stdout.print("{:>17}: {:7} exchanges/s\n", .{ E.name, throughput }); |
| 217 | } | 263 | } |
| 218 | } | 264 | } |
| 219 | | 265 | |
| 220 | inline for (signatures) |E| { | 266 | inline for (signatures) |E| { |
| 221 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { | 267 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { |
| 222 | const throughput = try benchmarkSignatures(E.ty, mode(1000)); | 268 | const throughput = try benchmarkSignature(E.ty, mode(1000)); |
| 223 | try stdout.print("{:>11}: {:5} signatures/s\n", .{ E.name, throughput }); | 269 | try stdout.print("{:>17}: {:7} signatures/s\n", .{ E.name, throughput }); |
| | 270 | } |
| | 271 | } |
| | 272 | |
| | 273 | inline for (aeads) |E| { |
| | 274 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { |
| | 275 | const throughput = try benchmarkAead(E.ty, mode(128 * MiB)); |
| | 276 | try stdout.print("{:>17}: {:7} MiB/s\n", .{ E.name, throughput / (1 * MiB) }); |
| 224 | } | 277 | } |
| 225 | } | 278 | } |
| 226 | } | 279 | } |