From 7f0dacdeca2205e0f92f0d97c0176acbeb9a13f0 Mon Sep 17 00:00:00 2001 From: Sebastian Hildebrandt Date: Tue, 30 Aug 2016 10:28:14 +0200 Subject: [PATCH] rewritten processes current cpu usage linux --- README.md | 4 + lib/index.js | 201 +++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 184 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 4f6d3fb..a39d6e6 100644 --- a/README.md +++ b/README.md @@ -256,6 +256,9 @@ This library is splitted in several sections: | si.currentLoad(cb) | X | X | CPU-Load | | - avgload | X | X | average load | | - currentload | X | X | CPU-Load in % | +| - currentload_user | X | | CPU-Load User in % | +| - currentload_nice | X | | CPU-Load Nice in % | +| - currentload_system | X | | CPU-Load System in % | | si.fullLoad(cb) | X | X | CPU-full load since bootup in % | | si.services('mysql, apache2', cb) | X | X | pass comma separated string of services | | - [0].name | X | X | name of service | @@ -369,6 +372,7 @@ I am happy to discuss any comments and suggestions. Please feel free to contact | Version | Date | Comment | | -------------- | -------------- | -------- | +| 3.3.1 | 2016-08-30 | rewritten processes current cpu usage | | 3.3.0 | 2016-08-24 | process list added to processes | | 3.2.1 | 2016-08-19 | updated docs, improvement system | | 3.2.0 | 2016-08-19 | added battery information | diff --git a/lib/index.js b/lib/index.js index f214a58..42e14a7 100644 --- a/lib/index.js +++ b/lib/index.js @@ -80,6 +80,7 @@ // -------------------------------- // // version date comment +// 3.3.1 2016-08-30 current process cpu usage // 3.3.0 2016-08-24 added process list // 3.2.1 2016-08-20 updated docs, improvement system // 3.2.0 2016-08-19 added battery info @@ -127,6 +128,24 @@ var _fs_speed = {}; var _disk_io = {}; var _default_iface; var _docker_container_stats = {}; +var _process_cpu = { + all: 0, + list: {}, + ms: 0 +}; +var _current_cpu = { + user: 0, + nice: 0, + system: 0, + idle: 0, + iowait: 0, + irq: 0, + softirq: 0, + steal: 0, + guest: 0, + guest_nice: 0, + all: 0 +}; const NOT_SUPPORTED = 'not supported'; @@ -1487,19 +1506,61 @@ function getLoad() { let loads = os.loadavg().map(function (x) { return x / _cores; }); result.avgload = parseFloat((Math.max.apply(Math, loads)).toFixed(2)); result.currentload = -1; + result.currentload_user = -1; + result.currentload_nice = -1; + result.currentload_system = -1; - let cmd = (_darwin) ? "ps -cax -o pcpu" : "ps axo pcpu"; - exec(cmd, function (error, stdout) { - if (!error) { - let lines = stdout.toString().replace(/,+/g, ".").split('\n'); - lines.shift(); - lines.pop(); - result.currentload = parseFloat(((lines.reduce(function (pv, cv) { - return pv + parseFloat(cv.trim()); - }, 0)) / _cores).toFixed(2)); - } - resolve(result); - }); + if (_darwin) { + exec("ps -cax -o pcpu", function (error, stdout) { + if (!error) { + let lines = stdout.toString().replace(/,+/g, ".").split('\n'); + lines.shift(); + lines.pop(); + result.currentload = parseFloat(((lines.reduce(function (pv, cv) { + return pv + parseFloat(cv.trim()); + }, 0)) / _cores).toFixed(2)); + } + resolve(result); + }); + } + if (_linux) { + exec("cat /proc/stat | grep 'cpu '", function (error, stdout) { + if (!error) { + let lines = stdout.toString().split('\n'); + let parts = lines[0].replace(/ +/g, " ").split(' '); + let user = (parts.length >= 2 ? parseInt(parts[1]) : 0); + let nice = (parts.length >= 3 ? parseInt(parts[2]) : 0); + let system = (parts.length >= 4 ? parseInt(parts[3]) : 0); + let idle = (parts.length >= 5 ? parseInt(parts[4]) : 0); + let iowait = (parts.length >= 6 ? parseInt(parts[5]) : 0); + let irq = (parts.length >= 7 ? parseInt(parts[6]) : 0); + let softirq = (parts.length >= 8 ? parseInt(parts[7]) : 0); + let steal = (parts.length >= 9 ? parseInt(parts[8]) : 0); + let guest = (parts.length >= 10 ? parseInt(parts[9]) : 0); + let guest_nice = (parts.length >= 11 ? parseInt(parts[10]) : 0); + let all = user + nice + system + idle + iowait + irq + softirq + steal + guest + guest_nice; + result.currentload = (user + nice + system - _current_cpu.user - _current_cpu.nice - _current_cpu.system) / (all - _current_cpu.all) * 100; + + result.currentload_user = (user - _current_cpu.user) / (all - _current_cpu.all) * 100; + result.currentload_nice = (nice - _current_cpu.nice) / (all - _current_cpu.all) * 100; + result.currentload_system = (system - _current_cpu.system) / (all - _current_cpu.all) * 100; + _current_cpu = { + user: user, + nice: nice, + system: system, + idle: idle, + iowait: iowait, + irq: irq, + softirq: softirq, + steal: steal, + guest: guest, + guest_nice: guest_nice, + all: all + } + } + resolve(result); + }); + } }); }); } @@ -1760,6 +1821,61 @@ function processes(callback) { return result; } + function parseProcStat(line) { + let parts = line.replace(/ +/g, " ").split(' '); + let user = (parts.length >= 2 ? parseInt(parts[1]) : 0); + let nice = (parts.length >= 3 ? parseInt(parts[2]) : 0); + let system = (parts.length >= 4 ? parseInt(parts[3]) : 0); + let idle = (parts.length >= 5 ? parseInt(parts[4]) : 0); + let iowait = (parts.length >= 6 ? parseInt(parts[5]) : 0); + let irq = (parts.length >= 7 ? parseInt(parts[6]) : 0); + let softirq = (parts.length >= 8 ? parseInt(parts[7]) : 0); + let steal = (parts.length >= 9 ? parseInt(parts[8]) : 0); + let guest = (parts.length >= 10 ? parseInt(parts[9]) : 0); + let guest_nice = (parts.length >= 11 ? parseInt(parts[10]) : 0); + return user + nice + system + idle + iowait + irq + softirq + steal + guest + guest_nice; + } + function parseProcPidStat(line, all) { + let parts = line.replace(/ +/g, " ").split(' '); + if (parts.length >= 17) { + let pid = parseInt(parts[0]); + let utime = parseInt(parts[13]); + let stime = parseInt(parts[14]); + let cutime = parseInt(parts[15]); + let cstime = parseInt(parts[16]); + + // calc + let pcpuu = 0; + let pcpus = 0; + if (_process_cpu.all > 0 && _process_cpu.list[pid]) { + pcpuu = (utime + cutime - _process_cpu.list[pid].utime - _process_cpu.list[pid].cutime) / (all - _process_cpu.all) * 100; // user + pcpus = (stime + cstime - _process_cpu.list[pid].stime - _process_cpu.list[pid].cstime) / (all - _process_cpu.all) * 100; // system + } else { + pcpuu = (utime + cutime) / (all) * 100; // user + pcpus = (stime + cstime) / (all) * 100; // system + } + return { + pid: pid, + utime: utime, + stime: stime, + cutime: cutime, + cstime: cstime, + pcpuu: pcpuu, + pcpus: pcpus + } + } else { + return { + pid: 0, + utime: 0, + stime: 0, + cutime: 0, + cstime: 0, + pcpuu: 0, + pcpus: 0 + } + } + } + return new Promise((resolve, reject) => { process.nextTick(() => { if (_windows) { @@ -1776,7 +1892,7 @@ function processes(callback) { }; let cmd = ""; - if (_linux) cmd = "ps axo pid:10,pcpu:6,pmem:6,pri:5,vsz:10,rss:10,start:20,state:20,tty:20,user:20,command --sort=-pcpu"; + if (_linux) cmd = "ps axo pid:10,pcpu:6,pmem:6,pri:5,vsz:10,rss:10,start:20,state:20,tty:20,user:20,command"; if (_darwin) cmd = "ps acxo pid,pcpu,pmem,pri,vsz,rss,start,state,tty,user,command -r"; exec(cmd, function (error, stdout) { if (!error) { @@ -1790,10 +1906,58 @@ function processes(callback) { }).length; result.sleeping = result.list.filter(function (e) { return e.state == 'sleeping' - }).length + }).length; + + if (_linux) { + // calc process_cpu - ps is not accurate in linux! + cmd = "cat /proc/stat | grep 'cpu '"; + for (let i=0; i< result.list.length; i++) { + cmd += (';cat /proc/' + result.list[i].pid + '/stat') + } + exec(cmd, function (error, stdout) { + let curr_processes = stdout.toString().split('\n'); + + // first line (all - /proc/stat) + let all = parseProcStat(curr_processes.shift()); + + // process + let list_new = {}; + let resultProcess = {}; + for (let i=0; i< curr_processes.length; i++) { + resultProcess = parseProcPidStat(curr_processes[i], all); + + if (resultProcess.pid) { + + // store pcpu in outer array + let listPos = result.list.map(function(e) { return e.pid; }).indexOf(resultProcess.pid); + if (listPos >= 0) { + result.list[listPos].pcpu = resultProcess.pcpuu + resultProcess.pcpus + } + + // save new values + list_new[resultProcess.pid] = { + pcpuu: resultProcess.pcpuu, + pcpus: resultProcess.pcpus, + utime: resultProcess.utime, + stime: resultProcess.stime, + cutime: resultProcess.cutime, + cstime: resultProcess.cstime + } + } + } + + // store old values + _process_cpu.all = all; + _process_cpu.list = list_new; + _process_cpu.ms = Date.now() - _process_cpu.ms; + if (callback) { callback(result) } + resolve(result); + }) + } else { + if (callback) { callback(result) } + resolve(result); + } } - if (callback) { callback(result) } - resolve(result); }); }); }); @@ -1898,15 +2062,12 @@ function parseUsers1(lines) { w_pos.push(line.indexOf(item)) }); w_first = false; - // console.log(w_pos); - // console.log(result_who); } else { // split by w_pos result_w.user = line.substring(w_pos[0], w_pos[1]-1).trim(); result_w.tty = line.substring(w_pos[1], w_pos[2]-1).trim(); result_w.ip = line.substring(w_pos[2], w_pos[3]-1).replace(/\(/g, "").replace(/\)/g, "").trim(); result_w.command = line.substring(w_pos[7], 1000).trim(); - // console.log(result_w); // find corresponding 'who' line who_line = result_who.filter(function(obj) { return (obj.user.substring(0,8).trim() == result_w.user && obj.tty == result_w.tty) @@ -2171,7 +2332,6 @@ function dockerContainers(all, callback) { try { let jsonString = stdout.toString(); var docker_containers = JSON.parse(jsonString); - // console.log(docker_containers) if (docker_containers && Object.prototype.toString.call(docker_containers) === '[object Array]' && docker_containers.length > 0) { docker_containers.forEach(function (element) { /** @@ -2352,7 +2512,6 @@ function dockerContainerStats(containerID, callback) { * @property {Object} blkio_stats */ - //console.log(stats); if (!stats.message) { result.mem_usage = (stats.memory_stats && stats.memory_stats.usage ? stats.memory_stats.usage : 0); result.mem_limit = (stats.memory_stats && stats.memory_stats.limit ? stats.memory_stats.limit : 0);