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

feat(core): Deno.core.heapStats() #9659

Merged
merged 8 commits into from
Mar 23, 2021
Merged

Conversation

AaronO
Copy link
Contributor

@AaronO AaronO commented Mar 3, 2021

This implements Deno.core.heapStats() so we can programatically measure isolate heap-usage (for benchmarks, etc...)

Sample output

❯ ./target/release/deno eval "console.log(Deno.core.heapStats())"
{
  total_heap_size: 3473408,
  total_heap_size_executable: 262144,
  total_physical_size: 2650012,
  total_available_size: 1515724108,
  total_global_handles_size: 8192,
  used_global_handles_size: 192,
  used_heap_size: 2874528,
  heap_size_limit: 1518338048,
  malloced_memory: 73860,
  external_memory: 5763,
  peak_malloced_memory: 58200,
  number_of_native_contexts: 1,
  number_of_detached_contexts: 0
}

Heap usage

.used_heap_size is the most relevant individual metric

With 1.8.0 it has grown from ~2MB to ~2.25MB (most likely due to the added JS for WebGPU, ~190kb of JS src)
I had originally reported 2MB => 3MB since I was sampling on a debug release

This is measured by:

❯ ./target/release/deno eval --v8-flags=--expose-gc "gc(); console.log(Deno.core.heapStats().used_heap_size/1e6)"
2.27596

Notes

  • This is implemented as a core function since ops don't have explicit access to the isolate.
  • It might make sense to integrate this with Deno.metrics at some point (to have a single func to get general metrics).
  • I've preserved the naming of the props in snake case, can change that to camel case if required.
  • Debug builds have a higher baseline than release (originally causing me to over-report the 1.8.0 increase)
  • Baseline should be measured after a GC

danopia added a commit to cloudydeno/deno-openmetrics_exporter that referenced this pull request Mar 3, 2021
Copy link
Contributor

@bnoordhuis bnoordhuis left a comment

Choose a reason for hiding this comment

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

Needs tests but other than that the technical side of the PR looks good to me, thanks.

Another maintainer should weigh in on the API.

}

// HeapStats stores values from a isolate.get_heap_statistics() call
struct HeapStats {
Copy link
Contributor

Choose a reason for hiding this comment

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

I assume you're wrapping v8::HeapStatistics because that makes it easier to serialize in the future?

Copy link
Contributor Author

@AaronO AaronO Mar 3, 2021

Choose a reason for hiding this comment

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

Exactly, with serde_v8 (and the new op-ABI) all the set_prop() calls would become a one-liner to_v8() and by keeping it in a struct we can have serde handle the camelCase-ification (if desired).

There are other core binding funcs that will be simplified with serde_v8, e.g: get_proxy_details and get_promise_details conceptually return tuples, which serde_v8 can serialize to JS arrays (removing a fair amount of boilerplate in each function)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I could probably add some simple alloc-dealloc tests (of large arrays) to ensure they are correctly reflected in the metrics.

Anything else that warrants testing in your opinion ?

Copy link
Member

Choose a reason for hiding this comment

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

@AaronO such test would be sufficient

@caspervonb
Copy link
Contributor

Nit; we should probably camelCase these properties?

@bartlomieju
Copy link
Member

Nit; we should probably camelCase these properties?

Yes

@AaronO
Copy link
Contributor Author

AaronO commented Mar 3, 2021

@caspervonb @bartlomieju Here's my reasoning:

  • If it's exposed via Deno.core.* I would simply follow the internal naming conventions leave it in snake_case
  • If it's exposed for "broad-consumption" in Deno.* I would not only switch it to camelCase but also rename the keys, since they're currently quite verbose (given that if they're behind a heapStats() call or a .heap sub-obj of Deno.metrics() context clarifies meaning)

Maybe something like this:

{
  heapTotal,
  heapExecutable,
  physical,
  available,
  globalHandlesTotal,
  globalHandlesUsed,
  heapUsed,
  heapLimit,
  malloced,
  external,
  mallocedPeak,
  nativeContexts,
  detachedContexts,
}

(Not alphabetically sorted/grouped with new names)

vs

{
  total_heap_size,
  total_heap_size_executable,
  total_physical_size,
  total_available_size,
  total_global_handles_size,
  used_global_handles_size,
  used_heap_size,
  heap_size_limit,
  malloced_memory,
  external_memory,
  peak_malloced_memory,
  number_of_native_contexts,
  number_of_detached_contexts,
}

@ry
Copy link
Member

ry commented Mar 3, 2021

Looks good to me, but this should wait for 1.9.0, I think. Unfortunately that's 6 weeks out as we just released 1.8.0 yesterday.

It could be argued that Deno.core is not part of the public API. It's not listed in "deno types" so maybe this could go out in a patch release. Interested in other's opinions...

@ry ry added this to the 1.9.0 milestone Mar 3, 2021
@lucacasonato
Copy link
Member

lucacasonato commented Mar 8, 2021

I think we should just land for 1.9. Merge window opens on 17th right? It will be in main for 4 weeks then. As this will mainly be used for benchmarking, it only needs to be in main, not necessarily in a release right away.

@AaronO AaronO mentioned this pull request Mar 9, 2021
7 tasks
@bartlomieju
Copy link
Member

It could be argued that Deno.core is not part of the public API. It's not listed in "deno types" so maybe this could go out in a patch release. Interested in other's opinions...

I agree with that, we've already did this several times, I see no point in holding it off.

That said I don't like that the fields are using snake_case instead of camelCase.

@AaronO
Copy link
Contributor Author

AaronO commented Mar 15, 2021

@bartlomieju I'll switch this to camelCase and add tests later today, so we can merge this then (I was hoping to camelCase through serde with #9722, but we can do that later)

I'll do a separate PR on adding this "baseline isolate heap" to the benchmarks since there's some meta-discussion to be had on where to put it (doesn't perfectly fit with the other "max memory" benches and also differs from them by an order of magnitude)

@AaronO
Copy link
Contributor Author

AaronO commented Mar 15, 2021

@bartlomieju The windows test release failed for an unrelated (DNS error), I don't think I can retry it, could you ?

Otherwise linting & tests pass.

@bartlomieju
Copy link
Member

@AaronO done, I think this is good to land as is

@AaronO
Copy link
Contributor Author

AaronO commented Mar 16, 2021

@bartlomieju great, thanks !

@bartlomieju bartlomieju merged commit 876f075 into denoland:main Mar 23, 2021
@AaronO AaronO deleted the core/heap-stats branch March 26, 2021 11:53
@danopia danopia mentioned this pull request May 9, 2021
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.

None yet

6 participants