Permalink
Browse files

Move memoryUsage() into C on Linux

  • Loading branch information...
1 parent 3a70129 commit b3b3cfe007f79a019a76dc0d35e9e77504d3e835 @ry ry committed Nov 3, 2009
Showing with 112 additions and 75 deletions.
  1. +0 −61 lib/sys.js
  2. +111 −13 src/node.cc
  3. +1 −1 test/mjsunit/test-memory-usage.js
View
@@ -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!");
- }
-};
View
@@ -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"),
@@ -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);

0 comments on commit b3b3cfe

Please sign in to comment.