From 3a70129a9c52e98f4acd678a1810455f4767ddf8 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Tue, 3 Nov 2009 01:30:01 +0100 Subject: [PATCH] Add sys.memoryUsage() --- doc/api.txt | 3 ++ lib/sys.js | 61 +++++++++++++++++++++++++++++++ src/node.cc | 40 ++++++++++++++++++++ test/mjsunit/test-memory-usage.js | 6 +++ 4 files changed, 110 insertions(+) create mode 100644 test/mjsunit/test-memory-usage.js diff --git a/doc/api.txt b/doc/api.txt index a3e356b5c0..d577546c5a 100644 --- a/doc/api.txt +++ b/doc/api.txt @@ -102,6 +102,9 @@ The PID of the process. +process.platform+ :: What platform you're running on. +"linux2"+, +"darwin"+, etc. ++process.memoryUsage()+ :: +Returns the memory usage of the Node process: e.g. +{"rss":5828608,"vsize":3112529920}+ + +process.exit(code=0)+:: Ends the process with the specified code. By default it exits with the success code 0. diff --git a/lib/sys.js b/lib/sys.js index de98a3b51f..31b8dc7f31 100644 --- a/lib/sys.js +++ b/lib/sys.js @@ -67,3 +67,64 @@ exports.exec = function (command) { return promise; }; + +exports.memoryUsage = function () { + if (process.platform == "linux2") { + var data = require("file").read("/proc/self/stat").wait(); + // from linux-2.6.29/Documentation/filesystems/proc.tx + // 0 pid process id + // 1 tcomm filename of the executable + // 2 state state (R is running, S is sleeping, D is sleeping in an + // uninterruptible wait, Z is zombie, T is traced or stopped) + // 3 ppid process id of the parent process + // 4 pgrp pgrp of the process + // 5 sid session id + // 6 tty_nr tty the process uses + // 7 tty_pgrp pgrp of the tty + // 8 flags task flags + // 9 min_flt number of minor faults + // 10 cmin_flt number of minor faults with child's + // 11 maj_flt number of major faults + // 12 cmaj_flt number of major faults with child's + // 13 utime user mode jiffies + // 14 stime kernel mode jiffies + // 15 cutime user mode jiffies with child's + // 16 cstime kernel mode jiffies with child's + // 17 priority priority level + // 18 nice nice level + // 19 num_threads number of threads + // 20 it_real_value (obsolete, always 0) + // 21 start_time time the process started after system boot + // 22 vsize virtual memory size + // 23 rss resident set memory size + // 24 rsslim current limit in bytes on the rss + // 25 start_code address above which program text can run + // 26 end_code address below which program text can run + // 27 start_stack address of the start of the stack + // 28 esp current value of ESP + // 29 eip current value of EIP + // 30 pending bitmap of pending signals (obsolete) + // 31 blocked bitmap of blocked signals (obsolete) + // 32 sigign bitmap of ignored signals (obsolete) + // 33 sigcatch bitmap of catched signals (obsolete) + // 34 wchan address where process went to sleep + // 35 0 (place holder) + // 36 0 (place holder) + // 37 exit_signal signal to send to parent thread on exit + // 38 task_cpu which CPU the task is scheduled on + // 39 rt_priority realtime priority + // 40 policy scheduling policy (man sched_setscheduler) + // 41 blkio_ticks time spent waiting for block IO + var fields = data.split(" "); + + // 22 vsize virtual memory size + // 23 rss resident set memory size + + return { vsize: parseInt(fields[22]), rss: 4096*parseInt(fields[23]) }; + + } else if (process.platform == "darwin") { + return process.macGetMemory(); + } else { + throw new Error("Unsupported on your platform! Complain to Ryan!"); + } +}; diff --git a/src/node.cc b/src/node.cc index bf17ce07a0..e1917e5f08 100644 --- a/src/node.cc +++ b/src/node.cc @@ -253,6 +253,43 @@ v8::Handle Exit(const v8::Arguments& args) { return Undefined(); } +#ifdef __APPLE__ +/* Researched by Tim Becker and Michael Knight + * http://blog.kuriositaet.de/?p=257 + * http://blog.kuriositaet.de/?p=257 + */ + +#include +#include + +v8::Handle MacGetMemory(const v8::Arguments& args) { + HandleScope scope; + + task_t task = MACH_PORT_NULL; + struct task_basic_info t_info; + mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; + + int r = task_info(mach_task_self(), + TASK_BASIC_INFO, + (task_info_t)&t_info, + &t_info_count); + + if (KERN_SUCCESS != r) { + return ThrowException(Exception::Error(String::New(strerror(errno)))); + } + + size_t rss = t_info.resident_size; + size_t vs = t_info.virtual_size; + + Local info = Object::New(); + + info->Set(String::NewSymbol("rss"), Integer::NewFromUnsigned(rss)); + info->Set(String::NewSymbol("vsize"), Integer::NewFromUnsigned(vs)); + + return scope.Close(info); +} +#endif // __APPLE__ + v8::Handle Kill(const v8::Arguments& args) { HandleScope scope; @@ -473,6 +510,9 @@ static Local Load(int argc, char *argv[]) { NODE_SET_METHOD(process, "cwd", Cwd); NODE_SET_METHOD(process, "dlopen", DLOpen); NODE_SET_METHOD(process, "kill", Kill); +#ifdef __APPLE__ + NODE_SET_METHOD(process, "macGetMemory", MacGetMemory); +#endif // Assign the EventEmitter. It was created in main(). process->Set(String::NewSymbol("EventEmitter"), diff --git a/test/mjsunit/test-memory-usage.js b/test/mjsunit/test-memory-usage.js new file mode 100644 index 0000000000..b9d935fb42 --- /dev/null +++ b/test/mjsunit/test-memory-usage.js @@ -0,0 +1,6 @@ +process.mixin(require("./common")); + +var r = memoryUsage(); +puts(inspect(r)); +assertTrue(r["rss"] > 0); +assertTrue(r["vsize"] > 0);