mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-12-16 08:18:59 +00:00
Merge branch 'performance_mark' into zigdom
This commit is contained in:
@@ -43,3 +43,91 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script id=mark>
|
||||||
|
{
|
||||||
|
let mark1 = performance.mark("start");
|
||||||
|
testing.expectEqual(true, mark1 instanceof PerformanceMark);
|
||||||
|
testing.expectEqual('start', mark1.name);
|
||||||
|
testing.expectEqual('mark', mark1.entryType);
|
||||||
|
testing.expectEqual(0, mark1.duration);
|
||||||
|
testing.expectEqual(null, mark1.detail);
|
||||||
|
|
||||||
|
let mark2 = performance.mark("start", {startTime: 32939393.9});
|
||||||
|
testing.expectEqual(32939393.9, mark2.startTime);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id=getEntries>
|
||||||
|
{
|
||||||
|
// Clear any existing marks first
|
||||||
|
performance.clearMarks();
|
||||||
|
|
||||||
|
const entries1 = performance.getEntries();
|
||||||
|
const initialCount = entries1.length;
|
||||||
|
|
||||||
|
performance.mark("test1");
|
||||||
|
performance.mark("test2");
|
||||||
|
performance.mark("test3");
|
||||||
|
|
||||||
|
const entries2 = performance.getEntries();
|
||||||
|
testing.expectEqual(initialCount + 3, entries2.length);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id=getEntriesByType>
|
||||||
|
{
|
||||||
|
performance.clearMarks();
|
||||||
|
|
||||||
|
performance.mark("mark1");
|
||||||
|
performance.mark("mark2");
|
||||||
|
|
||||||
|
const marks = performance.getEntriesByType("mark");
|
||||||
|
testing.expectEqual(2, marks.length);
|
||||||
|
testing.expectEqual('mark1', marks[0].name);
|
||||||
|
testing.expectEqual('mark2', marks[1].name);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id=getEntriesByName>
|
||||||
|
{
|
||||||
|
performance.clearMarks();
|
||||||
|
|
||||||
|
performance.mark("myMark");
|
||||||
|
performance.mark("otherMark");
|
||||||
|
performance.mark("myMark");
|
||||||
|
|
||||||
|
const entries = performance.getEntriesByName("myMark");
|
||||||
|
testing.expectEqual(2, entries.length);
|
||||||
|
testing.expectEqual('myMark', entries[0].name);
|
||||||
|
testing.expectEqual('myMark', entries[1].name);
|
||||||
|
|
||||||
|
const byType = performance.getEntriesByName("myMark", "mark");
|
||||||
|
testing.expectEqual(2, byType.length);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id=clearMarks>
|
||||||
|
{
|
||||||
|
performance.clearMarks();
|
||||||
|
|
||||||
|
performance.mark("mark1");
|
||||||
|
performance.mark("mark2");
|
||||||
|
performance.mark("mark3");
|
||||||
|
|
||||||
|
let marks = performance.getEntriesByType("mark");
|
||||||
|
testing.expectEqual(3, marks.length);
|
||||||
|
|
||||||
|
// Clear specific mark
|
||||||
|
performance.clearMarks("mark2");
|
||||||
|
marks = performance.getEntriesByType("mark");
|
||||||
|
testing.expectEqual(2, marks.length);
|
||||||
|
testing.expectEqual('mark1', marks[0].name);
|
||||||
|
testing.expectEqual('mark3', marks[1].name);
|
||||||
|
|
||||||
|
// Clear all marks
|
||||||
|
performance.clearMarks();
|
||||||
|
marks = performance.getEntriesByType("mark");
|
||||||
|
testing.expectEqual(0, marks.length);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -1,20 +1,22 @@
|
|||||||
const js = @import("../js/js.zig");
|
const js = @import("../js/js.zig");
|
||||||
|
const Page = @import("../Page.zig");
|
||||||
const datetime = @import("../../datetime.zig");
|
const datetime = @import("../../datetime.zig");
|
||||||
|
|
||||||
pub fn registerTypes() []const type {
|
pub fn registerTypes() []const type {
|
||||||
return &.{
|
return &.{ Performance, Entry, Mark };
|
||||||
Performance,
|
|
||||||
Entry,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
const Performance = @This();
|
const Performance = @This();
|
||||||
|
|
||||||
_time_origin: u64,
|
_time_origin: u64,
|
||||||
|
_entries: std.ArrayListUnmanaged(*Entry) = .{},
|
||||||
|
|
||||||
pub fn init() Performance {
|
pub fn init() Performance {
|
||||||
return .{
|
return .{
|
||||||
._time_origin = datetime.milliTimestamp(.monotonic),
|
._time_origin = datetime.milliTimestamp(.monotonic),
|
||||||
|
._entries = .{},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,6 +30,75 @@ pub fn getTimeOrigin(self: *const Performance) f64 {
|
|||||||
return @floatFromInt(self._time_origin);
|
return @floatFromInt(self._time_origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mark(self: *Performance, name: []const u8, _options: ?Mark.Options, page: *Page) !*Mark {
|
||||||
|
const m = try Mark.init(name, _options, page);
|
||||||
|
try self._entries.append(page.arena, m._proto);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clearMarks(self: *Performance, mark_name: ?[]const u8) void {
|
||||||
|
if (mark_name) |name| {
|
||||||
|
// Remove specific mark by name
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < self._entries.items.len) {
|
||||||
|
const entry = self._entries.items[i];
|
||||||
|
if (entry._type == .mark and std.mem.eql(u8, entry._name, name)) {
|
||||||
|
_ = self._entries.orderedRemove(i);
|
||||||
|
} else {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Remove all marks
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < self._entries.items.len) {
|
||||||
|
const entry = self._entries.items[i];
|
||||||
|
if (entry._type == .mark) {
|
||||||
|
_ = self._entries.orderedRemove(i);
|
||||||
|
} else {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getEntries(self: *const Performance) []*Entry {
|
||||||
|
return self._entries.items;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getEntriesByType(self: *const Performance, entry_type: []const u8, page: *Page) ![]const *Entry {
|
||||||
|
var result: std.ArrayList(*Entry) = .empty;
|
||||||
|
|
||||||
|
for (self._entries.items) |entry| {
|
||||||
|
if (std.mem.eql(u8, entry.getEntryType(), entry_type)) {
|
||||||
|
try result.append(page.call_arena, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.items;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getEntriesByName(self: *const Performance, name: []const u8, entry_type: ?[]const u8, page: *Page) ![]const *Entry {
|
||||||
|
var result: std.ArrayList(*Entry) = .empty;
|
||||||
|
|
||||||
|
for (self._entries.items) |entry| {
|
||||||
|
if (!std.mem.eql(u8, entry._name, name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const et = entry_type orelse {
|
||||||
|
try result.append(page.call_arena, entry);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (std.mem.eql(u8, entry.getEntryType(), et)) {
|
||||||
|
try result.append(page.call_arena, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.items;
|
||||||
|
}
|
||||||
|
|
||||||
pub const JsApi = struct {
|
pub const JsApi = struct {
|
||||||
pub const bridge = js.Bridge(Performance);
|
pub const bridge = js.Bridge(Performance);
|
||||||
|
|
||||||
@@ -38,16 +109,21 @@ pub const JsApi = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const now = bridge.function(Performance.now, .{});
|
pub const now = bridge.function(Performance.now, .{});
|
||||||
|
pub const mark = bridge.function(Performance.mark, .{});
|
||||||
|
pub const clearMarks = bridge.function(Performance.clearMarks, .{});
|
||||||
|
pub const getEntries = bridge.function(Performance.getEntries, .{});
|
||||||
|
pub const getEntriesByType = bridge.function(Performance.getEntriesByType, .{});
|
||||||
|
pub const getEntriesByName = bridge.function(Performance.getEntriesByName, .{});
|
||||||
pub const timeOrigin = bridge.accessor(Performance.getTimeOrigin, null, .{});
|
pub const timeOrigin = bridge.accessor(Performance.getTimeOrigin, null, .{});
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Entry = struct {
|
pub const Entry = struct {
|
||||||
_duration: f64 = 0.0,
|
_duration: f64 = 0.0,
|
||||||
_entry_type: Type,
|
_type: Type,
|
||||||
_name: []const u8,
|
_name: []const u8,
|
||||||
_start_time: f64 = 0.0,
|
_start_time: f64 = 0.0,
|
||||||
|
|
||||||
const Type = enum {
|
const Type = union(enum) {
|
||||||
element,
|
element,
|
||||||
event,
|
event,
|
||||||
first_input,
|
first_input,
|
||||||
@@ -55,13 +131,13 @@ pub const Entry = struct {
|
|||||||
layout_shift,
|
layout_shift,
|
||||||
long_animation_frame,
|
long_animation_frame,
|
||||||
longtask,
|
longtask,
|
||||||
mark,
|
|
||||||
measure,
|
measure,
|
||||||
navigation,
|
navigation,
|
||||||
paint,
|
paint,
|
||||||
resource,
|
resource,
|
||||||
taskattribution,
|
taskattribution,
|
||||||
visibility_state,
|
visibility_state,
|
||||||
|
mark: *Mark,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn getDuration(self: *const Entry) f64 {
|
pub fn getDuration(self: *const Entry) f64 {
|
||||||
@@ -69,7 +145,7 @@ pub const Entry = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn getEntryType(self: *const Entry) []const u8 {
|
pub fn getEntryType(self: *const Entry) []const u8 {
|
||||||
return switch (self._entry_type) {
|
return switch (self._type) {
|
||||||
.first_input => "first-input",
|
.first_input => "first-input",
|
||||||
.largest_contentful_paint => "largest-contentful-paint",
|
.largest_contentful_paint => "largest-contentful-paint",
|
||||||
.layout_shift => "layout-shift",
|
.layout_shift => "layout-shift",
|
||||||
@@ -95,8 +171,58 @@ pub const Entry = struct {
|
|||||||
pub const prototype_chain = bridge.prototypeChain();
|
pub const prototype_chain = bridge.prototypeChain();
|
||||||
pub var class_id: bridge.ClassId = undefined;
|
pub var class_id: bridge.ClassId = undefined;
|
||||||
};
|
};
|
||||||
|
pub const name = bridge.accessor(Entry.getName, null, .{});
|
||||||
pub const duration = bridge.accessor(Entry.getDuration, null, .{});
|
pub const duration = bridge.accessor(Entry.getDuration, null, .{});
|
||||||
pub const entryType = bridge.accessor(Entry.getEntryType, null, .{});
|
pub const entryType = bridge.accessor(Entry.getEntryType, null, .{});
|
||||||
|
pub const startTime = bridge.accessor(Entry.getStartTime, null, .{});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Mark = struct {
|
||||||
|
_proto: *Entry,
|
||||||
|
_detail: ?js.Object,
|
||||||
|
|
||||||
|
const Options = struct {
|
||||||
|
detail: ?js.Object = null,
|
||||||
|
startTime: ?f64 = null,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn init(name: []const u8, _opts: ?Options, page: *Page) !*Mark {
|
||||||
|
const opts = _opts orelse Options{};
|
||||||
|
const start_time = opts.startTime orelse page.window._performance.now();
|
||||||
|
|
||||||
|
if (start_time < 0.0) {
|
||||||
|
return error.TypeError;
|
||||||
|
}
|
||||||
|
|
||||||
|
const detail = if (opts.detail) |d| try d.persist() else null;
|
||||||
|
const m = try page._factory.create(Mark{
|
||||||
|
._proto = undefined,
|
||||||
|
._detail = detail,
|
||||||
|
});
|
||||||
|
|
||||||
|
const entry = try page._factory.create(Entry{
|
||||||
|
._start_time = start_time,
|
||||||
|
._name = try page.dupeString(name),
|
||||||
|
._type = .{ .mark = m },
|
||||||
|
});
|
||||||
|
m._proto = entry;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getDetail(self: *const Mark) ?js.Object {
|
||||||
|
return self._detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const JsApi = struct {
|
||||||
|
pub const bridge = js.Bridge(Mark);
|
||||||
|
|
||||||
|
pub const Meta = struct {
|
||||||
|
pub const name = "PerformanceMark";
|
||||||
|
pub const prototype_chain = bridge.prototypeChain();
|
||||||
|
pub var class_id: bridge.ClassId = undefined;
|
||||||
|
};
|
||||||
|
pub const detail = bridge.accessor(Mark.getDetail, null, .{});
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user