mirror of
https://github.com/denoland/deno.git
synced 2024-11-25 15:29:32 -05:00
feat(core): Deno.core.heapStats() (#9659)
This commit implements "Deno.core.heapStats()" function that allows to programatically measure isolate heap-usage.
This commit is contained in:
parent
26f7a3f185
commit
876f075dde
5 changed files with 149 additions and 0 deletions
36
cli/tests/heapstats.js
Normal file
36
cli/tests/heapstats.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
"use strict";
|
||||
|
||||
function allocTest(alloc, allocAssert, deallocAssert) {
|
||||
// Helper func that GCs then returns heapStats
|
||||
const sample = () => {
|
||||
// deno-lint-ignore no-undef
|
||||
gc();
|
||||
return Deno.core.heapStats();
|
||||
};
|
||||
const delta = (t1, t2) => t2.usedHeapSize - t1.usedHeapSize;
|
||||
|
||||
// Sample "clean" heapStats
|
||||
const t1 = sample();
|
||||
|
||||
// Alloc
|
||||
let x = alloc();
|
||||
const t2 = sample();
|
||||
allocAssert(delta(t1, t2));
|
||||
|
||||
// Free
|
||||
x = null;
|
||||
const t3 = sample();
|
||||
deallocAssert(delta(t2, t3));
|
||||
}
|
||||
|
||||
function main() {
|
||||
// Large-array test, 1M slot array consumes ~4MB (4B per slot)
|
||||
allocTest(
|
||||
() => new Array(1e6),
|
||||
(delta) => console.log("Allocated:", Math.round(delta / 1e6) + "MB"),
|
||||
(delta) => console.log("Freed:", Math.round(delta / 1e6) + "MB"),
|
||||
);
|
||||
}
|
||||
|
||||
main();
|
2
cli/tests/heapstats.js.out
Normal file
2
cli/tests/heapstats.js.out
Normal file
|
@ -0,0 +1,2 @@
|
|||
Allocated: 4MB
|
||||
Freed: -4MB
|
|
@ -3217,6 +3217,11 @@ console.log("finish");
|
|||
output: "exit_error42.ts.out",
|
||||
});
|
||||
|
||||
itest!(heapstats {
|
||||
args: "run --quiet --v8-flags=--expose-gc heapstats.js",
|
||||
output: "heapstats.js.out",
|
||||
});
|
||||
|
||||
itest!(https_import {
|
||||
args: "run --quiet --reload --cert tls/RootCA.pem https_import.ts",
|
||||
output: "https_import.ts.out",
|
||||
|
|
103
core/bindings.rs
103
core/bindings.rs
|
@ -59,6 +59,9 @@ lazy_static! {
|
|||
v8::ExternalReference {
|
||||
function: get_proxy_details.map_fn_to()
|
||||
},
|
||||
v8::ExternalReference {
|
||||
function: heap_stats.map_fn_to(),
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -135,6 +138,7 @@ pub fn initialize_context<'s>(
|
|||
set_func(scope, core_val, "deserialize", deserialize);
|
||||
set_func(scope, core_val, "getPromiseDetails", get_promise_details);
|
||||
set_func(scope, core_val, "getProxyDetails", get_proxy_details);
|
||||
set_func(scope, core_val, "heapStats", heap_stats);
|
||||
|
||||
let shared_key = v8::String::new(scope, "shared").unwrap();
|
||||
core_val.set_accessor(scope, shared_key.into(), shared_getter);
|
||||
|
@ -923,3 +927,102 @@ fn throw_type_error(scope: &mut v8::HandleScope, message: impl AsRef<str>) {
|
|||
let exception = v8::Exception::type_error(scope, message);
|
||||
scope.throw_exception(exception);
|
||||
}
|
||||
|
||||
fn heap_stats(
|
||||
scope: &mut v8::HandleScope,
|
||||
_args: v8::FunctionCallbackArguments,
|
||||
mut rv: v8::ReturnValue,
|
||||
) {
|
||||
fn set_prop(
|
||||
scope: &mut v8::HandleScope,
|
||||
obj: v8::Local<v8::Object>,
|
||||
name: &'static str,
|
||||
value: usize,
|
||||
) {
|
||||
let key = v8::String::new(scope, name).unwrap();
|
||||
let val = v8::Number::new(scope, value as f64);
|
||||
obj.set(scope, key.into(), val.into());
|
||||
}
|
||||
|
||||
let s = get_heap_stats(scope);
|
||||
|
||||
// TODO: use serde for this once we have serde_v8
|
||||
let obj = v8::Object::new(scope);
|
||||
set_prop(scope, obj, "totalHeapSize", s.total_heap_size);
|
||||
set_prop(
|
||||
scope,
|
||||
obj,
|
||||
"totalHeapSizexecutable",
|
||||
s.total_heap_size_executable,
|
||||
);
|
||||
set_prop(scope, obj, "totalPhysicalSize", s.total_physical_size);
|
||||
set_prop(scope, obj, "totalAvailableSize", s.total_available_size);
|
||||
set_prop(
|
||||
scope,
|
||||
obj,
|
||||
"totalGlobalHandlesSize",
|
||||
s.total_global_handles_size,
|
||||
);
|
||||
set_prop(
|
||||
scope,
|
||||
obj,
|
||||
"usedGlobalHandlesSize",
|
||||
s.used_global_handles_size,
|
||||
);
|
||||
set_prop(scope, obj, "usedHeapSize", s.used_heap_size);
|
||||
set_prop(scope, obj, "heapSizeLimit", s.heap_size_limit);
|
||||
set_prop(scope, obj, "mallocedMemory", s.malloced_memory);
|
||||
set_prop(scope, obj, "externalMemory", s.external_memory);
|
||||
set_prop(scope, obj, "peakMallocedMemory", s.peak_malloced_memory);
|
||||
set_prop(
|
||||
scope,
|
||||
obj,
|
||||
"numberOfNativeContexts",
|
||||
s.number_of_native_contexts,
|
||||
);
|
||||
set_prop(
|
||||
scope,
|
||||
obj,
|
||||
"numberOfDetachedContexts",
|
||||
s.number_of_detached_contexts,
|
||||
);
|
||||
|
||||
rv.set(obj.into());
|
||||
}
|
||||
|
||||
// HeapStats stores values from a isolate.get_heap_statistics() call
|
||||
struct HeapStats {
|
||||
total_heap_size: usize,
|
||||
total_heap_size_executable: usize,
|
||||
total_physical_size: usize,
|
||||
total_available_size: usize,
|
||||
total_global_handles_size: usize,
|
||||
used_global_handles_size: usize,
|
||||
used_heap_size: usize,
|
||||
heap_size_limit: usize,
|
||||
malloced_memory: usize,
|
||||
external_memory: usize,
|
||||
peak_malloced_memory: usize,
|
||||
number_of_native_contexts: usize,
|
||||
number_of_detached_contexts: usize,
|
||||
}
|
||||
fn get_heap_stats(isolate: &mut v8::Isolate) -> HeapStats {
|
||||
let mut s = v8::HeapStatistics::default();
|
||||
isolate.get_heap_statistics(&mut s);
|
||||
|
||||
HeapStats {
|
||||
total_heap_size: s.total_heap_size(),
|
||||
total_heap_size_executable: s.total_heap_size_executable(),
|
||||
total_physical_size: s.total_physical_size(),
|
||||
total_available_size: s.total_available_size(),
|
||||
total_global_handles_size: s.total_global_handles_size(),
|
||||
used_global_handles_size: s.used_global_handles_size(),
|
||||
used_heap_size: s.used_heap_size(),
|
||||
heap_size_limit: s.heap_size_limit(),
|
||||
malloced_memory: s.malloced_memory(),
|
||||
external_memory: s.external_memory(),
|
||||
peak_malloced_memory: s.peak_malloced_memory(),
|
||||
number_of_native_contexts: s.number_of_native_contexts(),
|
||||
number_of_detached_contexts: s.number_of_detached_contexts(),
|
||||
}
|
||||
}
|
||||
|
|
3
core/lib.deno_core.d.ts
vendored
3
core/lib.deno_core.d.ts
vendored
|
@ -35,5 +35,8 @@ declare namespace Deno {
|
|||
|
||||
/** Close the resource with the specified op id. */
|
||||
function close(rid: number): void;
|
||||
|
||||
/** Get heap stats for current isolate/worker */
|
||||
function heapStats(): Record<string, number>;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue