mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-28 22:53:28 +00:00
Expose v8 CpuProfiler + add fast properties for some window properties
First, this exposes the v8 Profiler. Right now it's just a commented-out block in `fetch` and meant for internal debugging. Depends on: https://github.com/lightpanda-io/zig-v8-fork/pull/105 Use postAttach on Window to attach "static" properties. This comes from profiling (lightpanda.io) and seeing window.get_self called tens of thousands of times.
This commit is contained in:
@@ -5,8 +5,8 @@
|
|||||||
.fingerprint = 0xda130f3af836cea0,
|
.fingerprint = 0xda130f3af836cea0,
|
||||||
.dependencies = .{
|
.dependencies = .{
|
||||||
.v8 = .{
|
.v8 = .{
|
||||||
.url = "https://github.com/lightpanda-io/zig-v8-fork/archive/5ce9ade6c6d7f7ab9ab4582a6b1b36fdc8e246e2.tar.gz",
|
.url = "https://github.com/lightpanda-io/zig-v8-fork/archive/305bb3706716d32d59b2ffa674731556caa1002b.tar.gz",
|
||||||
.hash = "v8-0.0.0-xddH6yTGAwA__kfiDozsVXL2_jnycrtDUfR8kIADQFUz",
|
.hash = "v8-0.0.0-xddH63bVAwBSEobaUok9J0er1FqsvEujCDDVy6ItqKQ5",
|
||||||
},
|
},
|
||||||
//.v8 = .{ .path = "../zig-v8-fork" }
|
//.v8 = .{ .path = "../zig-v8-fork" }
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -136,14 +136,6 @@ pub const Window = struct {
|
|||||||
self.onload_callback = null;
|
self.onload_callback = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_window(self: *Window) *Window {
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_navigator(self: *Window) *Navigator {
|
|
||||||
return &self.navigator;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_location(self: *Window) *Location {
|
pub fn get_location(self: *Window) *Location {
|
||||||
return &self.location;
|
return &self.location;
|
||||||
}
|
}
|
||||||
@@ -152,22 +144,6 @@ pub const Window = struct {
|
|||||||
return page.navigateFromWebAPI(url, .{ .reason = .script });
|
return page.navigateFromWebAPI(url, .{ .reason = .script });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_console(self: *Window) *Console {
|
|
||||||
return &self.console;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_crypto(self: *Window) *Crypto {
|
|
||||||
return &self.crypto;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_self(self: *Window) *Window {
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_parent(self: *Window) *Window {
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
// frames return the window itself, but accessing it via a pseudo
|
// frames return the window itself, but accessing it via a pseudo
|
||||||
// array returns the Window object corresponding to the given frame or
|
// array returns the Window object corresponding to the given frame or
|
||||||
// iframe.
|
// iframe.
|
||||||
@@ -205,10 +181,6 @@ pub const Window = struct {
|
|||||||
return frames.get_length();
|
return frames.get_length();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_top(self: *Window) *Window {
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_document(self: *Window) ?*parser.DocumentHTML {
|
pub fn get_document(self: *Window) ?*parser.DocumentHTML {
|
||||||
return self.document;
|
return self.document;
|
||||||
}
|
}
|
||||||
@@ -243,14 +215,6 @@ pub const Window = struct {
|
|||||||
return &self.storage_shelf.?.bucket.session;
|
return &self.storage_shelf.?.bucket.session;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_performance(self: *Window) *Performance {
|
|
||||||
return &self.performance;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_screen(self: *Window) *Screen {
|
|
||||||
return &self.screen;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_CSS(self: *Window) *Css {
|
pub fn get_CSS(self: *Window) *Css {
|
||||||
return &self.css;
|
return &self.css;
|
||||||
}
|
}
|
||||||
@@ -463,6 +427,18 @@ pub const Window = struct {
|
|||||||
// and thus the target has already been set to the document.
|
// and thus the target has already been set to the document.
|
||||||
return self.base.redispatchEvent(evt);
|
return self.base.redispatchEvent(evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn postAttach(self: *Window, js_this: js.This) !void {
|
||||||
|
try js_this.set("top", self, .{});
|
||||||
|
try js_this.set("self", self, .{});
|
||||||
|
try js_this.set("parent", self, .{});
|
||||||
|
try js_this.set("window", self, .{});
|
||||||
|
try js_this.set("crypto", &self.crypto, .{});
|
||||||
|
try js_this.set("screen", &self.screen, .{});
|
||||||
|
try js_this.set("console", &self.console, .{});
|
||||||
|
try js_this.set("navigator", &self.navigator, .{});
|
||||||
|
try js_this.set("performance", &self.performance, .{});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const TimerCallback = struct {
|
const TimerCallback = struct {
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ isolate: v8.Isolate,
|
|||||||
v8_context: v8.Context,
|
v8_context: v8.Context,
|
||||||
handle_scope: ?v8.HandleScope,
|
handle_scope: ?v8.HandleScope,
|
||||||
|
|
||||||
|
cpu_profiler: ?v8.CpuProfiler = null,
|
||||||
|
|
||||||
// references Env.templates
|
// references Env.templates
|
||||||
templates: []v8.FunctionTemplate,
|
templates: []v8.FunctionTemplate,
|
||||||
|
|
||||||
@@ -1819,6 +1821,11 @@ fn zigJsonToJs(isolate: v8.Isolate, v8_context: v8.Context, value: std.json.Valu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getGlobalThis(self: *Context) js.This {
|
||||||
|
const js_global = self.v8_context.getGlobal();
|
||||||
|
return .{ .obj = .{ .js_obj = js_global, .context = self } };
|
||||||
|
}
|
||||||
|
|
||||||
// == Misc ==
|
// == Misc ==
|
||||||
// An interface for types that want to have their jsDeinit function to be
|
// An interface for types that want to have their jsDeinit function to be
|
||||||
// called when the call context ends
|
// called when the call context ends
|
||||||
@@ -1847,3 +1854,26 @@ const DestructorCallback = struct {
|
|||||||
self.destructorFn(self.ptr);
|
self.destructorFn(self.ptr);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// == Profiler ==
|
||||||
|
pub fn startCpuProfiler(self: *Context) void {
|
||||||
|
if (builtin.mode != .Debug) {
|
||||||
|
// Still testing this out, don't have it properly exposed, so add this
|
||||||
|
// guard for the time being to prevent any accidental/weird prod issues.
|
||||||
|
@compileError("CPU Profiling is only available in debug builds");
|
||||||
|
}
|
||||||
|
|
||||||
|
std.debug.assert(self.cpu_profiler == null);
|
||||||
|
v8.CpuProfiler.useDetailedSourcePositionsForProfiling(self.isolate);
|
||||||
|
const cpu_profiler = v8.CpuProfiler.init(self.isolate);
|
||||||
|
const title = self.isolate.initStringUtf8("v8_cpu_profile");
|
||||||
|
cpu_profiler.startProfiling(title);
|
||||||
|
self.cpu_profiler = cpu_profiler;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stopCpuProfiler(self: *Context) ![]const u8 {
|
||||||
|
const title = self.isolate.initStringUtf8("v8_cpu_profile");
|
||||||
|
const profile = self.cpu_profiler.?.stopProfiling(title) orelse unreachable;
|
||||||
|
const serialized = profile.serialize(self.isolate).?;
|
||||||
|
return self.jsStringToZig(serialized, .{});
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ pub fn setIndex(self: Object, index: u32, value: anytype, opts: SetOpts) !void {
|
|||||||
return self.set(key, value, opts);
|
return self.set(key, value, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(self: Object, key: []const u8, value: anytype, opts: SetOpts) !void {
|
pub fn set(self: Object, key: []const u8, value: anytype, opts: SetOpts) error{ FailedToSet, OutOfMemory }!void {
|
||||||
const context = self.context;
|
const context = self.context;
|
||||||
|
|
||||||
const js_key = v8.String.initUtf8(context.isolate, key);
|
const js_key = v8.String.initUtf8(context.isolate, key);
|
||||||
|
|||||||
@@ -849,7 +849,7 @@ pub const Page = struct {
|
|||||||
_ = self.session.browser.transfer_arena.reset(.{ .retain_with_limit = 4 * 1024 });
|
_ = self.session.browser.transfer_arena.reset(.{ .retain_with_limit = 4 * 1024 });
|
||||||
}
|
}
|
||||||
|
|
||||||
// extracted because this sis called from tests to set things up.
|
// extracted because this is called from tests to set things up.
|
||||||
pub fn setDocument(self: *Page, html_doc: *parser.DocumentHTML) !void {
|
pub fn setDocument(self: *Page, html_doc: *parser.DocumentHTML) !void {
|
||||||
const doc = parser.documentHTMLToDocument(html_doc);
|
const doc = parser.documentHTMLToDocument(html_doc);
|
||||||
try parser.documentSetDocumentURI(doc, self.url.raw);
|
try parser.documentSetDocumentURI(doc, self.url.raw);
|
||||||
|
|||||||
18
src/main.zig
18
src/main.zig
@@ -165,6 +165,24 @@ fn run(alloc: Allocator) !void {
|
|||||||
// page
|
// page
|
||||||
const page = try session.createPage();
|
const page = try session.createPage();
|
||||||
|
|
||||||
|
// // Comment this out to get a profile of the JS code in v8/profile.json.
|
||||||
|
// // You can open this in Chrome's profiler.
|
||||||
|
// // I've seen it generate invalid JSON, but I'm not sure why. It only
|
||||||
|
// // happens rarely, and I manually fix the file.
|
||||||
|
// page.js.startCpuProfiler();
|
||||||
|
// defer {
|
||||||
|
// if (page.js.stopCpuProfiler()) |profile| {
|
||||||
|
// std.fs.cwd().writeFile(.{
|
||||||
|
// .sub_path = "v8/profile.json",
|
||||||
|
// .data = profile,
|
||||||
|
// }) catch |err| {
|
||||||
|
// log.err(.app, "profile write error", .{ .err = err });
|
||||||
|
// };
|
||||||
|
// } else |err| {
|
||||||
|
// log.err(.app, "profile error", .{ .err = err });
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
_ = page.navigate(url, .{}) catch |err| switch (err) {
|
_ = page.navigate(url, .{}) catch |err| switch (err) {
|
||||||
error.UnsupportedUriScheme, error.UriMissingHost => {
|
error.UnsupportedUriScheme, error.UriMissingHost => {
|
||||||
log.fatal(.app, "invalid fetch URL", .{ .err = err, .url = url });
|
log.fatal(.app, "invalid fetch URL", .{ .err = err, .url = url });
|
||||||
|
|||||||
Reference in New Issue
Block a user