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",
|
output: "exit_error42.ts.out",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
itest!(heapstats {
|
||||||
|
args: "run --quiet --v8-flags=--expose-gc heapstats.js",
|
||||||
|
output: "heapstats.js.out",
|
||||||
|
});
|
||||||
|
|
||||||
itest!(https_import {
|
itest!(https_import {
|
||||||
args: "run --quiet --reload --cert tls/RootCA.pem https_import.ts",
|
args: "run --quiet --reload --cert tls/RootCA.pem https_import.ts",
|
||||||
output: "https_import.ts.out",
|
output: "https_import.ts.out",
|
||||||
|
|
103
core/bindings.rs
103
core/bindings.rs
|
@ -59,6 +59,9 @@ lazy_static! {
|
||||||
v8::ExternalReference {
|
v8::ExternalReference {
|
||||||
function: get_proxy_details.map_fn_to()
|
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, "deserialize", deserialize);
|
||||||
set_func(scope, core_val, "getPromiseDetails", get_promise_details);
|
set_func(scope, core_val, "getPromiseDetails", get_promise_details);
|
||||||
set_func(scope, core_val, "getProxyDetails", get_proxy_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();
|
let shared_key = v8::String::new(scope, "shared").unwrap();
|
||||||
core_val.set_accessor(scope, shared_key.into(), shared_getter);
|
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);
|
let exception = v8::Exception::type_error(scope, message);
|
||||||
scope.throw_exception(exception);
|
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. */
|
/** Close the resource with the specified op id. */
|
||||||
function close(rid: number): void;
|
function close(rid: number): void;
|
||||||
|
|
||||||
|
/** Get heap stats for current isolate/worker */
|
||||||
|
function heapStats(): Record<string, number>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue