@@ -69,6 +69,7 @@ deno_core::extension!(
6969 op_get_exit_code,
7070 op_system_memory_info,
7171 op_uid,
72+ op_runtime_cpu_usage,
7273 op_runtime_memory_usage,
7374 ops:: signal:: op_signal_bind,
7475 ops:: signal:: op_signal_unbind,
@@ -106,6 +107,7 @@ deno_core::extension!(
106107 op_get_exit_code,
107108 op_system_memory_info,
108109 op_uid,
110+ op_runtime_cpu_usage,
109111 op_runtime_memory_usage,
110112 ops:: signal:: op_signal_bind,
111113 ops:: signal:: op_signal_unbind,
@@ -420,27 +422,127 @@ fn op_uid(state: &mut OpState) -> Result<Option<u32>, PermissionCheckError> {
420422 Ok ( None )
421423}
422424
423- // HeapStats stores values from a isolate.get_heap_statistics() call
424- #[ derive( Serialize ) ]
425- #[ serde( rename_all = "camelCase" ) ]
426- struct MemoryUsage {
427- rss : usize ,
428- heap_total : usize ,
429- heap_used : usize ,
430- external : usize ,
425+ #[ op2]
426+ #[ serde]
427+ fn op_runtime_cpu_usage ( ) -> ( usize , usize ) {
428+ let ( sys, user) = get_cpu_usage ( ) ;
429+ ( sys. as_micros ( ) as usize , user. as_micros ( ) as usize )
430+ }
431+
432+ #[ cfg( unix) ]
433+ fn get_cpu_usage ( ) -> ( std:: time:: Duration , std:: time:: Duration ) {
434+ let mut rusage = std:: mem:: MaybeUninit :: uninit ( ) ;
435+
436+ // Uses POSIX getrusage from libc
437+ // to retrieve user and system times
438+ // SAFETY: libc call
439+ let ret = unsafe { libc:: getrusage ( libc:: RUSAGE_SELF , rusage. as_mut_ptr ( ) ) } ;
440+ if ret != 0 {
441+ return Default :: default ( ) ;
442+ }
443+
444+ // SAFETY: already checked the result
445+ let rusage = unsafe { rusage. assume_init ( ) } ;
446+
447+ let sys = std:: time:: Duration :: from_micros ( rusage. ru_stime . tv_usec as u64 )
448+ + std:: time:: Duration :: from_secs ( rusage. ru_stime . tv_sec as u64 ) ;
449+ let user = std:: time:: Duration :: from_micros ( rusage. ru_utime . tv_usec as u64 )
450+ + std:: time:: Duration :: from_secs ( rusage. ru_utime . tv_sec as u64 ) ;
451+
452+ ( sys, user)
453+ }
454+
455+ #[ cfg( windows) ]
456+ fn get_cpu_usage ( ) -> ( std:: time:: Duration , std:: time:: Duration ) {
457+ use winapi:: shared:: minwindef:: FALSE ;
458+ use winapi:: shared:: minwindef:: FILETIME ;
459+ use winapi:: shared:: minwindef:: TRUE ;
460+ use winapi:: um:: minwinbase:: SYSTEMTIME ;
461+ use winapi:: um:: processthreadsapi:: GetCurrentProcess ;
462+ use winapi:: um:: processthreadsapi:: GetProcessTimes ;
463+ use winapi:: um:: timezoneapi:: FileTimeToSystemTime ;
464+
465+ fn convert_system_time ( system_time : SYSTEMTIME ) -> std:: time:: Duration {
466+ std:: time:: Duration :: from_secs (
467+ system_time. wHour as u64 * 3600
468+ + system_time. wMinute as u64 * 60
469+ + system_time. wSecond as u64 ,
470+ ) + std:: time:: Duration :: from_millis ( system_time. wMilliseconds as u64 )
471+ }
472+
473+ let mut creation_time = std:: mem:: MaybeUninit :: < FILETIME > :: uninit ( ) ;
474+ let mut exit_time = std:: mem:: MaybeUninit :: < FILETIME > :: uninit ( ) ;
475+ let mut kernel_time = std:: mem:: MaybeUninit :: < FILETIME > :: uninit ( ) ;
476+ let mut user_time = std:: mem:: MaybeUninit :: < FILETIME > :: uninit ( ) ;
477+
478+ // SAFETY: winapi calls
479+ let ret = unsafe {
480+ GetProcessTimes (
481+ GetCurrentProcess ( ) ,
482+ creation_time. as_mut_ptr ( ) ,
483+ exit_time. as_mut_ptr ( ) ,
484+ kernel_time. as_mut_ptr ( ) ,
485+ user_time. as_mut_ptr ( ) ,
486+ )
487+ } ;
488+
489+ if ret != TRUE {
490+ return std:: default:: Default :: default ( ) ;
491+ }
492+
493+ let mut kernel_system_time = std:: mem:: MaybeUninit :: < SYSTEMTIME > :: uninit ( ) ;
494+ let mut user_system_time = std:: mem:: MaybeUninit :: < SYSTEMTIME > :: uninit ( ) ;
495+
496+ // SAFETY: convert to system time
497+ unsafe {
498+ let sys_ret = FileTimeToSystemTime (
499+ kernel_time. assume_init_mut ( ) ,
500+ kernel_system_time. as_mut_ptr ( ) ,
501+ ) ;
502+ let user_ret = FileTimeToSystemTime (
503+ user_time. assume_init_mut ( ) ,
504+ user_system_time. as_mut_ptr ( ) ,
505+ ) ;
506+
507+ match ( sys_ret, user_ret) {
508+ ( TRUE , TRUE ) => (
509+ convert_system_time ( kernel_system_time. assume_init ( ) ) ,
510+ convert_system_time ( user_system_time. assume_init ( ) ) ,
511+ ) ,
512+ ( TRUE , FALSE ) => (
513+ convert_system_time ( kernel_system_time. assume_init ( ) ) ,
514+ Default :: default ( ) ,
515+ ) ,
516+ ( FALSE , TRUE ) => (
517+ Default :: default ( ) ,
518+ convert_system_time ( user_system_time. assume_init ( ) ) ,
519+ ) ,
520+ ( _, _) => Default :: default ( ) ,
521+ }
522+ }
523+ }
524+
525+ #[ cfg( not( any( windows, unix) ) ) ]
526+ fn get_cpu_usage ( ) -> ( std:: time:: Duration , std:: time:: Duration ) {
527+ Default :: default ( )
431528}
432529
433530#[ op2]
434531#[ serde]
435- fn op_runtime_memory_usage ( scope : & mut v8:: HandleScope ) -> MemoryUsage {
532+ fn op_runtime_memory_usage (
533+ scope : & mut v8:: HandleScope ,
534+ ) -> ( usize , usize , usize , usize ) {
436535 let mut s = v8:: HeapStatistics :: default ( ) ;
437536 scope. get_heap_statistics ( & mut s) ;
438- MemoryUsage {
439- rss : rss ( ) ,
440- heap_total : s. total_heap_size ( ) ,
441- heap_used : s. used_heap_size ( ) ,
442- external : s. external_memory ( ) ,
443- }
537+
538+ let ( rss, heap_total, heap_used, external) = (
539+ rss ( ) ,
540+ s. total_heap_size ( ) ,
541+ s. used_heap_size ( ) ,
542+ s. external_memory ( ) ,
543+ ) ;
544+
545+ ( rss, heap_total, heap_used, external)
444546}
445547
446548#[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
0 commit comments