Merge pull request #2220 from lightpanda-io/performance_observer_functions

Add getEntriesByType and getEntriesByName to PerformanceObserver entr…
This commit is contained in:
Karl Seguin
2026-04-24 16:35:32 +08:00
committed by GitHub
3 changed files with 106 additions and 21 deletions

View File

@@ -69,6 +69,77 @@
testing.expectEqual(['mark', 'measure'], PerformanceObserver.supportedEntryTypes);
</script>
<script id="list_get_entries_by_type">
{
performance.clearMarks();
performance.clearMeasures();
const observer = new PerformanceObserver((list) => {
const marks = list.getEntriesByType("mark");
testing.expectEqual(true, marks instanceof Array);
testing.expectEqual(2, marks.length);
testing.expectEqual("lbt1", marks[0].name);
testing.expectEqual("mark", marks[0].entryType);
testing.expectEqual("lbt2", marks[1].name);
const measures = list.getEntriesByType("measure");
testing.expectEqual(1, measures.length);
testing.expectEqual("lbtMeasure", measures[0].name);
testing.expectEqual("measure", measures[0].entryType);
// A type that's observed but has no entries returns an empty array.
const resources = list.getEntriesByType("resource");
testing.expectEqual(true, resources instanceof Array);
testing.expectEqual(0, resources.length);
observer.disconnect();
});
observer.observe({ entryTypes: ["mark", "measure"] });
performance.mark("lbt1");
performance.mark("lbt2");
performance.measure("lbtMeasure");
}
</script>
<script id="list_get_entries_by_name">
{
performance.clearMarks();
performance.clearMeasures();
const observer = new PerformanceObserver((list) => {
// Without entryType, any type matching the name is returned.
const shared = list.getEntriesByName("lbnShared");
testing.expectEqual(true, shared instanceof Array);
testing.expectEqual(2, shared.length);
// With entryType, only entries of that type are returned.
const sharedMark = list.getEntriesByName("lbnShared", "mark");
testing.expectEqual(1, sharedMark.length);
testing.expectEqual("mark", sharedMark[0].entryType);
const sharedMeasure = list.getEntriesByName("lbnShared", "measure");
testing.expectEqual(1, sharedMeasure.length);
testing.expectEqual("measure", sharedMeasure[0].entryType);
// Name mismatch -> empty array.
const missing = list.getEntriesByName("lbnMissing");
testing.expectEqual(0, missing.length);
// Name matches but type doesn't -> empty array.
const wrongType = list.getEntriesByName("lbnOnlyMark", "measure");
testing.expectEqual(0, wrongType.length);
observer.disconnect();
});
observer.observe({ entryTypes: ["mark", "measure"] });
performance.mark("lbnShared");
performance.measure("lbnShared");
performance.mark("lbnOnlyMark");
}
</script>
<script id="buffered_option">
{
// Clear marks from previous tests so we get a precise count

View File

@@ -1,15 +1,16 @@
const std = @import("std");
const js = @import("../js/js.zig");
const Frame = @import("../Frame.zig");
const datetime = @import("../../datetime.zig");
const EventCounts = @import("EventCounts.zig");
const Allocator = std.mem.Allocator;
pub fn registerTypes() []const type {
return &.{ Performance, Entry, Mark, Measure, PerformanceTiming, PerformanceNavigation };
}
const std = @import("std");
const Performance = @This();
_time_origin: u64,
@@ -188,32 +189,34 @@ pub fn getEntries(self: *const Performance) []*Entry {
}
pub fn getEntriesByType(self: *const Performance, entry_type: []const u8, frame: *Frame) ![]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(frame.call_arena, entry);
}
}
return result.items;
return filterEntriesByType(frame.call_arena, self._entries.items, entry_type);
}
pub fn getEntriesByName(self: *const Performance, name: []const u8, entry_type: ?[]const u8, frame: *Frame) ![]const *Entry {
return filterEntriesByName(frame.call_arena, self._entries.items, name, entry_type);
}
// Also used by PerformanceObserver
pub fn filterEntriesByType(arena: Allocator, list: []*Entry, entry_type: []const u8) ![]const *Entry {
var result: std.ArrayList(*Entry) = .empty;
for (list) |entry| {
if (std.mem.eql(u8, entry.getEntryType(), entry_type)) {
try result.append(arena, entry);
}
}
return result.items;
}
// Also used by PerformanceObserver
pub fn filterEntriesByName(arena: Allocator, list: []*Entry, name: []const u8, entry_type: ?[]const u8) ![]const *Entry {
var result: std.ArrayList(*Entry) = .empty;
for (self._entries.items) |entry| {
for (list) |entry| {
if (!std.mem.eql(u8, entry._name, name)) {
continue;
}
const et = entry_type orelse {
try result.append(frame.call_arena, entry);
continue;
};
if (std.mem.eql(u8, entry.getEntryType(), et)) {
try result.append(frame.call_arena, entry);
if (entry_type == null or std.mem.eql(u8, entry.getEntryType(), entry_type.?)) {
try result.append(arena, entry);
}
}

View File

@@ -24,6 +24,7 @@ const Frame = @import("../Frame.zig");
const Performance = @import("Performance.zig");
const log = lp.log;
const Execution = js.Execution;
pub fn registerTypes() []const type {
return &.{ PerformanceObserver, EntryList };
@@ -203,10 +204,18 @@ pub const JsApi = struct {
pub const EntryList = struct {
_entries: []*Performance.Entry,
pub fn getEntries(self: *const EntryList) []*Performance.Entry {
pub fn getEntries(self: *const EntryList) []const *Performance.Entry {
return self._entries;
}
pub fn getEntriesByType(self: *const EntryList, entry_type: []const u8, exec: *Execution) ![]const *Performance.Entry {
return Performance.filterEntriesByType(exec.call_arena, self._entries, entry_type);
}
pub fn getEntriesByName(self: *const EntryList, name: []const u8, entry_type: ?[]const u8, exec: *Execution) ![]const *Performance.Entry {
return Performance.filterEntriesByName(exec.call_arena, self._entries, name, entry_type);
}
pub const JsApi = struct {
pub const bridge = js.Bridge(EntryList);
@@ -217,6 +226,8 @@ pub const EntryList = struct {
};
pub const getEntries = bridge.function(EntryList.getEntries, .{});
pub const getEntriesByType = bridge.function(EntryList.getEntriesByType, .{});
pub const getEntriesByName = bridge.function(EntryList.getEntriesByName, .{});
};
};