diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c082c8..c0ef745 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -100,6 +100,7 @@ Other changes | Version | Date | Comment | | -------------- | -------------- | -------- | +| 3.50.3 | 2018-11-25 | `processLoad()`, `services()` fixed cpu data (linux) | | 3.50.2 | 2018-11-23 | network mac adresses: ip support fix | | 3.50.1 | 2018-11-23 | `services()` added possibility to specify ALL services "*" for win | | 3.50.0 | 2018-11-23 | `services()` added possibility to specify ALL services "*" for linux | diff --git a/lib/cpu.js b/lib/cpu.js index e01b98b..3898e32 100644 --- a/lib/cpu.js +++ b/lib/cpu.js @@ -132,7 +132,6 @@ function getAMDSpeed(brand) { for (let key in AMDBaseFrequencies) { if (AMDBaseFrequencies.hasOwnProperty(key)) { let parts = key.split('|'); - //console.log(item); let found = 0; parts.forEach(item => { if (brand.indexOf(item) > -1) { diff --git a/lib/processes.js b/lib/processes.js index 9b7d0cc..7dbd04c 100644 --- a/lib/processes.js +++ b/lib/processes.js @@ -29,6 +29,18 @@ const _sunos = (_platform === 'sunos'); const NOT_SUPPORTED = 'not supported'; +let _processes_cpu = { + all: 0, + list: {}, + ms: 0, + result: {} +}; +let _services_cpu = { + all: 0, + list: {}, + ms: 0, + result: {} +}; let _process_cpu = { all: 0, list: {}, @@ -86,7 +98,7 @@ function services(srv, callback) { if (srv) { srv = srv.trim().toLowerCase().replace(/,+/g, ' ').replace(/ +/g, ' ').replace(/ +/g, '|'); let srvs = srv.split('|'); - let data = []; + let result = []; let dataSrv = []; let allSrv = []; @@ -103,20 +115,33 @@ function services(srv, callback) { } srvs = srv.split('|'); } - let comm = (_darwin) ? 'ps -caxo pcpu,pmem,comm' : 'ps -axo pcpu,pmem,command'; + let comm = (_darwin) ? 'ps -caxo pcpu,pmem,pid,command' : 'ps -axo pcpu,pmem,pid,command'; if (srv !== '' && srvs.length > 0) { - exec(comm + ' | grep -v grep | egrep "' + srv + '"', { maxBuffer: 1024 * 2000 }, function (error, stdout) { + exec(comm + ' | grep -v grep | grep -iE "' + srv + '"', { maxBuffer: 1024 * 2000 }, function (error, stdout) { if (!error) { let lines = stdout.toString().replace(/ +/g, ' ').replace(/,+/g, '.').split('\n'); srvs.forEach(function (srv) { - let ps = lines.filter(function (e) { - return (e.toLowerCase().indexOf(' ' + srv + ':') !== -1) || (e.toLowerCase().indexOf('/' + srv) !== -1); - }); + let ps; + if (_darwin) { + ps = lines.filter(function (e) { + return (e.toLowerCase().indexOf(srv) !== -1); + }); + + } else { + ps = lines.filter(function (e) { + return (e.toLowerCase().indexOf(' ' + srv + ':') !== -1) || (e.toLowerCase().indexOf('/' + srv) !== -1); + }); + } let singleSrv = allSrv.filter(item => { return item.name === srv; }); - data.push({ + const pids = []; + for (const p of ps) { + pids.push(p.trim().split(' ')[2]); + } + result.push({ name: srv, running: (allSrv.length && singleSrv.length ? singleSrv[0].running : ps.length > 0), startmode: '', + pids: pids, pcpu: parseFloat((ps.reduce(function (pv, cv) { return pv + parseFloat(cv.trim().split(' ')[0]); }, 0)).toFixed(2)), @@ -125,8 +150,63 @@ function services(srv, callback) { }, 0)).toFixed(2)) }); }); - if (callback) { callback(data); } - resolve(data); + if (_linux) { + // calc process_cpu - ps is not accurate in linux! + let cmd = 'cat /proc/stat | grep "cpu "'; + for (let i in result) { + for (let j in result[i].pids) { + cmd += (';cat /proc/' + result[i].pids[j] + '/stat'); + } + } + exec(cmd, { maxBuffer: 1024 * 2000 }, 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 = calcProcStatLinux(curr_processes[i], all, _services_cpu); + + if (resultProcess.pid) { + let listPos = -1; + for (let i in result) { + for (let j in result[i].pids) { + if (parseInt(result[i].pids[j]) === parseInt(resultProcess.pid)) { + listPos = i; + } + } + } + if (listPos >= 0) { + result[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 + _services_cpu.all = all; + _services_cpu.list = list_new; + _services_cpu.ms = Date.now() - _services_cpu.ms; + _services_cpu.result = result; + if (callback) { callback(result); } + resolve(result); + }); + } else { + if (callback) { callback(result); } + resolve(result); + } } else { exec('ps -o comm | grep -v grep | egrep "' + srv + '"', { maxBuffer: 1024 * 2000 }, function (error, stdout) { if (!error) { @@ -135,7 +215,7 @@ function services(srv, callback) { let ps = lines.filter(function (e) { return e.indexOf(srv) !== -1; }); - data.push({ + result.push({ name: srv, running: ps.length > 0, startmode: '', @@ -143,11 +223,11 @@ function services(srv, callback) { pmem: 0 }); }); - if (callback) { callback(data); } - resolve(data); + if (callback) { callback(result); } + resolve(result); } else { srvs.forEach(function (srv) { - data.push({ + result.push({ name: srv, running: false, startmode: '', @@ -155,15 +235,15 @@ function services(srv, callback) { pmem: 0 }); }); - if (callback) { callback(data); } - resolve(data); + if (callback) { callback(result); } + resolve(result); } }); } }); } else { - if (callback) { callback(data); } - resolve(data); + if (callback) { callback(result); } + resolve(result); } } if (_windows) { @@ -178,7 +258,7 @@ function services(srv, callback) { let started = util.getValue(lines, 'Started', '=', true); let startMode = util.getValue(lines, 'StartMode', '=', true); if (srv === '*' || srvs.indexOf(srvName) >= 0) { - data.push({ + result.push({ name: srvName, running: (started === 'TRUE'), startmode: startMode, @@ -194,7 +274,7 @@ function services(srv, callback) { return dataSrv.indexOf(e) === -1; }); srvsMissing.forEach(function (srvName) { - data.push({ + result.push({ name: srvName, running: false, startmode: '', @@ -203,11 +283,11 @@ function services(srv, callback) { }); }); } - if (callback) { callback(data); } - resolve(data); + if (callback) { callback(result); } + resolve(result); } else { srvs.forEach(function (srvName) { - data.push({ + result.push({ name: srvName, running: false, startmode: '', @@ -215,13 +295,13 @@ function services(srv, callback) { pmem: 0 }); }); - if (callback) { callback(data); } - resolve(data); + if (callback) { callback(result); } + resolve(result); } }); } catch (e) { - if (callback) { callback(data); } - resolve(data); + if (callback) { callback(result); } + resolve(result); } } } else { @@ -234,6 +314,97 @@ function services(srv, callback) { exports.services = services; +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 calcProcStatLinux(line, all, _cpu_old) { + let statparts = line.replace(/ +/g, ' ').split(')'); + if (statparts.length >= 2) { + let parts = statparts[1].split(' '); + if (parts.length >= 16) { + let pid = parseInt(statparts[0].split(' ')[0]); + let utime = parseInt(parts[12]); + let stime = parseInt(parts[13]); + let cutime = parseInt(parts[14]); + let cstime = parseInt(parts[15]); + + // calc + let pcpuu = 0; + let pcpus = 0; + if (_cpu_old.all > 0 && _cpu_old.list[pid]) { + pcpuu = (utime + cutime - _cpu_old.list[pid].utime - _cpu_old.list[pid].cutime) / (all - _cpu_old.all) * 100; // user + pcpus = (stime + cstime - _cpu_old.list[pid].stime - _cpu_old.list[pid].cstime) / (all - _cpu_old.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 + }; + } + } else { + return { + pid: 0, + utime: 0, + stime: 0, + cutime: 0, + cstime: 0, + pcpuu: 0, + pcpus: 0 + }; + } +} + +function calcProcStatWin(procStat, all, _cpu_old) { + // calc + let pcpuu = 0; + let pcpus = 0; + if (_cpu_old.all > 0 && _cpu_old.list[procStat.pid]) { + pcpuu = (procStat.utime - _cpu_old.list[procStat.pid].utime) / (all - _cpu_old.all) * 100; // user + pcpus = (procStat.stime - _cpu_old.list[procStat.pid].stime) / (all - _cpu_old.all) * 100; // system + } else { + pcpuu = (procStat.utime) / (all) * 100; // user + pcpus = (procStat.stime) / (all) * 100; // system + } + return { + pid: procStat.pid, + utime: procStat.utime, + stime: procStat.stime, + pcpuu: pcpuu, + pcpus: pcpus + }; +} + + + // -------------------------- // running processes @@ -432,95 +603,6 @@ 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 statparts = line.replace(/ +/g, ' ').split(')'); - if (statparts.length >= 2) { - let parts = statparts[1].split(' '); - if (parts.length >= 16) { - let pid = parseInt(statparts[0].split(' ')[0]); - let utime = parseInt(parts[12]); - let stime = parseInt(parts[13]); - let cutime = parseInt(parts[14]); - let cstime = parseInt(parts[15]); - - // 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 - }; - } - } else { - return { - pid: 0, - utime: 0, - stime: 0, - cutime: 0, - cstime: 0, - pcpuu: 0, - pcpus: 0 - }; - } - } - - function calcProcPidStat(procStat, all) { - // calc - let pcpuu = 0; - let pcpus = 0; - if (_process_cpu.all > 0 && _process_cpu.list[procStat.pid]) { - pcpuu = (procStat.utime - _process_cpu.list[procStat.pid].utime) / (all - _process_cpu.all) * 100; // user - pcpus = (procStat.stime - _process_cpu.list[procStat.pid].stime) / (all - _process_cpu.all) * 100; // system - } else { - pcpuu = (procStat.utime) / (all) * 100; // user - pcpus = (procStat.stime) / (all) * 100; // system - } - return { - pid: procStat.pid, - utime: procStat.utime, - stime: procStat.stime, - pcpuu: pcpuu, - pcpus: pcpus - }; - } - return new Promise((resolve) => { process.nextTick(() => { let result = { @@ -534,7 +616,7 @@ function processes(callback) { let cmd = ''; - if ((_process_cpu.ms && Date.now() - _process_cpu.ms >= 500) || _process_cpu.ms === 0) { + if ((_processes_cpu.ms && Date.now() - _processes_cpu.ms >= 500) || _processes_cpu.ms === 0) { if (_linux || _freebsd || _openbsd || _darwin || _sunos) { if (_linux) cmd = 'export LC_ALL=C; ps -axo pid:11,ppid:11,pcpu:6,pmem:6,pri:5,vsz:11,rss:11,ni:5,lstart:30,state:5,tty:15,user:20,command; unset LC_ALL'; if (_freebsd || _openbsd) cmd = 'export LC_ALL=C; ps -axo pid,ppid,pcpu,pmem,pri,vsz,rss,ni,lstart,state,tty,user,command; unset LC_ALL'; @@ -570,7 +652,7 @@ function processes(callback) { let list_new = {}; let resultProcess = {}; for (let i = 0; i < curr_processes.length; i++) { - resultProcess = parseProcPidStat(curr_processes[i], all); + resultProcess = calcProcStatLinux(curr_processes[i], all, _processes_cpu); if (resultProcess.pid) { @@ -595,10 +677,10 @@ function processes(callback) { } // store old values - _process_cpu.all = all; - _process_cpu.list = list_new; - _process_cpu.ms = Date.now() - _process_cpu.ms; - _process_cpu.result = result; + _processes_cpu.all = all; + _processes_cpu.list = list_new; + _processes_cpu.ms = Date.now() - _processes_cpu.ms; + _processes_cpu.result = result; if (callback) { callback(result); } resolve(result); }); @@ -696,7 +778,7 @@ function processes(callback) { result.sleeping = result.all - result.running - result.blocked - result.unknown; result.list = procs; for (let i = 0; i < procStats.length; i++) { - let resultProcess = calcProcPidStat(procStats[i], allcpuu + allcpus); + let resultProcess = calcProcStatWin(procStats[i], allcpuu + allcpus, _processes_cpu); // store pcpu in outer array let listPos = result.list.map(function (e) { return e.pid; }).indexOf(resultProcess.pid); @@ -715,10 +797,10 @@ function processes(callback) { }; } // store old values - _process_cpu.all = allcpuu + allcpus; - _process_cpu.list = list_new; - _process_cpu.ms = Date.now() - _process_cpu.ms; - _process_cpu.result = result; + _processes_cpu.all = allcpuu + allcpus; + _processes_cpu.list = list_new; + _processes_cpu.ms = Date.now() - _processes_cpu.ms; + _processes_cpu.result = result; } if (callback) { callback(result); @@ -731,8 +813,8 @@ function processes(callback) { } } } else { - if (callback) { callback(_process_cpu.result); } - resolve(_process_cpu.result); + if (callback) { callback(_processes_cpu.result); } + resolve(_processes_cpu.result); } }); }); @@ -769,33 +851,86 @@ function processLoad(proc, callback) { }; if (proc) { - exec('ps -axo pid,pcpu,pmem,comm | grep ' + proc + ' | grep -v grep', { maxBuffer: 1024 * 2000 }, function (error, stdout) { + exec('ps -axo pid,pcpu,pmem,comm | grep -i ' + proc + ' | grep -v grep', { maxBuffer: 1024 * 2000 }, function (error, stdout) { if (!error) { let lines = stdout.toString().split('\n'); let pid = 0; + let pids = []; let cpu = 0; let mem = 0; lines.forEach(function (line) { - let data = line.replace(/ +/g, ' ').split(' '); + let data = line.trim().replace(/ +/g, ' ').split(' '); if (data.length > 3) { pid = (!pid ? parseInt(data[0]) : 0); + pids.push(parseInt(data[0], 10)); cpu = cpu + parseFloat(data[1].replace(',', '.')); mem = mem + parseFloat(data[2].replace(',', '.')); } }); - // TODO: calc process_cpu - ps is not accurate in linux! result = { 'proc': proc, 'pid': pid, + 'pids': pids, 'cpu': parseFloat((cpu / lines.length).toFixed(2)), 'mem': parseFloat((mem / lines.length).toFixed(2)) }; + if (_linux) { + // calc process_cpu - ps is not accurate in linux! + let cmd = 'cat /proc/stat | grep "cpu "'; + for (let i = 0; i < result.pids.length; i++) { + cmd += (';cat /proc/' + result.pids[i] + '/stat'); + } + + exec(cmd, { maxBuffer: 1024 * 2000 }, 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 = {}; + result.cpu = 0; + for (let i = 0; i < curr_processes.length; i++) { + resultProcess = calcProcStatLinux(curr_processes[i], all, _process_cpu); + + if (resultProcess.pid) { + + // store pcpu in outer result + result.cpu += 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 + }; + } + } + + result.cpu = Math.round(result.cpu * 100) / 100; + + _process_cpu.all = all; + _process_cpu.list = list_new; + _process_cpu.ms = Date.now() - _process_cpu.ms; + _process_cpu.result = result; + if (callback) { callback(result); } + resolve(result); + }); + } else { + if (callback) { callback(result); } + resolve(result); + } + } else { + if (callback) { callback(result); } + resolve(result); } - if (callback) { callback(result); } - resolve(result); }); } else { if (callback) { callback(result); }