I was toying around porting a baremetal riscV code from Rust to Zig and noticed a critical section was performing an order of magnitude slower the orignal code. In this section, a piece of hardware ask for an address which is stored somewhere in memory, and the code should fetch this address and send it back to the hw.
Basically, the hot loop is continuously polling on the hw until there's a request, then it pops the asked item from a queue/array/whatever and writes it to the hw. Since the array maximum capacity is known at compile time, it felt natural to use BundedArray, which also avoid dealing with an allocator, but somehow this resulted much slower in performances than using an ArrayList with a FixedBufferAllocator (like 500us vs 50us on the riscV core I'm using to handle the request).
If someone is interested, I wrote a chunk of code which compares push/pop times for ArrayList and BoudedArray, which shows the same behavior when run on my x86 laptop:
const std = @import("std");
const ITERATIONS = 100000000;
fn test_bound(array: anytype, item: *u64) void {
const t0 = std.time.microTimestamp();
for (0..ITERATIONS) |_| {
array.append(item.*) catch unreachable;
item.* = array.pop();
}
const t1 = std.time.microTimestamp();
std.debug.print("{} - {} elapsed {}\n", .{ @TypeOf(array), item.*, t1 - t0 });
}
pub fn main() !void {
std.debug.print("hello\n", .{});
var barr = try std.BoundedArray(u64, 100).init(0);
var buffer: [1000]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buffer);
const allocator = fba.allocator();
var list = std.ArrayList(u64).init(allocator);
defer list.deinit();
var item: u64 = 3;
test_bound(&list, &item);
test_bound(&barr, &item);
}
Built with ReleaseSafe, this result in ~60ms for ArrayList and ~2600ms for BoundedArray.
Is this expected or am I doing something wrong?
