Created
July 9, 2019 17:01
-
-
Save kprotty/2158c10b6496d134ba68e5fd412f9bfa to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const std = @import("std"); | |
const builtin = @import("builtin"); | |
pub fn main() !void { | |
if (std.os.argv.len < 2) | |
return error.NeedsIterationArgument; | |
const FIB = 35; | |
const RESOLUTION = Timer.Resolution.Millisecond; | |
const ITERATIONS = try std.fmt.parseInt(usize, std.mem.toSlice(u8, std.os.argv[1]), 10); | |
Timer.Time("fib-zig", ITERATIONS, RESOLUTION, struct { fn run() usize { | |
return fib_zig(FIB); | |
}}); | |
Timer.Time("fib-asm", ITERATIONS, RESOLUTION, struct { fn run() usize { | |
return fib_asm(FIB); | |
}}); | |
} | |
// LLVM version | |
pub export fn fib_zig(n: usize) usize { | |
if (n <= 1) return 1; | |
return fib_zig(n - 1) + fib_zig(n - 2); | |
} | |
// Custom SystemV version | |
extern fn fib_asm(n: usize) usize; | |
comptime { asm ( | |
\\ .intel_syntax noprefix | |
\\ .global fib_asm | |
\\ .type fib_asm, @function | |
\\ | |
\\ fib_asm: | |
\\ mov rax, 1 | |
\\ cmp rdi, rax | |
\\ jle done | |
\\ dec rdi | |
\\ push rdi | |
\\ call fib_asm | |
\\ pop rdi | |
\\ push rax | |
\\ dec rdi | |
\\ call fib_asm | |
\\ pop rcx | |
\\ add rax, rcx | |
\\ done: | |
\\ ret | |
);} | |
pub const Timer = struct { | |
pub const Resolution = enum { | |
Second, | |
Millisecond, | |
Microsecond, | |
Nanosecond, | |
pub fn toUnit(self: Resolution) []const u8 { | |
return switch (self) { | |
.Second => "s", | |
.Millisecond => "ms", | |
.Microsecond => "μs", | |
.Nanosecond => "ns", | |
}; | |
} | |
pub fn toSecondMultiple(self: Resolution) u64 { | |
return switch (self) { | |
.Second => u64(1), | |
.Millisecond => u64(1000), | |
.Microsecond => u64(1000 * 1000), | |
.Nanosecond => u64(1000 * 1000 * 1000), | |
}; | |
} | |
}; | |
pub fn Time( | |
comptime name: []const u8, | |
iterations: usize, | |
resolution: Resolution, | |
comptime action: type, | |
) void { | |
var it = u64(0); | |
var average: u64 = 0; | |
while (it < iterations) : (it += 1) { | |
const start = Timer.Get(resolution); | |
const result = action.run(); | |
const end = Timer.Get(resolution); | |
average = ((average * it) + (end - start)) / (it + 1); | |
_ = Timer.BlackBox(result); | |
} | |
const unit = resolution.toUnit(); | |
std.debug.warn("{} takes {}{} on average(runs: {})\n", name, average, unit, iterations); | |
} | |
pub usingnamespace switch (builtin.os) { | |
.windows => struct { | |
var freq: u64 = 0; | |
extern "kernel32" stdcallcc fn QueryPerformanceCounter(x: *u64) usize; | |
extern "kernel32" stdcallcc fn QueryPerformanceFrequency(x: *u64) usize; | |
pub fn BlackBox(result: u64) usize { | |
return QueryPerformanceCounter(@intToPtr(*u64, @intCast(usize, result))); | |
} | |
pub fn Get(resolution: Resolution) u64 { | |
var time: u64 = undefined; | |
if (freq == 0) | |
_ = QueryPerformanceFrequency(&freq); | |
_ = QueryPerformanceCounter(&time); | |
return time / (freq / resolution.toSecondMultiple()); | |
} | |
}, | |
.linux => struct { | |
const linux = std.os.linux; | |
pub fn BlackBox(result: u64) usize { | |
return linux.syscall2(linux.SYS_clock_gettime, linux.CLOCK_REALTIME, @intCast(usize, result)); | |
} | |
pub fn Get(resolution: Resolution) u64 { | |
var tp: linux.timespec = undefined; | |
const ns = Resolution.Nanosecond.toSecondMultiple(); | |
_ = linux.syscall2(linux.SYS_clock_gettime, linux.CLOCK_REALTIME, @ptrToInt(&tp)); | |
const time = @intCast(u64, tp.tv_sec) * ns + @intCast(u64, tp.tv_nsec); | |
return time / (ns / resolution.toSecondMultiple()); | |
} | |
}, | |
else => @compileError("OS not supported"), | |
}; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment