mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 07:14:47 -05:00
fix(runtime): Deno.memoryUsage().rss
should return correct value (#17088)
This commit changes implementation of "Deno.memoryUsage()" to return correct value for "rss" field. To do that we implement a specialized function per os to retrieve this information.
This commit is contained in:
parent
f46df3e359
commit
e9ecfdd20a
5 changed files with 140 additions and 5 deletions
|
@ -272,3 +272,12 @@ Deno.test({ permissions: { sys: ["gid"] } }, function getGid() {
|
|||
assert(gid > 0);
|
||||
}
|
||||
});
|
||||
|
||||
Deno.test(function memoryUsage() {
|
||||
const mem = Deno.memoryUsage();
|
||||
assert(typeof mem.rss === "number");
|
||||
assert(typeof mem.heapTotal === "number");
|
||||
assert(typeof mem.heapUsed === "number");
|
||||
assert(typeof mem.external === "number");
|
||||
assert(mem.rss >= mem.heapTotal);
|
||||
});
|
||||
|
|
|
@ -654,7 +654,7 @@ fn op_get_proxy_details<'a>(
|
|||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct MemoryUsage {
|
||||
rss: usize,
|
||||
physical_total: usize,
|
||||
heap_total: usize,
|
||||
heap_used: usize,
|
||||
external: usize,
|
||||
|
@ -668,7 +668,7 @@ fn op_memory_usage(scope: &mut v8::HandleScope) -> MemoryUsage {
|
|||
let mut s = v8::HeapStatistics::default();
|
||||
scope.get_heap_statistics(&mut s);
|
||||
MemoryUsage {
|
||||
rss: s.total_physical_size(),
|
||||
physical_total: s.total_physical_size(),
|
||||
heap_total: s.total_heap_size(),
|
||||
heap_used: s.used_heap_size(),
|
||||
external: s.external_memory(),
|
||||
|
|
|
@ -94,7 +94,7 @@ uuid.workspace = true
|
|||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
fwdansi.workspace = true
|
||||
winapi = { workspace = true, features = ["commapi", "knownfolders", "mswsock", "objbase", "shlobj", "tlhelp32", "winbase", "winerror", "winsock2"] }
|
||||
winapi = { workspace = true, features = ["commapi", "knownfolders", "mswsock", "objbase", "psapi", "shlobj", "tlhelp32", "winbase", "winerror", "winsock2"] }
|
||||
ntapi = "0.4.0"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
makeTempDir: __bootstrap.fs.makeTempDir,
|
||||
makeTempFileSync: __bootstrap.fs.makeTempFileSync,
|
||||
makeTempFile: __bootstrap.fs.makeTempFile,
|
||||
memoryUsage: core.memoryUsage,
|
||||
memoryUsage: () => core.ops.op_runtime_memory_usage(),
|
||||
mkdirSync: __bootstrap.fs.mkdirSync,
|
||||
mkdir: __bootstrap.fs.mkdir,
|
||||
chdir: __bootstrap.fs.chdir,
|
||||
|
|
|
@ -4,11 +4,14 @@ use super::utils::into_string;
|
|||
use crate::permissions::Permissions;
|
||||
use crate::worker::ExitCode;
|
||||
use deno_core::error::{type_error, AnyError};
|
||||
use deno_core::op;
|
||||
use deno_core::url::Url;
|
||||
use deno_core::v8;
|
||||
use deno_core::Extension;
|
||||
use deno_core::ExtensionBuilder;
|
||||
use deno_core::OpState;
|
||||
use deno_core::{op, ExtensionBuilder};
|
||||
use deno_node::NODE_ENV_VAR_ALLOWLIST;
|
||||
use serde::Serialize;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
|
||||
|
@ -30,6 +33,7 @@ fn init_ops(builder: &mut ExtensionBuilder) -> &mut ExtensionBuilder {
|
|||
op_set_exit_code::decl(),
|
||||
op_system_memory_info::decl(),
|
||||
op_uid::decl(),
|
||||
op_runtime_memory_usage::decl(),
|
||||
])
|
||||
}
|
||||
|
||||
|
@ -297,3 +301,125 @@ fn op_uid(state: &mut OpState) -> Result<Option<u32>, AnyError> {
|
|||
.check("uid", Some("Deno.uid()"))?;
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
// HeapStats stores values from a isolate.get_heap_statistics() call
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct MemoryUsage {
|
||||
rss: usize,
|
||||
heap_total: usize,
|
||||
heap_used: usize,
|
||||
external: usize,
|
||||
}
|
||||
|
||||
#[op(v8)]
|
||||
fn op_runtime_memory_usage(scope: &mut v8::HandleScope) -> MemoryUsage {
|
||||
let mut s = v8::HeapStatistics::default();
|
||||
scope.get_heap_statistics(&mut s);
|
||||
MemoryUsage {
|
||||
rss: rss(),
|
||||
heap_total: s.total_heap_size(),
|
||||
heap_used: s.used_heap_size(),
|
||||
external: s.external_memory(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn rss() -> usize {
|
||||
// Inspired by https://github.com/Arc-blroth/memory-stats/blob/5364d0d09143de2a470d33161b2330914228fde9/src/linux.rs
|
||||
|
||||
// Extracts a positive integer from a string that
|
||||
// may contain leading spaces and trailing chars.
|
||||
// Returns the extracted number and the index of
|
||||
// the next character in the string.
|
||||
fn scan_int(string: &str) -> (usize, usize) {
|
||||
let mut out = 0;
|
||||
let mut idx = 0;
|
||||
let mut chars = string.chars().peekable();
|
||||
while let Some(' ') = chars.next_if_eq(&' ') {
|
||||
idx += 1;
|
||||
}
|
||||
for n in chars {
|
||||
idx += 1;
|
||||
if ('0'..='9').contains(&n) {
|
||||
out *= 10;
|
||||
out += n as usize - '0' as usize;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
(out, idx)
|
||||
}
|
||||
|
||||
let statm_content = if let Ok(c) = std::fs::read_to_string("/proc/self/statm")
|
||||
{
|
||||
c
|
||||
} else {
|
||||
return 0;
|
||||
};
|
||||
|
||||
// statm returns the virtual size and rss, in
|
||||
// multiples of the page size, as the first
|
||||
// two columns of output.
|
||||
// SAFETY: libc call
|
||||
let page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) };
|
||||
|
||||
if page_size < 0 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let (_total_size_pages, idx) = scan_int(&statm_content);
|
||||
let (total_rss_pages, _) = scan_int(&statm_content[idx..]);
|
||||
|
||||
total_rss_pages * page_size as usize
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn rss() -> usize {
|
||||
// Inspired by https://github.com/Arc-blroth/memory-stats/blob/5364d0d09143de2a470d33161b2330914228fde9/src/darwin.rs
|
||||
|
||||
let mut task_info =
|
||||
std::mem::MaybeUninit::<libc::mach_task_basic_info_data_t>::uninit();
|
||||
let mut count = libc::MACH_TASK_BASIC_INFO_COUNT;
|
||||
// SAFETY: libc calls
|
||||
let r = unsafe {
|
||||
libc::task_info(
|
||||
libc::mach_task_self(),
|
||||
libc::MACH_TASK_BASIC_INFO,
|
||||
task_info.as_mut_ptr() as libc::task_info_t,
|
||||
&mut count as *mut libc::mach_msg_type_number_t,
|
||||
)
|
||||
};
|
||||
// According to libuv this should never fail
|
||||
assert_eq!(r, libc::KERN_SUCCESS);
|
||||
// SAFETY: we just asserted that it was success
|
||||
let task_info = unsafe { task_info.assume_init() };
|
||||
task_info.resident_size as usize
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn rss() -> usize {
|
||||
use winapi::shared::minwindef::DWORD;
|
||||
use winapi::shared::minwindef::FALSE;
|
||||
use winapi::um::processthreadsapi::GetCurrentProcess;
|
||||
use winapi::um::psapi::GetProcessMemoryInfo;
|
||||
use winapi::um::psapi::PROCESS_MEMORY_COUNTERS;
|
||||
|
||||
// SAFETY: winapi calls
|
||||
unsafe {
|
||||
// this handle is a constant—no need to close it
|
||||
let current_process = GetCurrentProcess();
|
||||
let mut pmc: PROCESS_MEMORY_COUNTERS = std::mem::zeroed();
|
||||
|
||||
if GetProcessMemoryInfo(
|
||||
current_process,
|
||||
&mut pmc,
|
||||
std::mem::size_of::<PROCESS_MEMORY_COUNTERS>() as DWORD,
|
||||
) != FALSE
|
||||
{
|
||||
pmc.WorkingSetSize
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue