diff options
author | Ryan Dahl <ry@tinyclouds.org> | 2009-11-03 15:00:42 +0300 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2009-11-03 15:00:42 +0300 |
commit | b3b3cfe007f79a019a76dc0d35e9e77504d3e835 (patch) | |
tree | 7446f19e08a7899a2ea42568f12bdd0853e4ef8e | |
parent | 3a70129a9c52e98f4acd678a1810455f4767ddf8 (diff) |
Move memoryUsage() into C on Linux
-rw-r--r-- | lib/sys.js | 61 | ||||
-rw-r--r-- | src/node.cc | 124 | ||||
-rw-r--r-- | test/mjsunit/test-memory-usage.js | 2 |
3 files changed, 112 insertions, 75 deletions
diff --git a/lib/sys.js b/lib/sys.js index 31b8dc7f31a..de98a3b51fa 100644 --- a/lib/sys.js +++ b/lib/sys.js @@ -67,64 +67,3 @@ 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 e1917e5f089..0cf2d2fd7de 100644 --- a/src/node.cc +++ b/src/node.cc @@ -254,17 +254,15 @@ v8::Handle<v8::Value> Exit(const v8::Arguments& args) { } #ifdef __APPLE__ +#define HAVE_GETMEM 1 /* Researched by Tim Becker and Michael Knight * http://blog.kuriositaet.de/?p=257 - * http://blog.kuriositaet.de/?p=257 */ #include <mach/task.h> #include <mach/mach_init.h> -v8::Handle<v8::Value> MacGetMemory(const v8::Arguments& args) { - HandleScope scope; - +int getmem(size_t *rss, size_t *vsize) { task_t task = MACH_PORT_NULL; struct task_basic_info t_info; mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; @@ -274,21 +272,123 @@ v8::Handle<v8::Value> MacGetMemory(const v8::Arguments& args) { (task_info_t)&t_info, &t_info_count); - if (KERN_SUCCESS != r) { + if (r != KERN_SUCCESS) return -1; + + *rss = t_info.resident_size; + *vsize = t_info.virtual_size; + + return 0; +} +#endif // __APPLE__ + +#ifdef __linux__ +# define HAVE_GETMEM 1 +# include <sys/param.h> /* for MAXPATHLEN */ +# include <sys/user.h> /* for PAGE_SIZE */ + +int getmem(size_t *rss, size_t *vsize) { + FILE *f = fopen("/proc/self/stat", "r"); + if (!f) return -1; + + int itmp; + char ctmp; + char buffer[MAXPATHLEN]; + + /* PID */ + if (fscanf(f, "%d ", &itmp) == 0) goto error; + /* Exec file */ + if (fscanf (f, "%s ", &buffer[0]) == 0) goto error; + /* State */ + if (fscanf (f, "%c ", &ctmp) == 0) goto error; + /* Parent process */ + if (fscanf (f, "%d ", &itmp) == 0) goto error; + /* Process group */ + if (fscanf (f, "%d ", &itmp) == 0) goto error; + /* Session id */ + if (fscanf (f, "%d ", &itmp) == 0) goto error; + /* TTY */ + if (fscanf (f, "%d ", &itmp) == 0) goto error; + /* TTY owner process group */ + if (fscanf (f, "%d ", &itmp) == 0) goto error; + /* Flags */ + if (fscanf (f, "%u ", &itmp) == 0) goto error; + /* Minor faults (no memory page) */ + if (fscanf (f, "%u ", &itmp) == 0) goto error; + /* Minor faults, children */ + if (fscanf (f, "%u ", &itmp) == 0) goto error; + /* Major faults (memory page faults) */ + if (fscanf (f, "%u ", &itmp) == 0) goto error; + /* Major faults, children */ + if (fscanf (f, "%u ", &itmp) == 0) goto error; + /* utime */ + if (fscanf (f, "%d ", &itmp) == 0) goto error; + /* stime */ + if (fscanf (f, "%d ", &itmp) == 0) goto error; + /* utime, children */ + if (fscanf (f, "%d ", &itmp) == 0) goto error; + /* stime, children */ + if (fscanf (f, "%d ", &itmp) == 0) goto error; + /* jiffies remaining in current time slice */ + if (fscanf (f, "%d ", &itmp) == 0) goto error; + /* 'nice' value */ + if (fscanf (f, "%d ", &itmp) == 0) goto error; + /* jiffies until next timeout */ + if (fscanf (f, "%u ", &itmp) == 0) goto error; + /* jiffies until next SIGALRM */ + if (fscanf (f, "%u ", &itmp) == 0) goto error; + /* start time (jiffies since system boot) */ + if (fscanf (f, "%d ", &itmp) == 0) goto error; + + /* Virtual memory size */ + if (fscanf (f, "%u ", &itmp) == 0) goto error; + *vsize = (size_t) itmp; + + /* Resident set size */ + if (fscanf (f, "%u ", &itmp) == 0) goto error; + *rss = (size_t) itmp * PAGE_SIZE; + + /* rlim */ + if (fscanf (f, "%u ", &itmp) == 0) goto error; + /* Start of text */ + if (fscanf (f, "%u ", &itmp) == 0) goto error; + /* End of text */ + if (fscanf (f, "%u ", &itmp) == 0) goto error; + /* Start of stack */ + if (fscanf (f, "%u ", &itmp) == 0) goto error; + + fclose (f); + + return 0; + +error: + fclose (f); + return -1; +} +#endif // __linux__ + +v8::Handle<v8::Value> MemoryUsage(const v8::Arguments& args) { + HandleScope scope; + +#ifndef HAVE_GETMEM + return ThrowException(Exception::Error(String::New("Not support on your platform. (Talk to Ryan.)"))); +#else + size_t rss, vsize; + + int r = getmem(&rss, &vsize); + + if (r != 0) { return ThrowException(Exception::Error(String::New(strerror(errno)))); } - size_t rss = t_info.resident_size; - size_t vs = t_info.virtual_size; - Local<Object> info = Object::New(); info->Set(String::NewSymbol("rss"), Integer::NewFromUnsigned(rss)); - info->Set(String::NewSymbol("vsize"), Integer::NewFromUnsigned(vs)); + info->Set(String::NewSymbol("vsize"), Integer::NewFromUnsigned(vsize)); return scope.Close(info); +#endif } -#endif // __APPLE__ + v8::Handle<v8::Value> Kill(const v8::Arguments& args) { HandleScope scope; @@ -510,9 +610,7 @@ static Local<Object> 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 + NODE_SET_METHOD(process, "memoryUsage", MemoryUsage); // 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 index b9d935fb42a..2da67f2667d 100644 --- a/test/mjsunit/test-memory-usage.js +++ b/test/mjsunit/test-memory-usage.js @@ -1,6 +1,6 @@ process.mixin(require("./common")); -var r = memoryUsage(); +var r = process.memoryUsage(); puts(inspect(r)); assertTrue(r["rss"] > 0); assertTrue(r["vsize"] > 0); |