From 3a4783cfa11fe563468f63339142d359fb6395ae Mon Sep 17 00:00:00 2001 From: adrien Date: Sat, 25 Apr 2026 18:47:13 +0200 Subject: [PATCH] Benchmark SIMD vs Native --- src/Scalar.zig | 2 -- src/Vector.zig | 1 + src/benchmark.zig | 77 ++++++++++++++++++++++++++++++++++++++++++++--- src/main.zig | 10 +++--- 4 files changed, 79 insertions(+), 11 deletions(-) diff --git a/src/Scalar.zig b/src/Scalar.zig index ecc35f6..34877cb 100644 --- a/src/Scalar.zig +++ b/src/Scalar.zig @@ -7,8 +7,6 @@ const UnitScale = Scales.UnitScale; const Dimensions = @import("Dimensions.zig"); const Dimension = Dimensions.Dimension; -// --------------------------------------------------------------------------- - /// A dimensioned scalar value. `T` is the numeric type, `d` the dimension exponents, `s` the SI scales. /// All dimension and unit tracking is resolved at comptime — zero runtime overhead. pub fn Scalar(comptime T: type, comptime d_opt: Dimensions.ArgOpts, comptime s_opt: Scales.ArgOpts) type { diff --git a/src/Vector.zig b/src/Vector.zig index 2e2bdee..62f9325 100644 --- a/src/Vector.zig +++ b/src/Vector.zig @@ -74,6 +74,7 @@ pub fn Vector(comptime len: usize, comptime Q: type) type { } return res; } + /// Element-wise subtraction. Dimensions must match; scales resolve to the finer of the two. pub inline fn sub(self: Self, rhs: anytype) Vector(len, Scalar( T, diff --git a/src/benchmark.zig b/src/benchmark.zig index 2d9d5d0..1d77d0e 100644 --- a/src/benchmark.zig +++ b/src/benchmark.zig @@ -11,14 +11,25 @@ pub fn main(init: std.process.Init) !void { io = init.io; - try bench_Scalar(&stdout_writer.interface); + try vectorSIMDvsNative(f64, &stdout_writer.interface); try stdout_writer.flush(); - try bench_vsNative(&stdout_writer.interface); + try vectorSIMDvsNative(f32, &stdout_writer.interface); try stdout_writer.flush(); - try bench_crossTypeVsNative(&stdout_writer.interface); + try vectorSIMDvsNative(i32, &stdout_writer.interface); try stdout_writer.flush(); - try bench_Vector(&stdout_writer.interface); + try vectorSIMDvsNative(i64, &stdout_writer.interface); try stdout_writer.flush(); + try vectorSIMDvsNative(i128, &stdout_writer.interface); + try stdout_writer.flush(); + + // try bench_Scalar(&stdout_writer.interface); + // try stdout_writer.flush(); + // try bench_vsNative(&stdout_writer.interface); + // try stdout_writer.flush(); + // try bench_crossTypeVsNative(&stdout_writer.interface); + // try stdout_writer.flush(); + // try bench_Vector(&stdout_writer.interface); + // try stdout_writer.flush(); } fn getTime() Io.Timestamp { @@ -478,3 +489,61 @@ fn bench_Vector(writer: *std.Io.Writer) !void { } try writer.print("└──────────────────┴──────┴─────────┴─────────┴─────────┘\n", .{}); } + +fn vectorSIMDvsNative(comptime T: type, writer: *std.Io.Writer) !void { + const iterations: u64 = 100_000; + const lens = [_]u32{ 1, 2, 3, 4, 5, 10, 100, 1_000, 10_000 }; + + try writer.print("\nSIMD Speedup Analysis: {s}\n", .{@typeName(T)}); + try writer.print("┌────────────┬────────────┬────────────┬────────────┐\n", .{}); + try writer.print("│ Vector Len │ Scalar (ns)│ Vector (ns)│ Speedup │\n", .{}); + try writer.print("├────────────┼────────────┼────────────┼────────────┤\n", .{}); + + inline for (lens) |vector_len| { + // --- Scalar Test --- + var scalar_val: T = 10; + const start_scalar = getTime(); + + var i: u64 = 0; + while (i < iterations * vector_len) : (i += 1) { + if (comptime @typeInfo(T) == .int) + scalar_val = scalar_val +% 1 + else + scalar_val = scalar_val + 1; + } + const scalar_time = start_scalar.durationTo(getTime()).toNanoseconds(); + + // --- Vector Test --- + var vector_val: @Vector(vector_len, T) = @splat(20); + const start_vector = getTime(); + + i = 0; + const increment: @Vector(vector_len, T) = @splat(1); + while (i < iterations) : (i += 1) { + if (comptime @typeInfo(T) == .int) + vector_val = vector_val +% increment + else + vector_val = vector_val + increment; + } + const vector_time = start_vector.durationTo(getTime()).toNanoseconds(); + + // --- Results --- + const s_float = @as(f64, @floatFromInt(scalar_time)); + const v_float = @as(f64, @floatFromInt(vector_time)); + + // Speedup = ScalarTime / VectorTime. + // > 1.0 means SIMD is faster. + const speedup = if (vector_time > 0) s_float / v_float else 0; + + try writer.print("│ {d:<10} │ {d:>10} │ {d:>10} │ {d:>9.2}x │\n", .{ + vector_len, + scalar_time, + vector_time, + speedup, + }); + + std.mem.doNotOptimizeAway(scalar_val); + std.mem.doNotOptimizeAway(vector_val); + } + try writer.print("└────────────┴────────────┴────────────┴────────────┘\n", .{}); +} diff --git a/src/main.zig b/src/main.zig index 015d36f..eab001d 100644 --- a/src/main.zig +++ b/src/main.zig @@ -8,9 +8,9 @@ pub const Base = @import("Base.zig"); test { _ = @import("Scalar.zig"); - _ = @import("Vector.zig"); - _ = @import("Dimensions.zig"); - _ = @import("Scales.zig"); - _ = @import("Base.zig"); - _ = @import("helper.zig"); + // _ = @import("Vector.zig"); + // _ = @import("Dimensions.zig"); + // _ = @import("Scales.zig"); + // _ = @import("Base.zig"); + // _ = @import("helper.zig"); }