Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/browser/console/console.zig
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,7 @@ pub const Console = struct {
};

fn timestamp() u32 {
const ts = std.posix.clock_gettime(std.posix.CLOCK.MONOTONIC) catch unreachable;
return @intCast(ts.sec);
return @import("../../datetime.zig").timestamp();
}

var test_capture = TestCapture{};
Expand Down
63 changes: 30 additions & 33 deletions src/browser/dom/performance.zig
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ const EventTarget = @import("../dom/event_target.zig").EventTarget;
const Env = @import("../env.zig").Env;
const Page = @import("../page.zig").Page;

const milliTimestamp = @import("../../datetime.zig").milliTimestamp;

pub const Interfaces = .{
Performance,
PerformanceEntry,
Expand All @@ -36,29 +38,27 @@ pub const Performance = struct {
// Extend libdom event target for pure zig struct.
base: parser.EventTargetTBase = parser.EventTargetTBase{ .internal_target_type = .performance },

time_origin: std.time.Timer,
time_origin: u64,
// if (Window.crossOriginIsolated) -> Resolution in isolated contexts: 5 microseconds
// else -> Resolution in non-isolated contexts: 100 microseconds
const ms_resolution = 100;

fn limitedResolutionMs(nanoseconds: u64) f64 {
const elapsed_at_resolution = ((nanoseconds / std.time.ns_per_us) + ms_resolution / 2) / ms_resolution * ms_resolution;
const elapsed = @as(f64, @floatFromInt(elapsed_at_resolution));
return elapsed / @as(f64, std.time.us_per_ms);
pub fn init() Performance {
return .{
.time_origin = milliTimestamp(),
};
}

pub fn get_timeOrigin(self: *const Performance) f64 {
const is_posix = switch (@import("builtin").os.tag) { // From std.time.zig L125
.windows, .uefi, .wasi => false,
else => true,
};
const zero = std.time.Instant{ .timestamp = if (!is_posix) 0 else .{ .sec = 0, .nsec = 0 } };
const started = self.time_origin.started.since(zero);
return limitedResolutionMs(started);
pub fn get_timeOrigin(self: *const Performance) u64 {
return self.time_origin;
}

pub fn reset(self: *Performance) void {
self.time_origin = milliTimestamp();
}

pub fn _now(self: *Performance) f64 {
return limitedResolutionMs(self.time_origin.read());
pub fn _now(self: *const Performance) u64 {
return milliTimestamp() - self.time_origin;
}

pub fn _mark(_: *Performance, name: []const u8, _options: ?PerformanceMark.Options, page: *Page) !PerformanceMark {
Expand Down Expand Up @@ -152,14 +152,14 @@ pub const PerformanceMark = struct {

const Options = struct {
detail: ?Env.JsObject = null,
start_time: ?f64 = null,
startTime: ?f64 = null,
};

pub fn constructor(name: []const u8, _options: ?Options, page: *Page) !PerformanceMark {
const perf = &page.window.performance;

const options = _options orelse Options{};
const start_time = options.start_time orelse perf._now();
const start_time = options.startTime orelse @as(f64, @floatFromInt(perf._now()));

if (start_time < 0.0) {
return error.TypeError;
Expand All @@ -181,47 +181,44 @@ pub const PerformanceMark = struct {
const testing = @import("./../../testing.zig");

test "Performance: get_timeOrigin" {
var perf = Performance{ .time_origin = try std.time.Timer.start() };
var perf = Performance.init();
const time_origin = perf.get_timeOrigin();
try testing.expect(time_origin >= 0);

// Check resolution
try testing.expectDelta(@rem(time_origin * std.time.us_per_ms, 100.0), 0.0, 0.2);
}

test "Performance: now" {
var perf = Performance{ .time_origin = try std.time.Timer.start() };
var perf = Performance.init();

// Monotonically increasing
var now = perf._now();
while (now <= 0) { // Loop for now to not be 0
try testing.expectEqual(now, 0);
now = perf._now();
}
// Check resolution
try testing.expectDelta(@rem(now * std.time.us_per_ms, 100.0), 0.0, 0.1);

var after = perf._now();
while (after <= now) { // Loop untill after > now
try testing.expectEqual(after, now);
after = perf._now();
}
// Check resolution
try testing.expectDelta(@rem(after * std.time.us_per_ms, 100.0), 0.0, 0.1);
}

test "Browser.Performance.Mark" {
var runner = try testing.jsRunner(testing.tracking_allocator, .{});
defer runner.deinit();

try runner.testCases(&.{
.{ "let performance = window.performance", "undefined" },
.{ "let performance = window.performance", null },
.{ "performance instanceof Performance", "true" },
.{ "let mark = performance.mark(\"start\")", "undefined" },
.{ "mark instanceof PerformanceMark", "true" },
.{ "mark.name", "start" },
.{ "mark.entryType", "mark" },
.{ "mark.duration", "0" },
.{ "mark.detail", "null" },

.{ "let mark1 = performance.mark(\"start\")", null },
.{ "mark1 instanceof PerformanceMark", "true" },
.{ "mark1.name", "start" },
.{ "mark1.entryType", "mark" },
.{ "mark1.duration", "0" },
.{ "mark1.detail", "null" },

.{ "let mark2 = performance.mark(\"start\", {startTime: 32939393.9})", null },
.{ "mark2.startTime", "32939393.9" },
}, .{});
}
4 changes: 2 additions & 2 deletions src/browser/html/window.zig
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ pub const Window = struct {
.document = html_doc,
.target = target orelse "",
.navigator = navigator orelse .{},
.performance = .{ .time_origin = try std.time.Timer.start() },
.performance = Performance.init(),
};
}

Expand All @@ -86,7 +86,7 @@ pub const Window = struct {
}

pub fn replaceDocument(self: *Window, doc: *parser.DocumentHTML) !void {
self.performance.time_origin.reset(); // When to reset see: https://developer.mozilla.org/en-US/docs/Web/API/Performance/timeOrigin
self.performance.reset(); // When to reset see: https://developer.mozilla.org/en-US/docs/Web/API/Performance/timeOrigin
self.document = doc;
try parser.documentHTMLSetLocation(Location, doc, &self.location);
}
Expand Down
3 changes: 1 addition & 2 deletions src/browser/page.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1101,8 +1101,7 @@ pub const NavigateOpts = struct {
};

fn timestamp() u32 {
const ts = std.posix.clock_gettime(std.posix.CLOCK.MONOTONIC) catch unreachable;
return @intCast(ts.sec);
return @import("../datetime.zig").timestamp();
}

// A callback from libdom whenever a script tag is added to the DOM.
Expand Down
22 changes: 22 additions & 0 deletions src/datetime.zig
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,28 @@ pub const DateTime = struct {
}
};

pub fn timestamp() u32 {
const ts = timespec();
return @intCast(ts.sec);
}

pub fn milliTimestamp() u64 {
const ts = timespec();
return @as(u64, @intCast(ts.sec)) * 1000 + @as(u64, @intCast(@divTrunc(ts.nsec, 1_000_000)));
}

fn timespec() std.posix.timespec {
const clock_id = switch (@import("builtin").os.tag) {
.freebsd, .dragonfly => std.posix.CLOCK.MONOTONIC_FAST,
.macos, .ios, .tvos, .watchos, .visionos => std.posix.CLOCK.UPTIME_RAW, // continues counting while suspended
.linux => std.posix.CLOCK.BOOTTIME, // continues counting while suspended
else => std.posix.CLOCK.MONOTONIC,
};
// we don't currently support platforms where, at the very least,
// posix.CLOCK.MONOTONIC wouldn't be available.
return std.posix.clock_gettime(clock_id) catch unreachable;
}

fn writeDate(into: []u8, date: Date) u8 {
var buf: []u8 = undefined;
// cast year to a u16 so it doesn't insert a sign
Expand Down
6 changes: 3 additions & 3 deletions src/log.zig
Original file line number Diff line number Diff line change
Expand Up @@ -321,14 +321,14 @@ fn writeString(comptime format: Format, value: []const u8, writer: anytype) !voi
return writer.writeByte('"');
}

fn timestamp() i64 {
fn timestamp() u64 {
if (comptime @import("builtin").is_test) {
return 1739795092929;
}
return std.time.milliTimestamp();
return @import("datetime.zig").milliTimestamp();
}

var first_log: i64 = 0;
var first_log: u64 = 0;
fn elapsed() struct { time: f64, unit: []const u8 } {
const now = timestamp();

Expand Down
3 changes: 1 addition & 2 deletions src/server.zig
Original file line number Diff line number Diff line change
Expand Up @@ -897,8 +897,7 @@ fn buildJSONVersionResponse(
}

fn timestamp() u32 {
const ts = std.posix.clock_gettime(std.posix.CLOCK.MONOTONIC) catch unreachable;
return @intCast(ts.sec);
return @import("datetime.zig").timestamp();
}

// In-place string lowercase
Expand Down