EverydayTech Platform - Developer Reference
Complete Source Code Documentation - All Applications
Loading...
Searching...
No Matches
sysinfo.js
Go to the documentation of this file.
1/*
2Copyright 2019-2021 Intel Corporation
3
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
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
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.
15*/
16
17var PDH_FMT_LONG = 0x00000100;
18var PDH_FMT_DOUBLE = 0x00000200;
19
20var promise = require('promise');
21if (process.platform == 'win32')
22{
23 var GM = require('_GenericMarshal');
24 GM.kernel32 = GM.CreateNativeProxy('kernel32.dll');
25 GM.kernel32.CreateMethod('GlobalMemoryStatusEx');
26
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');
35}
36
37function windows_cpuUtilization()
38{
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();
43 var err = 0;
44 if ((err = GM.pdh.PdhOpenQueryA(0, 0, p.cpu).Val) != 0) { p._rej(err); return; }
45
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; }
48
49 if ((err = GM.pdh.PdhCollectQueryData(p.cpu.Deref()).Val != 0)) { p._rej(err); return; }
50 p._timeout = setTimeout(function (po)
51 {
52 var u = { cpus: [] };
53 var bufSize = GM.CreateVariable(4);
54 var itemCount = GM.CreateVariable(4);
55 var buffer, szName, item;
56 var e;
57 if ((e = GM.pdh.PdhCollectQueryData(po.cpu.Deref()).Val != 0)) { po._rej(e); return; }
58
59 if ((e = GM.pdh.PdhGetFormattedCounterArrayA(po.cpuTotal.Deref(), PDH_FMT_DOUBLE, bufSize, itemCount, 0).Val) == -2147481646)
60 {
61 buffer = GM.CreateVariable(bufSize.toBuffer().readUInt32LE());
62 }
63 else
64 {
65 po._rej(e);
66 return;
67 }
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)
70 {
71 item = buffer.Deref(i * 24, 24);
72 szName = item.Deref(0, GM.PointerSize).Deref();
73 if (szName.String == '_Total')
74 {
75 u.total = item.Deref(16, 8).toBuffer().readDoubleLE();
76 }
77 else
78 {
79 u.cpus[parseInt(szName.String)] = item.Deref(16, 8).toBuffer().readDoubleLE();
80 }
81 }
82
83 GM.pdh.PdhRemoveCounter(po.cpuTotal.Deref());
84 GM.pdh.PdhCloseQuery(po.cpu.Deref());
85 p._res(u);
86 }, 100, p);
87
88 return (p);
89}
90function windows_memUtilization()
91{
92 var info = GM.CreateVariable(64);
93 info.Deref(0, 4).toBuffer().writeUInt32LE(64);
94 GM.kernel32.GlobalMemoryStatusEx(info);
95
96 var ret =
97 {
98 MemTotal: require('bignum').fromBuffer(info.Deref(8, 8).toBuffer(), { endian: 'little' }),
99 MemFree: require('bignum').fromBuffer(info.Deref(16, 8).toBuffer(), { endian: 'little' })
100 };
101
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();
106 return (ret);
107}
108
109var cpuLastIdle = [];
110var cpuLastSum = [];
111function linux_cpuUtilization() {
112 var ret = { cpus: [] };
113 var info = require('fs').readFileSync('/proc/stat');
114 var lines = info.toString().split('\n');
115 var columns;
116 var x, y;
117 var cpuNo = 0;
118 var currSum, currIdle, utilization;
119 for (var i in lines) {
120 columns = lines[i].split(' ');
121 if (!columns[0].startsWith('cpu')) { break; }
122
123 x = 0, currSum = 0;
124 while (columns[++x] == '');
125 for (y = x; y < columns.length; ++y) { currSum += parseInt(columns[y]); }
126 currIdle = parseInt(columns[3 + x]);
127
128 var diffIdle = currIdle - cpuLastIdle[cpuNo];
129 var diffSum = currSum - cpuLastSum[cpuNo];
130
131 utilization = (100 - ((diffIdle / diffSum) * 100));
132
133 cpuLastSum[cpuNo] = currSum;
134 cpuLastIdle[cpuNo] = currIdle;
135
136 if (!ret.total) {
137 ret.total = utilization;
138 } else {
139 ret.cpus.push(utilization);
140 }
141 ++cpuNo;
142 }
143
144 var p = new promise(function (res, rej) { this._res = res; this._rej = rej; });
145 p._res(ret);
146 return (p);
147}
148function linux_memUtilization()
149{
150 var ret = {};
151
152 var info = require('fs').readFileSync('/proc/meminfo').toString().split('\n');
153 var tokens;
154 for(var i in info)
155 {
156 tokens = info[i].split(' ');
157 switch(tokens[0])
158 {
159 case 'MemTotal:':
160 ret.total = parseInt(tokens[tokens.length - 2]);
161 break;
162 case 'MemAvailable:':
163 ret.free = parseInt(tokens[tokens.length - 2]);
164 break;
165 }
166 }
167 ret.percentFree = ((ret.free / ret.total) * 100);//.toFixed(2);
168 ret.percentConsumed = (((ret.total - ret.free) / ret.total) * 100);//.toFixed(2);
169 return (ret);
170}
171
172function macos_cpuUtilization()
173{
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');
179 child.waitExit();
180
181 var lines = child.stdout.str.split('\n');
182 if (lines[0].length > 0)
183 {
184 var usage = lines[0].split(':')[1];
185 var bdown = usage.split(',');
186
187 var tot = parseFloat(bdown[0].split('%')[0].trim()) + parseFloat(bdown[1].split('%')[0].trim());
188 ret._res({total: tot, cpus: []});
189 }
190 else
191 {
192 ret._rej('parse error');
193 }
194
195 return (ret);
196}
197function macos_memUtilization()
198{
199 var mem = { };
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');
205 child.waitExit();
206
207 var lines = child.stdout.str.split('\n');
208 if (lines[0].length > 0)
209 {
210 var usage = lines[0].split(':')[1];
211 var bdown = usage.split(',');
212 if (bdown.length > 2){ // new style - PhysMem: 5750M used (1130M wired, 634M compressor), 1918M unused.
213 mem.MemFree = parseInt(bdown[2].trim().split(' ')[0]);
214 } else { // old style - PhysMem: 6683M used (1606M wired), 9699M unused.
215 mem.MemFree = parseInt(bdown[1].trim().split(' ')[0]);
216 }
217 mem.MemUsed = parseInt(bdown[0].trim().split(' ')[0]);
218 mem.MemTotal = (mem.MemFree + mem.MemUsed);
219 mem.percentFree = ((mem.MemFree / mem.MemTotal) * 100);//.toFixed(2);
220 mem.percentConsumed = (((mem.MemTotal - mem.MemFree) / mem.MemTotal) * 100);//.toFixed(2);
221 return (mem);
222 }
223 else
224 {
225 throw ('Parse Error');
226 }
227}
228
229function windows_thermals()
230{
231 var ret = [];
232 try {
233 ret = require('win-wmi').query('ROOT\\WMI', 'SELECT CurrentTemperature,InstanceName FROM MSAcpi_ThermalZoneTemperature',['CurrentTemperature','InstanceName']);
234 if (ret[0]) {
235 for (var i = 0; i < ret.length; ++i) {
236 ret[i]['CurrentTemperature'] = ((parseFloat(ret[i]['CurrentTemperature']) / 10) - 273.15).toFixed(2);
237 }
238 }
239 } catch (ex) { }
240 return (ret);
241}
242
243function linux_thermals()
244{
245 var ret = [];
246 child = require('child_process').execFile('/bin/sh', ['sh']);
247 child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
248 child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
249 child.stdin.write("for folder in /sys/class/thermal/thermal_zone*/; do [ -e \"$folder/temp\" ] && echo \"$(cat \"$folder/temp\"),$(cat \"$folder/type\")\"; done\nexit\n");
250 child.waitExit();
251 if(child.stdout.str.trim()!='')
252 {
253 var lines = child.stdout.str.trim().split('\n');
254 for (var i = 0; i < lines.length; ++i)
255 {
256 var line = lines[i].trim().split(',');
257 ret.push({CurrentTemperature: (parseFloat(line[0])/1000), InstanceName: line[1]});
258 }
259 }
260 child = require('child_process').execFile('/bin/sh', ['sh']);
261 child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
262 child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
263 child.stdin.write("for mon in /sys/class/hwmon/hwmon*; do for label in \"$mon\"/temp*_label; do if [ -f $label ]; then echo $(cat \"$label\")___$(cat \"${label%_*}_input\"); fi; done; done;\nexit\n");
264 child.waitExit();
265 if(child.stdout.str.trim()!='')
266 {
267 var lines = child.stdout.str.trim().split('\n');
268 for (var i = 0; i < lines.length; ++i)
269 {
270 var line = lines[i].trim().split('___');
271 ret.push({ CurrentTemperature: (parseFloat(line[1])/1000), InstanceName: line[0] });
272 }
273 }
274 return (ret);
275}
276
277function macos_thermals()
278{
279 var ret = [];
280 var child = require('child_process').execFile('/bin/sh', ['sh']);
281 child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
282 child.stderr.on('data', function () { });
283 child.stdin.write('powermetrics --help | grep SMC\nexit\n');
284 child.waitExit();
285 if (child.stdout.str.trim() != '')
286 {
287 child = require('child_process').execFile('/bin/sh', ['sh']);
288 child.stdout.str = ''; child.stdout.on('data', function (c)
289 {
290 this.str += c.toString();
291 var tokens = this.str.trim().split('\n');
292 for (var i in tokens)
293 {
294 if (tokens[i].split(' die temperature: ').length > 1)
295 {
296 ret.push({CurrentTemperature: tokens[i].split(' ')[3], InstanceName: tokens[i].split(' ')[0]});
297 this.parent.kill();
298 }
299 }
300 });
301 child.stderr.on('data', function (c) {
302 if (c.toString().split('unable to get smc values').length > 1) { // error getting sensors so just kill
303 this.parent.kill();
304 return;
305 }
306 });
307 child.stdin.write('powermetrics -s smc -i 500 -n 1\n');
308 child.waitExit(2000);
309 }
310 return (ret);
311}
312
313switch(process.platform)
314{
315 case 'linux':
316 module.exports = { cpuUtilization: linux_cpuUtilization, memUtilization: linux_memUtilization, thermals: linux_thermals };
317 break;
318 case 'win32':
319 module.exports = { cpuUtilization: windows_cpuUtilization, memUtilization: windows_memUtilization, thermals: windows_thermals };
320 break;
321 case 'darwin':
322 module.exports = { cpuUtilization: macos_cpuUtilization, memUtilization: macos_memUtilization, thermals: macos_thermals };
323 break;
324}
325