diff --git a/.github/actions/install/action.yml b/.github/actions/install/action.yml index 842f39cc..9e4b8e38 100644 --- a/.github/actions/install/action.yml +++ b/.github/actions/install/action.yml @@ -13,7 +13,7 @@ inputs: zig-v8: description: 'zig v8 version to install' required: false - default: 'v0.2.4' + default: 'v0.2.5' v8: description: 'v8 version to install' required: false diff --git a/Dockerfile b/Dockerfile index e683674a..5ee73356 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM debian:stable-slim ARG MINISIG=0.12 ARG ZIG_MINISIG=RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U ARG V8=14.0.365.4 -ARG ZIG_V8=v0.2.4 +ARG ZIG_V8=v0.2.5 ARG TARGETPLATFORM RUN apt-get update -yq && \ diff --git a/build.zig.zon b/build.zig.zon index 191e1f0c..92506e1f 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -6,10 +6,10 @@ .minimum_zig_version = "0.15.2", .dependencies = .{ .v8 = .{ - .url = "https://github.com/lightpanda-io/zig-v8-fork/archive/v0.2.4.tar.gz", - .hash = "v8-0.0.0-xddH66YvBAD0YI9xr6F0Xgnw9wN30FdZ10FLyuoV3e66", + .url = "https://github.com/lightpanda-io/zig-v8-fork/archive/v0.2.5.tar.gz", + .hash = "v8-0.0.0-xddH641NBAC3MqKV44YCkwvnUenhQyGlgJI8OScx0tlP", }, - // .v8 = .{ .path = "../zig-v8-fork" }, + //.v8 = .{ .path = "../zig-v8-fork" }, .@"boringssl-zig" = .{ .url = "git+https://github.com/Syndica/boringssl-zig.git#c53df00d06b02b755ad88bbf4d1202ed9687b096", .hash = "boringssl-0.1.0-VtJeWehMAAA4RNnwRnzEvKcS9rjsR1QVRw1uJrwXxmVK", diff --git a/src/browser/js/Context.zig b/src/browser/js/Context.zig index e0d1f3de..aa873438 100644 --- a/src/browser/js/Context.zig +++ b/src/browser/js/Context.zig @@ -50,6 +50,8 @@ entered: bool, cpu_profiler: ?*v8.CpuProfiler = null, +heap_profiler: ?*v8.HeapProfiler = null, + // references Env.templates templates: []*const v8.FunctionTemplate, @@ -823,6 +825,10 @@ pub fn startCpuProfiler(self: *Context) void { @compileError("CPU Profiling is only available in debug builds"); } + var ls: js.Local.Scope = undefined; + self.localScope(&ls); + defer ls.deinit(); + std.debug.assert(self.cpu_profiler == null); v8.v8__CpuProfiler__UseDetailedSourcePositionsForProfiling(self.isolate.handle); @@ -833,8 +839,55 @@ pub fn startCpuProfiler(self: *Context) void { } pub fn stopCpuProfiler(self: *Context) ![]const u8 { + var ls: js.Local.Scope = undefined; + self.localScope(&ls); + defer ls.deinit(); + const title = self.isolate.initStringHandle("v8_cpu_profile"); const handle = v8.v8__CpuProfiler__StopProfiling(self.cpu_profiler.?, title) orelse return error.NoProfiles; const string_handle = v8.v8__CpuProfile__Serialize(handle, self.isolate.handle) orelse return error.NoProfile; - return self.jsStringToZig(string_handle, .{}); + return ls.local.jsStringToZig(string_handle, .{}); +} + +pub fn startHeapProfiler(self: *Context) void { + if (comptime !IS_DEBUG) { + @compileError("Heap Profiling is only available in debug builds"); + } + + var ls: js.Local.Scope = undefined; + self.localScope(&ls); + defer ls.deinit(); + + std.debug.assert(self.heap_profiler == null); + const heap_profiler = v8.v8__HeapProfiler__Get(self.isolate.handle).?; + + // Sample every 32KB, stack depth 32 + v8.v8__HeapProfiler__StartSamplingHeapProfiler(heap_profiler, 32 * 1024, 32); + v8.v8__HeapProfiler__StartTrackingHeapObjects(heap_profiler, true); + + self.heap_profiler = heap_profiler; +} + +pub fn stopHeapProfiler(self: *Context) !struct{[]const u8, []const u8} { + var ls: js.Local.Scope = undefined; + self.localScope(&ls); + defer ls.deinit(); + + const allocating = blk: { + const profile = v8.v8__HeapProfiler__GetAllocationProfile(self.heap_profiler.?); + const string_handle = v8.v8__AllocationProfile__Serialize(profile, self.isolate.handle); + v8.v8__HeapProfiler__StopSamplingHeapProfiler(self.heap_profiler.?); + v8.v8__AllocationProfile__Delete(profile); + break :blk try ls.local.jsStringToZig(string_handle, .{}); + }; + + const snapshot = blk: { + const snapshot = v8.v8__HeapProfiler__TakeHeapSnapshot(self.heap_profiler.?, null) orelse return error.NoProfiles; + const string_handle = v8.v8__HeapSnapshot__Serialize(snapshot, self.isolate.handle); + v8.v8__HeapProfiler__StopTrackingHeapObjects(self.heap_profiler.?); + v8.v8__HeapSnapshot__Delete(snapshot); + break :blk try ls.local.jsStringToZig(string_handle, .{}); + }; + + return .{allocating, snapshot}; } diff --git a/src/lightpanda.zig b/src/lightpanda.zig index 361d872d..ade06ceb 100644 --- a/src/lightpanda.zig +++ b/src/lightpanda.zig @@ -51,7 +51,7 @@ pub fn fetch(app: *App, url: [:0]const u8, opts: FetchOpts) !void { // defer { // if (page.js.stopCpuProfiler()) |profile| { // std.fs.cwd().writeFile(.{ - // .sub_path = "v8/profile.json", + // .sub_path = ".lp-cache/cpu_profile.json", // .data = profile, // }) catch |err| { // log.err(.app, "profile write error", .{ .err = err }); @@ -61,6 +61,27 @@ pub fn fetch(app: *App, url: [:0]const u8, opts: FetchOpts) !void { // } // } + // // Comment this out to get a heap V8 heap profil + // page.js.startHeapProfiler(); + // defer { + // if (page.js.stopHeapProfiler()) |profile| { + // std.fs.cwd().writeFile(.{ + // .sub_path = ".lp-cache/allocating.heapprofile", + // .data = profile.@"0", + // }) catch |err| { + // log.err(.app, "allocating write error", .{ .err = err }); + // }; + // std.fs.cwd().writeFile(.{ + // .sub_path = ".lp-cache/snapshot.heapsnapshot", + // .data = profile.@"1", + // }) catch |err| { + // log.err(.app, "heapsnapshot write error", .{ .err = err }); + // }; + // } else |err| { + // log.err(.app, "profile error", .{ .err = err }); + // } + // } + _ = try page.navigate(url, .{ .reason = .address_bar, .kind = .{ .push = null },