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

Introduce CpuProfiler, CpuProfile, and CpuProfileNode #167

Merged
merged 25 commits into from
Oct 20, 2021

Conversation

genevieve
Copy link
Collaborator

@genevieve genevieve commented Sep 8, 2021

This PR introduces the CpuProfiler, CpuProfile, and CpuProfileNode classes from v8. It originally started by introducing each class separately with their respective functions but it was pointed out that this would require a lot more cgo calls for a user to actually get the entire profile that they want. Instead, it now internally loads everything once a user calls cpuProfiler.StopProfiling("profile-name") onto a CPUProfile go object which can be traversed by the user to print the relative details of the profile they want. This (1) speeds up the performance time by doing as much in c++ as possible and reducing the number of cgo calls that need to be made and (2) reduces the amount of code a user will need to write in order to get the entirety of the profile they are looking for.

There's more to do like:

  • introducing support for sampling and then returning that data in a useful way (add GetSample so we can call it during our tests and ensure we have a sample to reduce flakiness)
  • collecting line ticks and hit count

For now, this allows users to generate cpu profiles. Added some instructions to the readme to print the profile and followed a bit of the pattern from here for function name - script resource name - line number - column number formatting.

The default sampling interval is 1000 us = 1 millisecond and we seem to occasionally get profiles generated without the script. It's possible that the sampling is somehow happening before/after the script executes. One way to guarantee a sample has been taken for testing is to support CollectSample API on the profiler.

Genevieve L'Esperance added 3 commits September 6, 2021 10:40
- SamplesCount requires the intro of Sampler + StartSampleCount so will
  defer for now
- GetAllProfiles, GetProfile, DeleteProfile on profiler TODO
@codecov
Copy link

codecov bot commented Sep 8, 2021

Codecov Report

Merging #167 (439ebb1) into master (8d1f88b) will increase coverage by 0.40%.
The diff coverage is 100.00%.

❗ Current head 439ebb1 differs from pull request most recent head 946873e. Consider uploading reports for the commit 946873e to get more accurate results
Impacted file tree graph

@@            Coverage Diff             @@
##           master     #167      +/-   ##
==========================================
+ Coverage   95.38%   95.78%   +0.40%     
==========================================
  Files          12       16       +4     
  Lines         498      546      +48     
==========================================
+ Hits          475      523      +48     
  Misses         14       14              
  Partials        9        9              
Impacted Files Coverage Δ
backports.go 100.00% <100.00%> (ø)
cpuprofile.go 100.00% <100.00%> (ø)
cpuprofilenode.go 100.00% <100.00%> (ø)
cpuprofiler.go 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 8d1f88b...946873e. Read the comment docs.

Copy link
Collaborator

@tmc tmc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly LGTM, one small request.

cpuprofiler.go Show resolved Hide resolved
@tmc
Copy link
Collaborator

tmc commented Sep 8, 2021

Can you open an issue to add documentation around how to use these exposed types?

Copy link
Collaborator

@tmc tmc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I wonder if this is a good time to consider introducing some additional packages to expose different aspects of v8's api.

Having parity with the v8 namespace is certainly a nice quality but as we add more surface area it will make use of the package for newcomers more complicated. (I imagine most users won't initially leverage these types).

@genevieve mentioned that we could follow how v8 splits up header files (e.g. profiler, inspector).

@rogchap thoughts?

@dylanahsmith
Copy link
Collaborator

Having parity with the v8 namespace is certainly a nice quality but as we add more surface area it will make use of the package for newcomers more complicated. (I imagine most users won't initially leverage these types).

For this users, is this mostly a documentation problem? Note that this could easily introduce the opposite problem of making it harder for users to find functionality when it isn't clear which package it is in.

mentioned that we could follow how v8 splits up header files (e.g. profiler, inspector).

Note that there are 17 top-level header files in the version of v8 that v8go is currently using and v8 master now has
59, so I wouldn't follow that file structure too carefully. For instance, I would treat all the headers included by v8.h as if they are part of v8.h, which would also keep the correspondence fairly stable by coupling to V8's intentionally public API.

In order to split the packages, we might also need an internal/unsafe package that could expose an V8 pointers that need to be accessed from other packages.

cpuprofilenode.go Show resolved Hide resolved
cpuprofile.go Outdated Show resolved Hide resolved
cpuprofilenode.go Outdated Show resolved Hide resolved
cpuprofiler.go Outdated Show resolved Hide resolved
cpuprofilenode.go Outdated Show resolved Hide resolved
@genevieve genevieve marked this pull request as draft October 7, 2021 16:16
v8go.cc Outdated Show resolved Hide resolved
cpuprofiler.go Outdated Show resolved Hide resolved
cpuprofiler.go Outdated Show resolved Hide resolved
@genevieve genevieve marked this pull request as ready for review October 13, 2021 00:51
cpuprofiler.go Outdated Show resolved Hide resolved
cpuprofiler.go Outdated Show resolved Hide resolved
cpuprofiler.go Outdated Show resolved Hide resolved
cpuprofiler_test.go Outdated Show resolved Hide resolved
cpuprofiler.go Outdated Show resolved Hide resolved
cpuprofiler.go Outdated Show resolved Hide resolved
cpuprofiler_test.go Outdated Show resolved Hide resolved
cpuprofiler_test.go Outdated Show resolved Hide resolved
cpuprofiler_test.go Outdated Show resolved Hide resolved
cpuprofiler_test.go Outdated Show resolved Hide resolved
v8go.h Outdated Show resolved Hide resolved
cpuprofile.go Outdated Show resolved Hide resolved
cpuprofiler.go Outdated
Comment on lines 70 to 71
startTime: timeUnixMicro(-int64(profile.startTime)),
endTime: timeUnixMicro(-int64(profile.endTime)),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The negation of the monotonic time values just seems wrong. I think the only reason why monotonic time values might be negative would be when these values are subtracted without knowing the ordering of the times to produce a possibly negative duration. The C standard unfortunately considering unsigned underflow to be defined behaviour, so the compiler won't even warn when it can detect this, so signed numbers may end up getting used to represent unsigned values.

It seems like this change was made to make the if cpuProfile.GetStartTime().Before(cpuProfile.GetEndTime()) { test pass, rather than using it as a sign that the test may be wrong.

Suggested change
startTime: timeUnixMicro(-int64(profile.startTime)),
endTime: timeUnixMicro(-int64(profile.endTime)),
startTime: timeUnixMicro(int64(profile.startTime)),
endTime: timeUnixMicro(int64(profile.endTime)),

t.Errorf("expected (root), but got %v", root.GetFunctionName())
}

if cpuProfile.GetStartTime().Before(cpuProfile.GetEndTime()) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want start time to be before the end time, not to give a test error in that case.

Suggested change
if cpuProfile.GetStartTime().Before(cpuProfile.GetEndTime()) {
if !cpuProfile.GetStartTime().Before(cpuProfile.GetEndTime()) {

cpuprofile_test.go Show resolved Hide resolved
cpuprofile.go Outdated Show resolved Hide resolved
Copy link
Collaborator

@dylanahsmith dylanahsmith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed my suggested changes from my PR review

@genevieve genevieve merged commit 6dff945 into rogchap:master Oct 20, 2021
@genevieve genevieve mentioned this pull request Feb 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants