Skip to content

Instantly share code, notes, and snippets.

@Rexicon226
Created June 27, 2025 23:21
Show Gist options
  • Save Rexicon226/e91d750f5842af43d96b2f0a526ba392 to your computer and use it in GitHub Desktop.
Save Rexicon226/e91d750f5842af43d96b2f0a526ba392 to your computer and use it in GitHub Desktop.
CRC-32C benchmark
const std = @import("std");
const Wrapper = @import("crc32c.zig").Wrapper;
const iterations_per_byte = 1000;
const warmup_iterations = 10;
pub fn main() !void {
const allocator = std.heap.smp_allocator;
// Pin the process to a single core (1)
const cpu0001: std.os.linux.cpu_set_t = [1]usize{0b0001} ++ ([_]usize{0} ** (16 - 1));
try std.os.linux.sched_setaffinity(0, &cpu0001);
const stdout = std.io.getStdOut().writer();
const loops = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, loops);
var prng = std.Random.DefaultPrng.init(0);
const random = prng.random();
const max_bytes = try std.fmt.parseInt(usize, loops[1], 10);
const pow_max_bytes = try std.math.powi(usize, 2, max_bytes);
const buffer = try allocator.alloc(u8, pow_max_bytes);
for (1..max_bytes) |N| {
const index = try std.math.powi(usize, 2, N);
const slice = buffer[0..index];
random.bytes(slice);
try stdout.print("{},", .{index});
inline for (.{
.{ Wrapper.hash, "fast crc32c" },
.{ std.hash.crc.Crc32Iscsi.hash, "stdlib crc32c" },
}) |impl| {
const func, const name = impl;
_ = name;
clflush(u8, slice);
var i: u32 = 0;
var cycles: u64 = 0;
while (i < iterations_per_byte + warmup_iterations) : (i += 1) {
const start = rdtsc();
std.mem.doNotOptimizeAway(func(slice));
const end = rdtsc();
if (i > warmup_iterations) cycles += (end - start);
}
const cycles_per_byte = cycles / iterations_per_byte;
try stdout.print("{d},", .{cycles_per_byte});
}
try stdout.writeAll("\n");
}
}
/// X86 cycle counter
inline fn rdtsc() usize {
var a: u32 = undefined;
var b: u32 = undefined;
asm volatile ("rdtscp"
: [a] "={edx}" (a),
[b] "={eax}" (b),
:
: "ecx"
);
return (@as(u64, a) << 32) | b;
}
inline fn clflush(comptime T: type, slice: []const T) void {
for (0..(slice.len) / @bitSizeOf(T) * 8) |chunk| {
const offset = slice.ptr + (chunk * @bitSizeOf(T) * 8);
asm volatile ("clflush %[ptr]"
:
: [ptr] "m" (offset),
: "memory"
);
}
}
import matplotlib.pyplot as plt
filename = "data.txt"
sizes = []
new_cycles = []
old_cycles = []
with open(filename) as f:
for line in f:
if not line.strip():
continue
parts = line.strip().split(",")
if len(parts) < 3:
continue
size, x, y = map(int, parts[:3])
sizes.append(size)
new_cycles.append(x)
old_cycles.append(y)
# Plot
plt.figure(figsize=(10, 6))
plt.plot(sizes, new_cycles, label="New", marker="o")
plt.plot(sizes, old_cycles, label="Old", marker="s")
plt.xscale("log", base=2)
plt.xlabel("Input size")
plt.ylabel("Cycles")
plt.grid(True, which="both", ls="--", alpha=0.5)
plt.legend()
plt.tight_layout()
plt.savefig("test.png")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment