Skip to content

Add resident memory size to process statistics #32

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,9 @@ node_modules

# Users Environment Variables
.lock-wscript

# WebStorm IDE settings
.idea

# NPM package lock file
package-lock.json
8 changes: 4 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
language: node_js
node_js:
- "0.10"
- "0.12"
- "4.4"
- "6.2"
- "8"
- "9"
- "10"

os:
- linux
- centos
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
[![Node.js Version](https://img.shields.io/node/v/ps-tree.svg?style=flat)](http://nodejs.org/download/)
[![Dependency Status](https://david-dm.org/indexzero/ps-tree.svg)](https://david-dm.org/indexzero/ps-tree)

NOTE: This is a fork of [ps-tree](https://www.npmjs.com/package/ps-tree) NPM package, with some fixes and extras.

Sometimes you cannot kill child processes like you would expect, this a feature of UNIX.

>in UNIX, a process may terminate by using the exit call, and it's parent process may wait for that event by using the wait system call. the wait system call returns the process identifier of a terminated child, so that the parent tell which of the possibly many children has terminated. If the parent terminates, however, all it's children have assigned as their new parent the init process. Thus, the children still have a parent to collect their status and execution statistics.
Expand Down
52 changes: 40 additions & 12 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@
var spawn = require('child_process').spawn,
es = require('event-stream');

module.exports = function childrenOfPid(pid, callback) {
module.exports = function childrenOfPid(pid, includeRoot, callback) {
var headers = null;

// includeRoot is optional parameter
if (typeof includeRoot === 'function') {
callback = includeRoot;
includeRoot = false;
}

if (typeof callback !== 'function') {
throw new Error('childrenOfPid(pid, callback) expects callback');
}
Expand Down Expand Up @@ -42,11 +48,13 @@ module.exports = function childrenOfPid(pid, callback) {
var processLister;
if (process.platform === 'win32') {
// See also: https://github.com/nodejs/node-v0.x-archive/issues/2318
processLister = spawn('wmic.exe', ['PROCESS', 'GET', 'Name,ProcessId,ParentProcessId,Status']);
processLister = spawn('wmic.exe', ['PROCESS', 'GET', 'ProcessId,ParentProcessId,WorkingSetSize,Name']);
} else {
processLister = spawn('ps', ['-A', '-o', 'ppid,pid,stat,comm']);
processLister = spawn('ps', ['-A', '-o', 'ppid,pid,stat,rss,comm']);
}

processLister.on('error', callback);

es.connect(
// spawn('ps', ['-A', '-o', 'ppid,pid,stat,comm']).stdout,
processLister.stdout,
Expand All @@ -63,23 +71,43 @@ module.exports = function childrenOfPid(pid, callback) {
return cb();
}

// Convert RSS to number of bytes
if (process.platform == 'win32') {
columns[2] = parseInt(columns[2], 10);
}
else {
columns[3] = parseInt(columns[3], 10);
columns[3] *= 1024;
}

var row = {};
// For each header
var h = headers.slice();
while (h.length) {
row[h.shift()] = h.length ? columns.shift() : columns.join(' ');
}

// For Windows, WMIC.exe never returns any value for "Status" which used to get value corresponding to "STAT"
// See: https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-process?redirectedfrom=MSDN
// So just set "null" for the backward compatibility.
if (process.platform == 'win32') {
row['STAT'] = null;
}

return cb(null, row);
}),
es.writeArray(function (err, ps) {
var parents = [pid],
children = [];
var parents = {};
var children = [];

parents[pid] = true;

ps.forEach(function (proc) {
if (parents.indexOf(proc.PPID) !== -1) {
parents.push(proc.PID)
children.push(proc)
if (parents[proc.PPID]) {
parents[proc.PID] = true;
children.push(proc);
} else if (includeRoot && pid === proc.PID) {
children.push(proc);
}
});

Expand All @@ -96,22 +124,22 @@ module.exports = function childrenOfPid(pid, callback) {
*/
function normalizeHeader(str) {
if (process.platform !== 'win32') {
// HOTFIX: On Mac ps gives "COMM" instead of "COMMAND"
if (str === "COMM") return "COMMAND";
return str;
}

switch (str) {
case 'Name':
return 'COMMAND';
break;
case 'ParentProcessId':
return 'PPID';
break;
case 'ProcessId':
return 'PID';
break;
case 'Status':
return 'STAT';
break;
case 'WorkingSetSize':
return 'RSS';
default:
throw new Error('Unknown process listing header: ' + str);
}
Expand Down
13 changes: 6 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
{
"name": "ps-tree",
"version": "1.1.0",
"name": "@apify/ps-tree",
"version": "1.2.0",
"description": "Get all children of a pid",
"license": "MIT",
"homepage": "http://github.com/indexzero/ps-tree#readme",
"repository": "github:indexzero/ps-tree",
"homepage": "https://github.com/apifytech/ps-tree",
"repository": "https://github.com/apifytech/ps-tree",
"bugs": {
"url": "https://github.com/indexzero/ps-tree/issues",
"email": "charlie.robbins@gmail.com"
"url": "https://github.com/apifytech/ps-tree/issues"
},
"author": "Charlie Robbins <charlie.robbins@gmail.com>",
"contributors": [
Expand Down Expand Up @@ -39,7 +38,7 @@
"codeclimate": "cross-env CODECLIMATE_REPO_TOKEN=84436b4f13c70ace9c62e7f04928bf23c234eb212c0232d39d7fb1535beb2da5 codeclimate < coverage/lcov.info"
},
"dependencies": {
"event-stream": "~3.3.0"
"event-stream": "3.3.4"
},
"devDependencies": {
"chalk": "^1.0.0",
Expand Down
27 changes: 27 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ var red = chalk.red,
green = chalk.green,
cyan = chalk.cyan;

var isWin = process.platform === 'win32';
var isNumGreaterThanZero = (n) => !isNaN(parseInt(n, 10)) && n > 0;

var scripts = {
parent: path.join(__dirname, 'exec', 'parent.js'),
child: path.join(__dirname, 'exec', 'child.js')
Expand Down Expand Up @@ -49,6 +52,30 @@ test(cyan('FORCE ERROR by calling psTree without supplying a Callback'), functio
t.end();
});

test(cyan('Includes itself it includeRoot is true'), function (t) {
psTree(process.pid, true, function(err, children) {
if (err) { console.log(err); }
t.equal(children.length, 2, green('✓ Two processes found'));

var current;
var other;
if (children[0].PID === '' + process.pid) {
current = children[0];
other = children[1];
} else {
current = children[1];
other = children[0];
};

t.equal(current.PID, '' + process.pid, green('✓ Current PID is valid'));
t.equal(current.COMMAND, isWin ? 'node.exe' : 'node', green('✓ Current COMM is node'));
t.equal(isNumGreaterThanZero(current.RSS), true, green('✓ Current RSS is valid'));
t.notEqual(other.PID, '' + process.pid, green('✓ Current PID is valid'));
t.equal(other.COMMAND, isWin ? 'WMIC.exe' : 'ps', green('✓ Current COMM is ps'));
t.equal(isNumGreaterThanZero(other.RSS), true, green('✓ Other RSS is valid'));
t.end();
});
});

test(cyan('Spawn a Child Process and psTree with a String as pid'), function (t) {
var child = cp.exec('node ' + scripts.child, function(error, stdout, stderr) {});
Expand Down