mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 15:13:28 +00:00
performance now
This commit is contained in:
@@ -251,7 +251,7 @@ pub const Page = struct {
|
||||
fn init(self: *Page, arena: Allocator, session: *Session) !void {
|
||||
const browser = session.browser;
|
||||
self.* = .{
|
||||
.window = .{},
|
||||
.window = try Window.create(null, null), // TODO why do we not call Window.create()?
|
||||
.arena = arena,
|
||||
.doc = null,
|
||||
.raw_data = null,
|
||||
|
||||
@@ -24,6 +24,7 @@ const Navigator = @import("navigator.zig").Navigator;
|
||||
const History = @import("history.zig").History;
|
||||
const Location = @import("location.zig").Location;
|
||||
const MediaQueryList = @import("media_query_list.zig").MediaQueryList;
|
||||
const Performance = @import("performance.zig").Performance;
|
||||
|
||||
pub const Interfaces = .{
|
||||
HTMLDocument,
|
||||
@@ -36,4 +37,5 @@ pub const Interfaces = .{
|
||||
History,
|
||||
Location,
|
||||
MediaQueryList,
|
||||
Performance,
|
||||
};
|
||||
|
||||
87
src/browser/html/performance.zig
Normal file
87
src/browser/html/performance.zig
Normal file
@@ -0,0 +1,87 @@
|
||||
// Copyright (C) 2023-2025 Lightpanda (Selecy SAS)
|
||||
//
|
||||
// Francis Bouvier <francis@lightpanda.io>
|
||||
// Pierre Tachoire <pierre@lightpanda.io>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
const EventTarget = @import("../dom/event_target.zig").EventTarget;
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Performance
|
||||
pub const Performance = struct {
|
||||
pub const prototype = *EventTarget;
|
||||
|
||||
// Extend libdom event target for pure zig struct.
|
||||
base: parser.EventTargetTBase = parser.EventTargetTBase{},
|
||||
|
||||
time_origin: std.time.Timer,
|
||||
// if (Window.crossOriginIsolated) -> Resolution in isolated contexts: 5 microseconds
|
||||
// else -> Resolution in non-isolated contexts: 100 microseconds
|
||||
const ms_resolution = 100;
|
||||
|
||||
fn limited_resolution_ms(nanoseconds: u64) f64 {
|
||||
const elapsed_at_resolution = ((nanoseconds / std.time.ns_per_ms) + 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 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 limited_resolution_ms(started);
|
||||
}
|
||||
|
||||
pub fn _now(self: *Performance) f64 {
|
||||
return limited_resolution_ms(self.time_origin.read());
|
||||
}
|
||||
};
|
||||
|
||||
const testing = @import("./../../testing.zig");
|
||||
|
||||
test "Performance: get_timeOrigin" {
|
||||
var perf = Performance{ .time_origin = try std.time.Timer.start() };
|
||||
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.1);
|
||||
}
|
||||
|
||||
test "Performance: now" {
|
||||
var perf = Performance{ .time_origin = try std.time.Timer.start() };
|
||||
|
||||
// Monotonically increasing
|
||||
var now = perf._now();
|
||||
while (now <= 0) { // Loop for now to not be 0
|
||||
try testing.expect(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.expect(after == now);
|
||||
after = perf._now();
|
||||
}
|
||||
// Check resolution
|
||||
try testing.expectDelta(@rem(after * std.time.us_per_ms, 100.0), 0.0, 0.1);
|
||||
}
|
||||
@@ -30,6 +30,7 @@ const Crypto = @import("../crypto/crypto.zig").Crypto;
|
||||
const Console = @import("../console/console.zig").Console;
|
||||
const EventTarget = @import("../dom/event_target.zig").EventTarget;
|
||||
const MediaQueryList = @import("media_query_list.zig").MediaQueryList;
|
||||
const Performance = @import("performance.zig").Performance;
|
||||
|
||||
const storage = @import("../storage/storage.zig");
|
||||
|
||||
@@ -56,11 +57,13 @@ pub const Window = struct {
|
||||
crypto: Crypto = .{},
|
||||
console: Console = .{},
|
||||
navigator: Navigator = .{},
|
||||
performance: Performance,
|
||||
|
||||
pub fn create(target: ?[]const u8, navigator: ?Navigator) Window {
|
||||
pub fn create(target: ?[]const u8, navigator: ?Navigator) !Window {
|
||||
return .{
|
||||
.target = target orelse "",
|
||||
.navigator = navigator orelse .{},
|
||||
.performance = .{ .time_origin = try std.time.Timer.start() },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -72,6 +75,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.document = doc;
|
||||
try parser.documentHTMLSetLocation(Location, doc, &self.location);
|
||||
}
|
||||
@@ -130,6 +134,10 @@ pub const Window = struct {
|
||||
return &self.storage_shelf.?.bucket.session;
|
||||
}
|
||||
|
||||
pub fn get_performance(self: *Window) *Performance {
|
||||
return &self.performance;
|
||||
}
|
||||
|
||||
// TODO handle callback arguments.
|
||||
pub fn _setTimeout(self: *Window, cbk: Callback, delay: ?u32, state: *SessionState) !u32 {
|
||||
return self.createTimeout(cbk, delay, state, false);
|
||||
|
||||
@@ -30,6 +30,7 @@ const parser = @import("../browser/netsurf.zig");
|
||||
const base = @import("../testing.zig");
|
||||
pub const allocator = base.allocator;
|
||||
pub const expectJson = base.expectJson;
|
||||
pub const expect = std.testing.expect;
|
||||
pub const expectEqual = base.expectEqual;
|
||||
pub const expectError = base.expectError;
|
||||
pub const expectEqualSlices = base.expectEqualSlices;
|
||||
|
||||
@@ -21,6 +21,7 @@ const Allocator = std.mem.Allocator;
|
||||
|
||||
pub const allocator = std.testing.allocator;
|
||||
pub const expectError = std.testing.expectError;
|
||||
pub const expect = std.testing.expect;
|
||||
pub const expectString = std.testing.expectEqualStrings;
|
||||
pub const expectEqualSlices = std.testing.expectEqualSlices;
|
||||
|
||||
@@ -421,7 +422,7 @@ pub const JsRunner = struct {
|
||||
.http_client = &self.http_client,
|
||||
};
|
||||
|
||||
self.window = .{};
|
||||
self.window = try Window.create(null, null);
|
||||
try self.window.replaceDocument(document);
|
||||
try self.window.replaceLocation(.{
|
||||
.url = try self.url.toWebApi(arena),
|
||||
|
||||
Reference in New Issue
Block a user