Skip to content
This repository has been archived by the owner on Nov 28, 2023. It is now read-only.

Commit

Permalink
New: ProcessMemory now uses the new parser-based approach
Browse files Browse the repository at this point in the history
  • Loading branch information
stuartherbert committed Apr 15, 2013
1 parent 61fceaa commit b6bd586
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 69 deletions.
87 changes: 18 additions & 69 deletions app/features/ProcessMemory.js
Expand Up @@ -9,6 +9,9 @@ var util = require("util");
var _ = require("underscore");
var dsCommon = require("dsCommon");

// our parser
var ProcessStatusParser = require("../parsers/ProcessStatusParser");

function ProcessMemory(appServer) {
// call our parent constructor
ProcessMemory.super_.call(this, appServer, {
Expand All @@ -21,13 +24,13 @@ function ProcessMemory(appServer) {
module.exports = ProcessMemory;
util.inherits(ProcessMemory, dsCommon.dsFeature);

ProcessMemory.prototype.canMonitorPid = function(pid) {
// does the pid refer to an existing process?
if (!fs.existsSync("/proc/" + pid + "/status")) {
return false;
}

return true;
ProcessMemory.prototype.getFilenamesToMonitor = function(pid) {
return [
{
filename: "/proc/" + pid + "/status",
parser: new ProcessStatusParser()
}
];
};

ProcessMemory.prototype.reportUsage = function(pid, alias) {
Expand All @@ -40,69 +43,15 @@ ProcessMemory.prototype.reportUsage = function(pid, alias) {
// we can get the information we need from the process's status file
var filename = "/proc/" + pid + "/status";

// this will hold the raw contents of the status file
var content = "";

// this will hold the processed contents of the status file
var status = {};

// does the path exist?
if (!fs.existsSync(filename)) {
throw new Error("Cannot find file " + filename + " for process ID " + pid);
}

content = fs.readFileSync(filename, "ascii");

// extract the values that we want
_.each(content.split("\n"), function(line) {
// peak size of the virtual memory of the process
if (line.match(/^VmPeak/)) {
status.vmPeakSize = parseInt(line.split(/\s+/)[1], 10) * 1024;
}
// current total size of the virtual memory of the process
if (line.match(/^VmSize/)) {
status.vmCurrentSize = parseInt(line.split(/\s+/)[1], 10) * 1024;
}
// total amount of 'locked' memory
if (line.match(/^VmLck/)) {
status.vmLocked = parseInt(line.split(/\s+/)[1], 10) * 1024;
}
// high-water mark for resident set size
if (line.match(/^VmHWM/)) {
status.vmPeakRss = parseInt(line.split(/\s+/)[1], 10) * 1024;
}
// current resident set size
if (line.match(/^VmRSS/)) {
status.vmCurrentRss = parseInt(line.split(/\s+/)[1], 10) * 1024;
}
// current data segment size
if (line.match(/^VmData/)) {
status.vmData = parseInt(line.split(/\s+/)[1], 10) * 1024;
}
// current stack size
if (line.match(/^VmStk/)) {
status.vmStack = parseInt(line.split(/\s+/)[1], 10) * 1024;
}
// current code pages size
if (line.match(/^VmExe/)) {
status.vmExe = parseInt(line.split(/\s+/)[1], 10) * 1024;
}
// current library size
if (line.match(/^VmLib/)) {
status.vmLib = parseInt(line.split(/\s+/)[1], 10) * 1024;
}
// current page table entries size
if (line.match(/^VmPTE/)) {
status.vmPTE = parseInt(line.split(/\s+/)[1], 10) * 1024;
}
// current swap usage
if (line.match(/^VmSwap/)) {
status.vmSwap = parseInt(line.split(/\s+/)[1], 10) * 1024;
}
}, this);
// get the parsed data
var results = self.appServer.getLatestDataFor(filename);

// at this point, we have data to send to statsd
_.each(status, function(value, name) {
self.appServer.statsManager.count(alias + ".memory." + name, value);
_.each(results, function(value, name) {
if (name.match(/^Vm/)) {
self.appServer.statsManager.count(alias + ".memory." + name, value);
}
});

// all done
};
102 changes: 102 additions & 0 deletions app/parsers/ProcessStatusParser.js
@@ -0,0 +1,102 @@
// Copyright (c) 2013 Mediasift Ltd
// All rights reserved

// our built-in includes
var fs = require("fs");

// our third-party includes
var _ = require("underscore");

function ProcessStatusParser() {
// does nothing
}
module.exports = ProcessStatusParser;

ProcessStatusParser.prototype.retrieveStats = function(filename) {
// self-reference
var self = this;

// this will hold the processed contents of the file
var results = {};

// does the path exist
if (!fs.existsSync(filename)) {
throw new Error("Cannot find file " + filename);
}

// this will hold the raw contents of the status file
var content = fs.readFileSync(filename, "ascii");

// put the raw contents of the file into our data structure
_.each(content.trim().split("\n"), function(line){
var parsed = line.match(/^([A-Za-z0-9_]+):\s+(.*)$/);

// did the line parse?
if (!parsed) {
// no - we want to know why
console.log(line);
}
else {
results[parsed[1]] = parsed[2];
}

});

// we're going to be doing a bit of line parsing
var parsed = [];

// handle the individual lines that need further finessing

// Thread group ID
results.Tgid = parseInt(results.Tgid, 10);

// process ID
results.Pid = parseInt(results.Pid, 10);

// parent process ID
results.PPid = parseInt(results.PPid, 10);

// tracer process ID
results.TracerPid = parseInt(results.TracerPid, 10);

// user ID data
parsed = results.Uid.split(/\t/);
results.real_uid = parseInt(parsed[0], 10);
results.effective_uid = parseInt(parsed[1], 10);
results.saved_set_uid = parseInt(parsed[2], 10);
results.file_system_uid = parseInt(parsed[3], 10);

// group ID data
parsed = results.Gid.split(/\t/);
results.real_gid = parseInt(parsed[0], 10);
results.effective_gid = parseInt(parsed[1], 10);
results.saved_set_gid = parseInt(parsed[2], 10);
results.file_system_gid = parseInt(parsed[3], 10);

// file descriptor slots
results.FDSize = parseInt(results.FDSize, 10);

// groups list
results.groups_list = results.Groups.trim().split(/\s/);

// memory
_.each(["VmPeak", "VmSize", "VmLck", "VmPin", "VmHWM", "VmRSS", "VmData", "VmStk", "VmExe", "VmLib", "VmPTE", "VmSwap"], function(name) {
var parsed = results[name].split(/\s/);
results[name] = parseInt(parsed[0], 10) * 1024;
});

// threads
results.Threads = parseInt(results.Threads, 10);

// signals queued
parsed = results.SigQ.split('/');
results.signals_queued = parseInt(parsed[0], 10);
results.max_signal_queue = parseInt(parsed[1], 10);

// context switches
results.voluntary_ctxt_switches = parseInt(results.voluntary_ctxt_switches, 10);
results.nonvoluntary_ctxt_switches = parseInt(results.nonvoluntary_ctxt_switches, 10);

// all done
return results;
};

0 comments on commit b6bd586

Please sign in to comment.