Skip to content

Instantly share code, notes, and snippets.

@18alantom
Created October 8, 2023 10:03
Show Gist options
  • Save 18alantom/fac21902a1e7b295cac16f3772f42df3 to your computer and use it in GitHub Desktop.
Save 18alantom/fac21902a1e7b295cac16f3772f42df3 to your computer and use it in GitHub Desktop.
Experiments
/// Run using
/// ```bash
/// zig run -O ReleaseFast fast_zeros.zig > /dev/null
/// ```
/// This program writes 0s to std out using a buffer.
/// Time taken, buffer size and number of loops are
/// written to stderr.
///
/// Purpose of this is to roughly check what size of
/// buffer allows for max throughput by measuring the
/// time taken to write zeros to stdout.
///
/// `c.printf` is used cause it's much faster than zig's
/// `os.write` to fd 1. Why? I'm not really sure, but I think
/// it's cause of error handling condional checking between
/// the two functions. Will have to dive deeper.
///
/// Insights from running the program:
/// - Power of 2 buffers take lesser time to fill (than pow 10).
/// - Until 1KB buffer big decrements in total time.
/// - After 1KB total roughly constant.
/// - Fastest run is with 4MB buffer (2**22).
/// - Commenting out the `std.c.printf` line shows that:
/// - `@memset` is constant until 512B (21ns).
/// - Doubles after that (linearly scales with input).
const temp = @import("./lib.zig").temp;
const std = @import("std");
const print = std.debug.print;
const os = std.os;
const pow = std.math.pow;
pub fn main() !void {
// Powers of 10
var ns1: [4]u32 = undefined;
for (0..ns1.len) |i| {
const exp: u32 = @intCast(i);
ns1[i] = pow(u32, 10, exp + 1);
}
// Powers of 2
var ns2: [24]u32 = undefined;
for (0..ns2.len) |i| {
const exp: u32 = @intCast(i + 2);
ns2[i] = pow(u32, 2, exp);
}
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
try outer_loop(&ns1, 10_000_000, &allocator);
try outer_loop(&ns2, pow(u32, 2, 30), &allocator);
}
pub fn outer_loop(buff_sizes: []const u32, size: u32, allocator: *const std.mem.Allocator) !void {
print("Looping: {d}\n{any}\n\n", .{ size, buff_sizes });
for (buff_sizes) |buff_size| {
const buff = try allocator.allocSentinel(u8, buff_size, 0);
defer allocator.free(buff);
try loop(buff, size);
}
print("\n\n", .{});
}
pub fn loop(buff: [:0]u8, size: u32) !void {
var timer = try std.time.Timer.start();
var acc: u128 = 0;
const loops = size / buff.len;
for (0..loops) |_| {
@memset(buff, '0');
_ = std.c.printf(buff);
acc += timer.lap();
}
print(
\\{d} buff.len, {d} loops:
\\ avg: {d:10}
\\ total: {d:10}
\\
\\
, .{ buff.len, loops, acc / loops, acc });
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment