Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CPU Profiling capability that works async #336

Merged
merged 10 commits into from
Feb 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ build/
node_modules/
package-lock.json
out/
.cache/
compile_commands.json
43 changes: 19 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -253,10 +253,16 @@ when you transfer a `Reference` instance via some method which accepts transfera
will also include underlying reference handles created by isolated-vm like `Script` or `Context`
objects.

##### `isolate.createCpuProfiler()` *[CpuProfiler]*
Create a CPU profiler, for performance profiling
##### `isolate.startCpuProfiler(title)` *[void]*
Start a CPU profiler in the isolate, for performance profiling. It only collects cpu profiles when
the isolate is active in a thread.

* **return** A [`CpuProfiler`](#class-cpu-profiler) object.
##### `isolate.stopCpuProfiler(title)` *[Promise<Array<ThreadCpuProfile>>]*
Stop a CPU profiler previously started using the same title. It returns an array of profiles dependening
on how many times the isolate get activated in a thread.


* **return** An array of [`ThreadCpuProfile`](#thread-cpu-profile) objects.

### Class: `Context` *[transferable]*
A context is a sandboxed execution environment within an isolate. Each context contains its own
Expand Down Expand Up @@ -562,26 +568,6 @@ will still remain in memory, but this handle will no longer be active. Disposing
instances isn't super important, v8 is a lot better at cleaning these up automatically because
there's no inter-isolate dependencies.

### Class: `CpuProfiler`
A CpuProfiler is a cpu profiler allows you to run cpu profiling against the application
running inside a specific `isolate`. Which works similar to `console.profile` & `console.profileEnd`.

##### `profiler.startProfiling(title, recordSamples)` *[v8 CPUProfiler::StartProfiling](https://v8docs.nodesource.com/node-16.0/d2/d34/classv8_1_1_cpu_profiler.html#adc48f6de278c03fde38e74e6f1bd63a6)*

* `title` *[string]*
* `recordSamples` *[boolean]*

#### `profiler.stopProfiling(title)`
Stop the CPU profiling, the title should be the same as the one used in `startProfiling`.
After calling this API, the profiler will be disposed. If you want to run cpu profiling
again, you will need to call `isolate.createCpuProfiler()` again for a new CPU Profiler.

* `title` *[string]* should be the same string as `startProfiling`
* **return** *[CpuProfile]*

#### `profiler.dispose()`
Cleanup the cpu profiler from `v8` to release the resources occupied by the CPU profiler.

### Shared Options
Many methods in this library accept common options between them. They are documented here instead of
being colocated with each instance.
Expand Down Expand Up @@ -629,11 +615,20 @@ More advanced situations like transferring ownership of `ArrayBuffer` instances
use of [`ExternalCopy`](#class-externalcopy-transferable) or
[`Reference`](#class-reference-transferable).



##### `ThreadCpuProfile`
It's a object that contains a thread id and a [CpuProfile](#cpuprofile) info.

* `threadId` *[number]* - The thread that isolate runs on.
* `profile` *[CpuProfile]* - The [CpuProfile](#cpuprofile).

##### `CpuProfile`
The CpuProfile Object that can be `JSON.stringify(cpuProfile)`, and save to any external file system
for later reloaded into chrome dev tool or any other js performance tool to review.

* `title` *[string]* - The profile title.
The format should matches the definition in: https://chromedevtools.github.io/devtools-protocol/tot/Profiler/#type-Profile

* `startTime` *[number]* - The start timestamp when calling `.startProfiling`.
* `endTime` *[number]* - The end timestamp when calling `.stopProfiling`,
* `samples` *[Array<number>]* - All sample node id has been collected.
Expand Down
4 changes: 2 additions & 2 deletions binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
'src/external_copy/string.cc',
'src/isolate/allocator_nortti.cc',
'src/isolate/environment.cc',
"src/isolate/cpu_profile_manager.cc",
'src/isolate/executor.cc',
'src/isolate/holder.cc',
'src/isolate/inspector.cc',
Expand All @@ -86,8 +87,7 @@
'src/module/reference_handle.cc',
'src/module/script_handle.cc',
'src/module/session_handle.cc',
'src/module/transferable.cc',
"src/module/cpu_profiler_handle.cc"
'src/module/transferable.cc'
],
'conditions': [
[ 'OS != "win"', {
Expand Down
43 changes: 17 additions & 26 deletions isolated-vm.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,15 +108,23 @@ declare module "isolated-vm" {
getHeapStatisticsSync(): HeapStatistics;

/**
* Returns a Cpu Profiler from v8 for this specific isolate.
* Start profiling against the isolate with a specific title
*
* This function only returns a `single-use` CpuProfiler, once the
* `stopProfiling` is called, it will automatically dispose the
* `CpuProfiler`.
* @param title the profile title
*/
startCpuProfiler(title: string): void;

/**
* Stop profiling against the isolate with a specific title
* that started via `startCpuProfiler`. It will return more
* than one cpu profiles because isolate can be run in different
* threads. The `ThreadCpuProfile` contains the `thread_id` that
* the isolate was running in.
*
* Any new CPU profiling require to call this function again.
* @param title
*/
createCpuProfiler(): CpuProfiler;
stopCpuProfiler(title: string): Promise<ThreadCpuProfile[]>;

}

export type IsolateOptions = {
Expand Down Expand Up @@ -598,29 +606,12 @@ declare module "isolated-vm" {
createSync(context: Context): Reference<any>;
}

export class CpuProfiler {

/**
* Similar to `console.profile(title)`
* @param title The title of the cpu profile
* @param recordSample Should record sample or not, `true` to genereate data.
*/
startProfiling(title: string, recordSample: boolean);

/**
* Similar to `console.profileEnd(title)`
* @param title The title of cpu profile
*/
stopProfiling(title: string): CpuProfile;

/**
* Dispose the CpuProfiler
*/
dispose(): void;
export type ThreadCpuProfile = {
threadId: number;
profile: CpuProfile;
}

export type CpuProfile = {
title: string;
startTime: number;
endTime: number;
samples: number[];
Expand Down
Loading