0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-02-08 07:16:56 -05:00

feat: implement process.cpuUsage (Deno.cpuUsage) (#27217)

This commit is contained in:
Cyan 2025-01-30 03:53:05 -08:00 committed by GitHub
parent b7456fed70
commit e6dda60d5c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 136 additions and 21 deletions

View file

@ -441,11 +441,7 @@ Process.prototype.config = {
};
Process.prototype.cpuUsage = function () {
warnNotImplemented("process.cpuUsage()");
return {
user: 0,
system: 0,
};
return Deno.cpuUsage();
};
/** https://nodejs.org/api/process.html#process_process_cwd */

View file

@ -32,3 +32,11 @@ This crate implements OS specific APIs for Deno
| Linux | sysinfo and `/proc/meminfo` | - |
| Windows | `sysinfoapi::GlobalMemoryStatusEx` | - |
| macOS | <br> <pre> sysctl([CTL_HW, HW_MEMSIZE]); <br> sysctl([CTL_VM, VM_SWAPUSAGE]); <br> host_statistics64(mach_host_self(), HOST_VM_INFO64) </pre> | - |
`cpu_usage`
| Target family | Syscall | Description |
| ------------- | ------------------------------------ | ----------- |
| Linux | getrusage | - |
| Windows | `processthreadsapi::GetProcessTimes` | - |
| macOS | getrusage | - |

View file

@ -69,6 +69,7 @@ deno_core::extension!(
op_get_exit_code,
op_system_memory_info,
op_uid,
op_runtime_cpu_usage,
op_runtime_memory_usage,
ops::signal::op_signal_bind,
ops::signal::op_signal_unbind,
@ -106,6 +107,7 @@ deno_core::extension!(
op_get_exit_code,
op_system_memory_info,
op_uid,
op_runtime_cpu_usage,
op_runtime_memory_usage,
ops::signal::op_signal_bind,
ops::signal::op_signal_unbind,
@ -420,27 +422,127 @@ fn op_uid(state: &mut OpState) -> Result<Option<u32>, PermissionCheckError> {
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,
#[op2]
#[serde]
fn op_runtime_cpu_usage() -> (usize, usize) {
let (sys, user) = get_cpu_usage();
(sys.as_micros() as usize, user.as_micros() as usize)
}
#[cfg(unix)]
fn get_cpu_usage() -> (std::time::Duration, std::time::Duration) {
let mut rusage = std::mem::MaybeUninit::uninit();
// Uses POSIX getrusage from libc
// to retrieve user and system times
// SAFETY: libc call
let ret = unsafe { libc::getrusage(libc::RUSAGE_SELF, rusage.as_mut_ptr()) };
if ret != 0 {
return Default::default();
}
// SAFETY: already checked the result
let rusage = unsafe { rusage.assume_init() };
let sys = std::time::Duration::from_micros(rusage.ru_stime.tv_usec as u64)
+ std::time::Duration::from_secs(rusage.ru_stime.tv_sec as u64);
let user = std::time::Duration::from_micros(rusage.ru_utime.tv_usec as u64)
+ std::time::Duration::from_secs(rusage.ru_utime.tv_sec as u64);
(sys, user)
}
#[cfg(windows)]
fn get_cpu_usage() -> (std::time::Duration, std::time::Duration) {
use winapi::shared::minwindef::FALSE;
use winapi::shared::minwindef::FILETIME;
use winapi::shared::minwindef::TRUE;
use winapi::um::minwinbase::SYSTEMTIME;
use winapi::um::processthreadsapi::GetCurrentProcess;
use winapi::um::processthreadsapi::GetProcessTimes;
use winapi::um::timezoneapi::FileTimeToSystemTime;
fn convert_system_time(system_time: SYSTEMTIME) -> std::time::Duration {
std::time::Duration::from_secs(
system_time.wHour as u64 * 3600
+ system_time.wMinute as u64 * 60
+ system_time.wSecond as u64,
) + std::time::Duration::from_millis(system_time.wMilliseconds as u64)
}
let mut creation_time = std::mem::MaybeUninit::<FILETIME>::uninit();
let mut exit_time = std::mem::MaybeUninit::<FILETIME>::uninit();
let mut kernel_time = std::mem::MaybeUninit::<FILETIME>::uninit();
let mut user_time = std::mem::MaybeUninit::<FILETIME>::uninit();
// SAFETY: winapi calls
let ret = unsafe {
GetProcessTimes(
GetCurrentProcess(),
creation_time.as_mut_ptr(),
exit_time.as_mut_ptr(),
kernel_time.as_mut_ptr(),
user_time.as_mut_ptr(),
)
};
if ret != TRUE {
return std::default::Default::default();
}
let mut kernel_system_time = std::mem::MaybeUninit::<SYSTEMTIME>::uninit();
let mut user_system_time = std::mem::MaybeUninit::<SYSTEMTIME>::uninit();
// SAFETY: convert to system time
unsafe {
let sys_ret = FileTimeToSystemTime(
kernel_time.assume_init_mut(),
kernel_system_time.as_mut_ptr(),
);
let user_ret = FileTimeToSystemTime(
user_time.assume_init_mut(),
user_system_time.as_mut_ptr(),
);
match (sys_ret, user_ret) {
(TRUE, TRUE) => (
convert_system_time(kernel_system_time.assume_init()),
convert_system_time(user_system_time.assume_init()),
),
(TRUE, FALSE) => (
convert_system_time(kernel_system_time.assume_init()),
Default::default(),
),
(FALSE, TRUE) => (
Default::default(),
convert_system_time(user_system_time.assume_init()),
),
(_, _) => Default::default(),
}
}
}
#[cfg(not(any(windows, unix)))]
fn get_cpu_usage() -> (std::time::Duration, std::time::Duration) {
Default::default()
}
#[op2]
#[serde]
fn op_runtime_memory_usage(scope: &mut v8::HandleScope) -> MemoryUsage {
fn op_runtime_memory_usage(
scope: &mut v8::HandleScope,
) -> (usize, usize, usize, usize) {
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(),
}
let (rss, heap_total, heap_used, external) = (
rss(),
s.total_heap_size(),
s.used_heap_size(),
s.external_memory(),
);
(rss, heap_total, heap_used, external)
}
#[cfg(any(target_os = "android", target_os = "linux"))]

View file

@ -4,6 +4,7 @@ import { core, primordials } from "ext:core/mod.js";
import {
op_net_listen_udp,
op_net_listen_unixpacket,
op_runtime_cpu_usage,
op_runtime_memory_usage,
} from "ext:core/ops";
@ -59,7 +60,15 @@ const denoNs = {
makeTempDir: fs.makeTempDir,
makeTempFileSync: fs.makeTempFileSync,
makeTempFile: fs.makeTempFile,
memoryUsage: () => op_runtime_memory_usage(),
cpuUsage: () => {
const { 0: system, 1: user } = op_runtime_cpu_usage();
return { system, user };
},
memoryUsage: () => {
const { 0: rss, 1: heapTotal, 2: heapUsed, 3: external } =
op_runtime_memory_usage();
return { rss, heapTotal, heapUsed, external };
},
mkdirSync: fs.mkdirSync,
mkdir: fs.mkdir,
chdir: fs.chdir,