Skip to content

Instantly share code, notes, and snippets.

@dolmen
Created March 17, 2011 13:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dolmen/874335 to your computer and use it in GitHub Desktop.
Save dolmen/874335 to your computer and use it in GitHub Desktop.
A new implementation of Node's Platform::GetMemory (in src/platform_linux.cc)
/* A new implementation of Node's Platform::GetMemory (in src/platform_linux.cc) */
/* Copyright (c) 2011 Olivier Mengué */
#include <stdlib.h>
#include <stdio.h>
#include <sys/param.h> // MAXPATHLEN
#include <fcntl.h> // O_RDONLY
#include <sys/time.h> // gettimeofday
typedef enum {
false = 0,
true = 1
} bool;
static char buf[MAXPATHLEN + 1];
// From NodeJs: src/platform_linux.cc
int GetMemory(size_t *rss, size_t *vsize) {
FILE *f = fopen("/proc/self/stat", "r");
if (!f) return -1;
int itmp;
char ctmp;
size_t page_size = getpagesize();
char *cbuf;
bool foundExeEnd;
/* PID */
if (fscanf(f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */
/* Exec file */
cbuf = buf;
foundExeEnd = false;
if (fscanf (f, "%c", cbuf++) == 0) goto error; // (
while (1) {
if (fscanf(f, "%c", cbuf) == 0) goto error;
if (*cbuf == ')') {
foundExeEnd = true;
} else if (foundExeEnd && *cbuf == ' ') {
*cbuf = 0;
break;
}
cbuf++;
}
/* State */
if (fscanf (f, "%c ", &ctmp) == 0) goto error; /* coverity[secure_coding] */
/* Parent process */
if (fscanf (f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */
/* Process group */
if (fscanf (f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */
/* Session id */
if (fscanf (f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */
/* TTY */
if (fscanf (f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */
/* TTY owner process group */
if (fscanf (f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */
/* Flags */
if (fscanf (f, "%u ", &itmp) == 0) goto error; /* coverity[secure_coding] */
/* Minor faults (no memory page) */
if (fscanf (f, "%u ", &itmp) == 0) goto error; /* coverity[secure_coding] */
/* Minor faults, children */
if (fscanf (f, "%u ", &itmp) == 0) goto error; /* coverity[secure_coding] */
/* Major faults (memory page faults) */
if (fscanf (f, "%u ", &itmp) == 0) goto error; /* coverity[secure_coding] */
/* Major faults, children */
if (fscanf (f, "%u ", &itmp) == 0) goto error; /* coverity[secure_coding] */
/* utime */
if (fscanf (f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */
/* stime */
if (fscanf (f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */
/* utime, children */
if (fscanf (f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */
/* stime, children */
if (fscanf (f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */
/* jiffies remaining in current time slice */
if (fscanf (f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */
/* 'nice' value */
if (fscanf (f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */
/* jiffies until next timeout */
if (fscanf (f, "%u ", &itmp) == 0) goto error; /* coverity[secure_coding] */
/* jiffies until next SIGALRM */
if (fscanf (f, "%u ", &itmp) == 0) goto error; /* coverity[secure_coding] */
/* start time (jiffies since system boot) */
if (fscanf (f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */
/* Virtual memory size */
if (fscanf (f, "%u ", &itmp) == 0) goto error; /* coverity[secure_coding] */
*vsize = (size_t) itmp;
/* Resident set size */
if (fscanf (f, "%u ", &itmp) == 0) goto error; /* coverity[secure_coding] */
*rss = (size_t) itmp * page_size;
/* rlim */
if (fscanf (f, "%u ", &itmp) == 0) goto error; /* coverity[secure_coding] */
/* Start of text */
if (fscanf (f, "%u ", &itmp) == 0) goto error; /* coverity[secure_coding] */
/* End of text */
if (fscanf (f, "%u ", &itmp) == 0) goto error; /* coverity[secure_coding] */
/* Start of stack */
if (fscanf (f, "%u ", &itmp) == 0) goto error; /* coverity[secure_coding] */
fclose (f);
return 0;
error:
fclose (f);
return -1;
}
int GetMemory2(size_t *rss, size_t *vsize) {
// See proc(5) manual
FILE *f = fopen("/proc/self/stat", "r");
if (!f) return -1;
int i;
int c;
// skip pid
c = fgetc(f);
if (c < '1' || c > '9') goto error;
do {
if ((c = fgetc(f)) == EOF) goto error;
} while (c >= '0' && c <= '9');
if (c != ' ') goto error;
if ((c = fgetc(f)) == EOF || c != '(') goto error;
// skip process name
do {
if ((c = fgetc(f)) == EOF) goto error;
} while (c != ')');
if ((c = fgetc(f)) == EOF || c != ' ') goto error;
// skip 20 columns
for(i=0; i<20; i++) {
do {
if ((c = fgetc(f)) == EOF) goto error;
if (c == ')') goto error; // the process name breaks parsing
} while (c != ' ');
}
// read vsize
size_t value = 0;
while (1) {
if ((c = fgetc(f)) == EOF) goto error;
if (c == ' ') break;
if (c < '0' || c > '9') goto error;
value = value * 10 + (c - '0');
}
*vsize = value;
// read rss
value = 0;
while (1) {
if ((c = fgetc(f)) == EOF) goto error;
if (c == ' ') break;
if (c < '0' || c > '9') goto error;
value = value * 10 + (c - '0');
}
*rss = value * getpagesize();
fclose(f);
return 0;
error:
*rss = *vsize = 0;
fclose(f);
return -1;
}
int GetMemory3(size_t *rss, size_t *vsize) {
// See proc(5) manual
int fd = open("/proc/self/stat", O_RDONLY);
if (fd < 0) return -1;
char buf[512];
ssize_t len = read(fd, buf, sizeof(buf));
close(fd);
if (len == sizeof(buf))
buf[sizeof(buf)-1] = '\n';
if (len <= 0 || buf[len-1] != '\n') goto error;
//if (len < 40) goto error;
char *p = buf;
if (*p < '1' || *p > '9') goto error;
do {
if (*++p == '\n') goto error;
} while (*p >= '0' && *p <= '9');
if (*p != ' ') goto error;
if (*++p != '(') goto error;
// skip process name
do {
if (*++p == '\n') goto error;
} while (*p != ')');
if (*++p != ' ') goto error;
// skip 20 columns
int i;
for(i=0; i<20; i++) {
do {
if (*++p == '\n') goto error;
if (*p == ')') goto error; // the process name breaks parsing
} while (*p != ' ');
}
// read vsize
size_t value = 0;
int c;
while (1) {
c = *++p;
if (c == ' ') break;
if (c < '0' || c > '9') goto error;
value = value * 10 + (c - '0');
}
*vsize = value;
// read rss
value = 0;
while (1) {
c = *++p;
if (c == ' ') break;
if (c < '0' || c > '9') goto error;
value = value * 10 + (c - '0');
}
*rss = value * getpagesize();
return 0;
error:
*rss = *vsize = 0;
return -1;
}
typedef int (*GetMemory_func)(size_t *rss, size_t *vsize);
void test(GetMemory_func func)
{
struct timeval start, stop, diff;
size_t rss = 0, vsize = 0;
gettimeofday(&start, NULL);
int res = GetMemory(&rss, &vsize);
res = GetMemory(&rss, &vsize);
res = GetMemory(&rss, &vsize);
gettimeofday(&stop, NULL);
time_t sec = stop.tv_sec - start.tv_sec;
int usec = (int)stop.tv_usec - (int)start.tv_usec;
if (usec < 0) {
sec--;
usec += 1000000;
}
printf("%ld.%06d res = %d, rss = %zd, vsize = %zd\n", sec, usec, res, rss, vsize);
}
int main() {
FILE *f = fopen("/proc/self/stat", "r");
char s[2048];
fputs(fgets(s, sizeof(s), f), stdout);
fclose(f);
test(GetMemory);
test(GetMemory);
test(GetMemory2);
test(GetMemory3);
void * p = malloc(10*1024*1024);
test(GetMemory);
test(GetMemory2);
test(GetMemory3);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment