added scopes
This commit is contained in:
parent
b5dad13bd7
commit
c7cfa18ce9
|
|
@ -0,0 +1,131 @@
|
|||
// pscopes
|
||||
//
|
||||
// a tiny scope based profiling library
|
||||
//
|
||||
// as well as contains info for arbitrary timestamping and timestamp resolution
|
||||
|
||||
const timestampTicks = if (builtin.target.cpu.arch == .x86_64) aarch64_ticks else rdtsc;
|
||||
|
||||
pub inline fn rdtsc_fenced() u64 {
|
||||
var hi: u32 = 0;
|
||||
var low: u32 = 0;
|
||||
|
||||
asm (
|
||||
\\rdtsc
|
||||
\\mfence
|
||||
: [low] "={eax}" (low),
|
||||
[hi] "={edx}" (hi),
|
||||
);
|
||||
return (@as(u64, hi) << 32) | @as(u64, low);
|
||||
}
|
||||
|
||||
// rdtsc actually gets read
|
||||
pub inline fn rdtsc() u64 {
|
||||
var hi: u32 = 0;
|
||||
var low: u32 = 0;
|
||||
|
||||
asm (
|
||||
\\rdtsc
|
||||
: [low] "={eax}" (low),
|
||||
[hi] "={edx}" (hi),
|
||||
);
|
||||
return (@as(u64, hi) << 32) | @as(u64, low);
|
||||
}
|
||||
|
||||
fn aarch64_ticks() u64 {
|
||||
return asm volatile ("mrs %[ret], CNTVCT_EL0"
|
||||
: [ret] "=r" (-> u64),
|
||||
);
|
||||
}
|
||||
|
||||
fn aarch64_freq() u64 {
|
||||
return asm volatile ("mrs %[ret], CNTFRQ_EL0"
|
||||
: [ret] "=r" (-> u64),
|
||||
);
|
||||
}
|
||||
|
||||
pub const TimingScope = struct {
|
||||
// value in tsc ticks
|
||||
startTsc: u64,
|
||||
endTsc: ?u64 = null,
|
||||
|
||||
context: *ScopesContext,
|
||||
|
||||
pub inline fn init(c: *ScopesContext) @This() {
|
||||
return .{
|
||||
.startTsc = rdtsc(),
|
||||
.context = c,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn duration(self: *@This()) ?f64 {
|
||||
_ = self;
|
||||
}
|
||||
|
||||
pub inline fn end(self: *@This()) void {
|
||||
self.endTsc = rdtsc();
|
||||
}
|
||||
};
|
||||
|
||||
pub const ScopesContext = struct {
|
||||
allocator: std.mem.Allocator,
|
||||
ticksPerMs: ?f64 = null,
|
||||
timer: std.time.Timer,
|
||||
|
||||
pub fn timingScope(self: *@This()) TimingScope {
|
||||
_ = self;
|
||||
}
|
||||
|
||||
// calibrates the ticks per second divider.
|
||||
// spins for 1 ms then compares against the monotonic timer
|
||||
// should be called once every second
|
||||
pub fn calibrate(self: *@This()) void {
|
||||
if (builtin.target.cpu.arch == .x86_64) {
|
||||
self.timer.reset();
|
||||
const startStamp = rdtsc();
|
||||
while (self.timer.read() < std.time.ns_per_ms) {}
|
||||
const endStamp = rdtsc();
|
||||
|
||||
self.ticksPerMs = @floatFromInt((endStamp - startStamp));
|
||||
} else if (builtin.target.cpu.arch == .aarch64) {
|
||||
self.ticksPerMs = @as(f64, @floatFromInt(aarch64_freq())) / 1000;
|
||||
} else {
|
||||
// not ticking
|
||||
// unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create(allocator: std.mem.Allocator) !*@This() {
|
||||
const self = try allocator.create(@This());
|
||||
self.* = .{
|
||||
.allocator = allocator,
|
||||
.timer = try std.time.Timer.start(),
|
||||
};
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn destroy(self: *@This()) void {
|
||||
self.allocator.destroy(self);
|
||||
}
|
||||
};
|
||||
|
||||
test "calibrate scoes" {
|
||||
const allocator = std.testing.allocator;
|
||||
|
||||
const scopes = try ScopesContext.create(allocator);
|
||||
defer scopes.destroy();
|
||||
scopes.calibrate();
|
||||
|
||||
std.debug.print("calibration ticksPerMs = {d}\n", .{scopes.ticksPerMs.?});
|
||||
scopes.calibrate();
|
||||
std.debug.print("calibration ticksPerMs = {d}\n", .{scopes.ticksPerMs.?});
|
||||
scopes.calibrate();
|
||||
std.debug.print("calibration ticksPerMs = {d}\n", .{scopes.ticksPerMs.?});
|
||||
scopes.calibrate();
|
||||
std.debug.print("calibration ticksPerMs = {d}\n", .{scopes.ticksPerMs.?});
|
||||
scopes.calibrate();
|
||||
std.debug.print("calibration ticksPerMs = {d}\n", .{scopes.ticksPerMs.?});
|
||||
}
|
||||
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
Loading…
Reference in New Issue