| 1 | const std = @import("std"); |
| 2 | const Io = std.Io; |
| 3 | const time = std.time; |
| 4 | const unicode = std.unicode; |
| 5 | |
| 6 | const N = 1_000_000; |
| 7 | |
| 8 | const KiB = 1024; |
| 9 | const MiB = 1024 * KiB; |
| 10 | const GiB = 1024 * MiB; |
| 11 | |
| 12 | const ResultCount = struct { |
| 13 | count: usize, |
| 14 | throughput: u64, |
| 15 | }; |
| 16 | |
| 17 | fn benchTime(io: Io) i96 { |
| 18 | return Io.Clock.awake.now(io).nanoseconds; |
| 19 | } |
| 20 | |
| 21 | fn benchmarkCodepointCount(buf: []const u8, io: Io) !ResultCount { |
| 22 | const bytes = N * buf.len; |
| 23 | |
| 24 | const start = benchTime(io); |
| 25 | var i: usize = 0; |
| 26 | var r: usize = undefined; |
| 27 | while (i < N) : (i += 1) { |
| 28 | r = try @call( |
| 29 | .never_inline, |
| 30 | std.unicode.utf8CountCodepoints, |
| 31 | .{buf}, |
| 32 | ); |
| 33 | } |
| 34 | const end = benchTime(io); |
| 35 | |
| 36 | const elapsed_s = @as(f64, @floatFromInt(end - start)) / time.ns_per_s; |
| 37 | const throughput = @as(u64, @intFromFloat(@as(f64, @floatFromInt(bytes)) / elapsed_s)); |
| 38 | |
| 39 | return ResultCount{ .count = r, .throughput = throughput }; |
| 40 | } |
| 41 | |
| 42 | pub fn main(init: std.process.Init) !void { |
| 43 | // Size of buffer is about size of printed message. |
| 44 | const io = init.io; |
| 45 | var stdout_buffer: [0x100]u8 = undefined; |
| 46 | var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer); |
| 47 | const stdout = &stdout_writer.interface; |
| 48 | |
| 49 | try stdout.print("short ASCII strings\n", .{}); |
| 50 | try stdout.flush(); |
| 51 | { |
| 52 | const result = try benchmarkCodepointCount("abc", io); |
| 53 | try stdout.print(" count: {:5} MiB/s [{d}]\n", .{ result.throughput / (1 * MiB), result.count }); |
| 54 | } |
| 55 | |
| 56 | try stdout.print("short Unicode strings\n", .{}); |
| 57 | try stdout.flush(); |
| 58 | { |
| 59 | const result = try benchmarkCodepointCount("ŌŌŌ", io); |
| 60 | try stdout.print(" count: {:5} MiB/s [{d}]\n", .{ result.throughput / (1 * MiB), result.count }); |
| 61 | } |
| 62 | |
| 63 | try stdout.print("pure ASCII strings\n", .{}); |
| 64 | try stdout.flush(); |
| 65 | { |
| 66 | const part = "hello"; |
| 67 | const buf: [16][part.len]u8 = @splat(part.*); |
| 68 | const result = try benchmarkCodepointCount(@ptrCast(&buf), io); |
| 69 | try stdout.print(" count: {:5} MiB/s [{d}]\n", .{ result.throughput / (1 * MiB), result.count }); |
| 70 | } |
| 71 | |
| 72 | try stdout.print("pure Unicode strings\n", .{}); |
| 73 | try stdout.flush(); |
| 74 | { |
| 75 | const part = "こんにちは"; |
| 76 | const buf: [16][part.len]u8 = @splat(part.*); |
| 77 | const result = try benchmarkCodepointCount(@ptrCast(&buf), io); |
| 78 | try stdout.print(" count: {:5} MiB/s [{d}]\n", .{ result.throughput / (1 * MiB), result.count }); |
| 79 | } |
| 80 | |
| 81 | try stdout.print("mixed ASCII/Unicode strings\n", .{}); |
| 82 | try stdout.flush(); |
| 83 | { |
| 84 | const part = "Hyvää huomenta"; |
| 85 | const buf: [16][part.len]u8 = @splat(part.*); |
| 86 | const result = try benchmarkCodepointCount(@ptrCast(&buf), io); |
| 87 | try stdout.print(" count: {:5} MiB/s [{d}]\n", .{ result.throughput / (1 * MiB), result.count }); |
| 88 | } |
| 89 | try stdout.flush(); |
| 90 | } |