2Copyright 2019-2021 Intel Corporation
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
17var PDH_FMT_LONG = 0x00000100;
18var PDH_FMT_DOUBLE = 0x00000200;
20var promise = require('promise');
21if (process.platform == 'win32')
23 var GM = require('_GenericMarshal');
24 GM.kernel32 = GM.CreateNativeProxy('kernel32.dll');
25 GM.kernel32.CreateMethod('GlobalMemoryStatusEx');
27 GM.pdh = GM.CreateNativeProxy('pdh.dll');
28 GM.pdh.CreateMethod('PdhAddEnglishCounterA');
29 GM.pdh.CreateMethod('PdhCloseQuery');
30 GM.pdh.CreateMethod('PdhCollectQueryData');
31 GM.pdh.CreateMethod('PdhGetFormattedCounterValue');
32 GM.pdh.CreateMethod('PdhGetFormattedCounterArrayA');
33 GM.pdh.CreateMethod('PdhOpenQueryA');
34 GM.pdh.CreateMethod('PdhRemoveCounter');
37function windows_cpuUtilization()
39 var p = new promise(function (res, rej) { this._res = res; this._rej = rej; });
40 p.counter = GM.CreateVariable(16);
41 p.cpu = GM.CreatePointer();
42 p.cpuTotal = GM.CreatePointer();
44 if ((err = GM.pdh.PdhOpenQueryA(0, 0, p.cpu).Val) != 0) { p._rej(err); return; }
46 // This gets the CPU Utilization for each proc
47 if ((err = GM.pdh.PdhAddEnglishCounterA(p.cpu.Deref(), GM.CreateVariable('\\Processor(*)\\% Processor Time'), 0, p.cpuTotal).Val) != 0) { p._rej(err); return; }
49 if ((err = GM.pdh.PdhCollectQueryData(p.cpu.Deref()).Val != 0)) { p._rej(err); return; }
50 p._timeout = setTimeout(function (po)
53 var bufSize = GM.CreateVariable(4);
54 var itemCount = GM.CreateVariable(4);
55 var buffer, szName, item;
57 if ((e = GM.pdh.PdhCollectQueryData(po.cpu.Deref()).Val != 0)) { po._rej(e); return; }
59 if ((e = GM.pdh.PdhGetFormattedCounterArrayA(po.cpuTotal.Deref(), PDH_FMT_DOUBLE, bufSize, itemCount, 0).Val) == -2147481646)
61 buffer = GM.CreateVariable(bufSize.toBuffer().readUInt32LE());
68 if ((e = GM.pdh.PdhGetFormattedCounterArrayA(po.cpuTotal.Deref(), PDH_FMT_DOUBLE, bufSize, itemCount, buffer).Val) != 0) { po._rej(e); return; }
69 for(var i=0;i<itemCount.toBuffer().readUInt32LE();++i)
71 item = buffer.Deref(i * 24, 24);
72 szName = item.Deref(0, GM.PointerSize).Deref();
73 if (szName.String == '_Total')
75 u.total = item.Deref(16, 8).toBuffer().readDoubleLE();
79 u.cpus[parseInt(szName.String)] = item.Deref(16, 8).toBuffer().readDoubleLE();
83 GM.pdh.PdhRemoveCounter(po.cpuTotal.Deref());
84 GM.pdh.PdhCloseQuery(po.cpu.Deref());
90function windows_memUtilization()
92 var info = GM.CreateVariable(64);
93 info.Deref(0, 4).toBuffer().writeUInt32LE(64);
94 GM.kernel32.GlobalMemoryStatusEx(info);
98 MemTotal: require('bignum').fromBuffer(info.Deref(8, 8).toBuffer(), { endian: 'little' }),
99 MemFree: require('bignum').fromBuffer(info.Deref(16, 8).toBuffer(), { endian: 'little' })
102 ret.percentFree = ((ret.MemFree.div(require('bignum')('1048576')).toNumber() / ret.MemTotal.div(require('bignum')('1048576')).toNumber()) * 100);//.toFixed(2);
103 ret.percentConsumed = ((ret.MemTotal.sub(ret.MemFree).div(require('bignum')('1048576')).toNumber() / ret.MemTotal.div(require('bignum')('1048576')).toNumber()) * 100);//.toFixed(2);
104 ret.MemTotal = ret.MemTotal.toString();
105 ret.MemFree = ret.MemFree.toString();
111function linux_cpuUtilization() {
112 var ret = { cpus: [] };
113 var info = require('fs').readFileSync('/proc/stat');
114 var lines = info.toString().split('\n');
118 var currSum, currIdle, utilization;
119 for (var i in lines) {
120 columns = lines[i].split(' ');
121 if (!columns[0].startsWith('cpu')) { break; }
124 while (columns[++x] == '');
125 for (y = x; y < columns.length; ++y) { currSum += parseInt(columns[y]); }
126 currIdle = parseInt(columns[3 + x]);
128 var diffIdle = currIdle - cpuLastIdle[cpuNo];
129 var diffSum = currSum - cpuLastSum[cpuNo];
131 utilization = (100 - ((diffIdle / diffSum) * 100));
133 cpuLastSum[cpuNo] = currSum;
134 cpuLastIdle[cpuNo] = currIdle;
137 ret.total = utilization;
139 ret.cpus.push(utilization);
144 var p = new promise(function (res, rej) { this._res = res; this._rej = rej; });
148function linux_memUtilization()
152 var info = require('fs').readFileSync('/proc/meminfo').toString().split('\n');
156 tokens = info[i].split(' ');
160 ret.total = parseInt(tokens[tokens.length - 2]);
163 ret.free = parseInt(tokens[tokens.length - 2]);
167 ret.percentFree = ((ret.free / ret.total) * 100);//.toFixed(2);
168 ret.percentConsumed = (((ret.total - ret.free) / ret.total) * 100);//.toFixed(2);
172function macos_cpuUtilization()
174 var ret = new promise(function (res, rej) { this._res = res; this._rej = rej; });
175 var child = require('child_process').execFile('/bin/sh', ['sh']);
176 child.stdout.str = '';
177 child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
178 child.stdin.write('top -l 1 | grep -E "^CPU"\nexit\n');
181 var lines = child.stdout.str.split('\n');
182 if (lines[0].length > 0)
184 var usage = lines[0].split(':')[1];
185 var bdown = usage.split(',');
187 var tot = parseFloat(bdown[0].split('%')[0].trim()) + parseFloat(bdown[1].split('%')[0].trim());
188 ret._res({total: tot, cpus: []});
192 ret._rej('parse error');
197function macos_memUtilization()
200 var ret = new promise(function (res, rej) { this._res = res; this._rej = rej; });
201 var child = require('child_process').execFile('/bin/sh', ['sh']);
202 child.stdout.str = '';
203 child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
204 child.stdin.write('top -l 1 | grep -E "^Phys"\nexit\n');
207 var lines = child.stdout.str.split('\n');
208 if (lines[0].length > 0)
210 var usage = lines[0].split(':')[1];
211 var bdown = usage.split(',');
213 mem.MemTotal = parseInt(bdown[0].trim().split(' ')[0]);
214 mem.MemFree = parseInt(bdown[1].trim().split(' ')[0]);
215 mem.percentFree = ((mem.MemFree / mem.MemTotal) * 100);//.toFixed(2);
216 mem.percentConsumed = (((mem.MemTotal - mem.MemFree) / mem.MemTotal) * 100);//.toFixed(2);
221 throw ('Parse Error');
225function windows_thermals()
229 ret = require('win-wmi').query('ROOT\\WMI', 'SELECT CurrentTemperature,InstanceName FROM MSAcpi_ThermalZoneTemperature',['CurrentTemperature','InstanceName']);
231 for (var i = 0; i < ret.length; ++i) {
232 ret[i]['CurrentTemperature'] = ((parseFloat(ret[i]['CurrentTemperature']) / 10) - 273.15).toFixed(2);
239function linux_thermals()
241 child = require('child_process').execFile('/bin/sh', ['sh']);
242 child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
243 child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
244 child.stdin.write("cat /sys/class/thermal/thermal_zone*/temp | awk '{ print $0 / 1000 }'\nexit\n");
246 var ret = child.stdout.str.trim().split('\n');
247 if (ret.length == 1 && ret[0] == '') { ret = []; }
251function macos_thermals()
254 var child = require('child_process').execFile('/bin/sh', ['sh']);
255 child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
256 child.stderr.on('data', function () { });
257 child.stdin.write('powermetrics --help | grep SMC\nexit\n');
260 if (child.stdout.str.trim() != '')
262 child = require('child_process').execFile('/bin/sh', ['sh']);
263 child.stdout.str = ''; child.stdout.on('data', function (c)
265 this.str += c.toString();
266 var tokens = this.str.trim().split('\n');
267 for (var i in tokens)
269 if (tokens[i].split(' die temperature: ').length > 1)
271 ret.push(tokens[i].split(' ')[3]);
276 child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
277 child.stdin.write('powermetrics -s smc\n');
278 child.waitExit(5000);
283const platformConfig = {
284 linux: { cpuUtilization: linux_cpuUtilization, memUtilization: linux_memUtilization, thermals: linux_thermals },
285 win32: { cpuUtilization: windows_cpuUtilization, memUtilization: windows_memUtilization, thermals: windows_thermals },
286 darwin: { cpuUtilization: macos_cpuUtilization, memUtilization: macos_memUtilization, thermals: macos_thermals }
289module.exports = platformConfig[process.platform];