graphics() adding nvidia-smi support (linux, win)
This commit is contained in:
parent
250f44dfab
commit
0da06759cb
@ -34,7 +34,7 @@ This is amazing. Started as a small project just for myself, it now has > 10,000
|
|||||||
|
|
||||||
## Upcoming
|
## Upcoming
|
||||||
|
|
||||||
**MacOS on ARM (Apple silicon support), Windows on ARM**: November 11th 2020 - We will have a closer look on that! I just ordered new hardware (any support is highly appreciated - [Buy me a coffe](https://www.buymeacoffee.com/systeminfo)). As soon as I have the new hardware here, I work very hard on it to get full native support for those platforms!
|
**MacOS on ARM (Apple silicon support), Windows on ARM**: November 11th 2020 - We will have a closer look on that! I just ordered new hardware (any support is highly appreciated - [Buy me a coffee](https://www.buymeacoffee.com/systeminfo)). As soon as I have the new hardware here, I work very hard on it to get full native support for those platforms!
|
||||||
|
|
||||||
**Version 5**: we are planning a new major version with some minor breaking changes and some additional features. Will try to make this available Q1 of 2021.
|
**Version 5**: we are planning a new major version with some minor breaking changes and some additional features. Will try to make this available Q1 of 2021.
|
||||||
|
|
||||||
|
|||||||
@ -46,7 +46,7 @@
|
|||||||
<p><span class="bold">Affected versions:</span>
|
<p><span class="bold">Affected versions:</span>
|
||||||
< 4.31.1<br>
|
< 4.31.1<br>
|
||||||
<span class="bold">Date:</span> 2020-12-11<br>
|
<span class="bold">Date:</span> 2020-12-11<br>
|
||||||
<span class="bold">CVE indentifier</span> CVE-2020-28448
|
<span class="bold">CVE indentifier</span> CVE-2020-26274, CVE-2020-28448
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h4>Impact</h4>
|
<h4>Impact</h4>
|
||||||
|
|||||||
164
lib/graphics.js
164
lib/graphics.js
@ -14,11 +14,13 @@
|
|||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
|
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
|
const fs = require('fs');
|
||||||
const exec = require('child_process').exec;
|
const exec = require('child_process').exec;
|
||||||
const execSync = require('child_process').execSync;
|
const execSync = require('child_process').execSync;
|
||||||
const util = require('./util');
|
const util = require('./util');
|
||||||
|
|
||||||
let _platform = process.platform;
|
let _platform = process.platform;
|
||||||
|
let _nvidiaSmiPath = '';
|
||||||
|
|
||||||
const _linux = (_platform === 'linux');
|
const _linux = (_platform === 'linux');
|
||||||
const _darwin = (_platform === 'darwin');
|
const _darwin = (_platform === 'darwin');
|
||||||
@ -204,7 +206,8 @@ function graphics(callback) {
|
|||||||
bus: '',
|
bus: '',
|
||||||
busAddress: '',
|
busAddress: '',
|
||||||
vram: -1,
|
vram: -1,
|
||||||
vramDynamic: false
|
vramDynamic: false,
|
||||||
|
pciID: ''
|
||||||
};
|
};
|
||||||
let isGraphicsController = false;
|
let isGraphicsController = false;
|
||||||
// PCI bus IDs
|
// PCI bus IDs
|
||||||
@ -238,9 +241,14 @@ function graphics(callback) {
|
|||||||
bus: '',
|
bus: '',
|
||||||
busAddress: '',
|
busAddress: '',
|
||||||
vram: -1,
|
vram: -1,
|
||||||
vramDynamic: false
|
vramDynamic: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const pciIDCandidate = lines[i].split(' ')[0];
|
||||||
|
if (/[\da-fA-F]{2}:[\da-fA-F]{2}\.[\da-fA-F]/.test(pciIDCandidate)) {
|
||||||
|
currentController.busAddress = pciIDCandidate;
|
||||||
|
}
|
||||||
isGraphicsController = true;
|
isGraphicsController = true;
|
||||||
let endpos = lines[i].search(/\[[0-9a-f]{4}:[0-9a-f]{4}]|$/);
|
let endpos = lines[i].search(/\[[0-9a-f]{4}:[0-9a-f]{4}]|$/);
|
||||||
let parts = lines[i].substr(vgapos, endpos - vgapos).split(':');
|
let parts = lines[i].substr(vgapos, endpos - vgapos).split(':');
|
||||||
@ -310,7 +318,7 @@ function graphics(callback) {
|
|||||||
return devices
|
return devices
|
||||||
}, {});
|
}, {});
|
||||||
for (let deviceId in devices) {
|
for (let deviceId in devices) {
|
||||||
const device = devices[deviceId]
|
const device = devices[deviceId];
|
||||||
if (device['CL_DEVICE_TYPE'] === 'CL_DEVICE_TYPE_GPU') {
|
if (device['CL_DEVICE_TYPE'] === 'CL_DEVICE_TYPE_GPU') {
|
||||||
let busAddress;
|
let busAddress;
|
||||||
if (device['CL_DEVICE_TOPOLOGY_AMD']) {
|
if (device['CL_DEVICE_TOPOLOGY_AMD']) {
|
||||||
@ -354,9 +362,114 @@ function graphics(callback) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return controllers
|
return controllers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getNvidiaSmi() {
|
||||||
|
if (_nvidiaSmiPath) {
|
||||||
|
return _nvidiaSmiPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_windows) {
|
||||||
|
try {
|
||||||
|
const basePath = util.WINDIR + '\\System32\\DriverStore\\FileRepository';
|
||||||
|
const dirContent = fs.readdirSync(basePath);
|
||||||
|
const candidateDirs = dirContent.filter(dir => dir.startsWith('nv'));
|
||||||
|
const targetDir = candidateDirs.find(dir => {
|
||||||
|
const content = fs.readdirSync([basePath, dir].join('/'));
|
||||||
|
return content.includes('nvidia-smi.exe');
|
||||||
|
});
|
||||||
|
|
||||||
|
if (targetDir) {
|
||||||
|
_nvidiaSmiPath = [basePath, targetDir, 'nvidia-smi.exe'].join('/');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
util.noop()
|
||||||
|
}
|
||||||
|
} else if (_linux) {
|
||||||
|
_nvidiaSmiPath = 'nvidia-smi';
|
||||||
|
}
|
||||||
|
return _nvidiaSmiPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
function nvidiaSmi(options) {
|
||||||
|
const nvidiaSmiExe = getNvidiaSmi();
|
||||||
|
if (nvidiaSmiExe) {
|
||||||
|
const nvidiaSmiOpts = '--query-gpu=driver_version,pci.sub_device_id,name,pci.bus_id,fan.speed,memory.total,memory.used,memory.free,utilization.gpu,utilization.memory,temperature.gpu,temperature.memory,power.draw,power.limit,clocks.gr,clocks.mem --format=csv,noheader,nounits'
|
||||||
|
try {
|
||||||
|
const res = execSync(nvidiaSmiExe + ' ' + nvidiaSmiOpts, options);
|
||||||
|
return res;
|
||||||
|
} catch (e) {
|
||||||
|
util.noop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function nvidiaDevices() {
|
||||||
|
|
||||||
|
function safeParseNumber(value) {
|
||||||
|
if ([null, undefined].includes(value)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return parseFloat(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const stdout = nvidiaSmi();
|
||||||
|
if (!stdout) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const gpus = stdout.split('\n').filter(Boolean);
|
||||||
|
const results = gpus.map(gpu => {
|
||||||
|
const splittedData = gpu.split(', ').map(value => value.includes('N/A') ? undefined : value);
|
||||||
|
if (splittedData.length === 16) {
|
||||||
|
return {
|
||||||
|
driverVersion: splittedData[0],
|
||||||
|
subDeviceId: splittedData[1],
|
||||||
|
name: splittedData[2],
|
||||||
|
pciBus: splittedData[3],
|
||||||
|
fanSpeed: safeParseNumber(splittedData[4]),
|
||||||
|
memoryTotal: safeParseNumber(splittedData[5]),
|
||||||
|
memoryUsed: safeParseNumber(splittedData[6]),
|
||||||
|
memoryFree: safeParseNumber(splittedData[7]),
|
||||||
|
utilizationGpu: safeParseNumber(splittedData[8]),
|
||||||
|
utilizationMemory: safeParseNumber(splittedData[9]),
|
||||||
|
temperatureGpu: safeParseNumber(splittedData[10]),
|
||||||
|
temperatureMemory: safeParseNumber(splittedData[11]),
|
||||||
|
powerDraw: safeParseNumber(splittedData[12]),
|
||||||
|
powerLimit: safeParseNumber(splittedData[13]),
|
||||||
|
clockCore: safeParseNumber(splittedData[14]),
|
||||||
|
clockMemory: safeParseNumber(splittedData[15]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mergeControllerNvidia(controller, nvidia) {
|
||||||
|
if (nvidia.driverVersion) { controller.driverVersion = nvidia.driverVersion; }
|
||||||
|
if (nvidia.subDeviceId) { controller.subDeviceId = nvidia.subDeviceId; }
|
||||||
|
if (nvidia.name) { controller.name = nvidia.name; }
|
||||||
|
if (nvidia.pciBus) { controller.pciBus = nvidia.pciBus; }
|
||||||
|
if (nvidia.fanSpeed) { controller.fanSpeed = nvidia.fanSpeed; }
|
||||||
|
if (nvidia.memoryTotal) { controller.memoryTotal = nvidia.memoryTotal; }
|
||||||
|
if (nvidia.memoryUsed) { controller.memoryUsed = nvidia.memoryUsed; }
|
||||||
|
if (nvidia.memoryFree) { controller.memoryFree = nvidia.memoryFree; }
|
||||||
|
if (nvidia.utilizationGpu) { controller.utilizationGpu = nvidia.utilizationGpu; }
|
||||||
|
if (nvidia.utilizationMemory) { controller.utilizationMemory = nvidia.utilizationMemory; }
|
||||||
|
if (nvidia.temperatureGpu) { controller.temperatureGpu = nvidia.temperatureGpu; }
|
||||||
|
if (nvidia.temperatureMemory) { controller.temperatureMemory = nvidia.temperatureMemory; }
|
||||||
|
if (nvidia.powerDraw) { controller.powerDraw = nvidia.powerDraw; }
|
||||||
|
if (nvidia.powerLimit) { controller.powerLimit = nvidia.powerLimit; }
|
||||||
|
if (nvidia.clockCore) { controller.clockCore = nvidia.clockCore; }
|
||||||
|
if (nvidia.clockMemory) { controller.clockMemory = nvidia.clockMemory; }
|
||||||
|
return controller
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function parseLinesLinuxEdid(edid) {
|
function parseLinesLinuxEdid(edid) {
|
||||||
// parsen EDID
|
// parsen EDID
|
||||||
// --> model
|
// --> model
|
||||||
@ -592,6 +705,11 @@ function graphics(callback) {
|
|||||||
if (!error) {
|
if (!error) {
|
||||||
let lines = stdout.toString().split('\n');
|
let lines = stdout.toString().split('\n');
|
||||||
result.controllers = parseLinesLinuxControllers(lines);
|
result.controllers = parseLinesLinuxControllers(lines);
|
||||||
|
const nvidiaData = nvidiaDevices();
|
||||||
|
// needs to be rewritten ... using no spread operators
|
||||||
|
result.controllers = result.controllers.map(( controller ) => { // match by busAddress
|
||||||
|
return mergeControllerNvidia(controller, nvidiaData.find(({ pciBus }) => pciBus.endsWith(controller.busAddress)) || {} );
|
||||||
|
})
|
||||||
}
|
}
|
||||||
let cmd = "clinfo --raw";
|
let cmd = "clinfo --raw";
|
||||||
exec(cmd, function (error, stdout) {
|
exec(cmd, function (error, stdout) {
|
||||||
@ -643,13 +761,18 @@ function graphics(callback) {
|
|||||||
workload.push(util.powerShell('Get-CimInstance -Namespace root\\wmi -ClassName WmiMonitorConnectionParams | fl'));
|
workload.push(util.powerShell('Get-CimInstance -Namespace root\\wmi -ClassName WmiMonitorConnectionParams | fl'));
|
||||||
workload.push(util.powerShell('gwmi WmiMonitorID -Namespace root\\wmi | ForEach-Object {(($_.ManufacturerName -notmatch 0 | foreach {[char]$_}) -join "") + "|" + (($_.ProductCodeID -notmatch 0 | foreach {[char]$_}) -join "") + "|" + (($_.UserFriendlyName -notmatch 0 | foreach {[char]$_}) -join "") + "|" + (($_.SerialNumberID -notmatch 0 | foreach {[char]$_}) -join "") + "|" + $_.InstanceName}'));
|
workload.push(util.powerShell('gwmi WmiMonitorID -Namespace root\\wmi | ForEach-Object {(($_.ManufacturerName -notmatch 0 | foreach {[char]$_}) -join "") + "|" + (($_.ProductCodeID -notmatch 0 | foreach {[char]$_}) -join "") + "|" + (($_.UserFriendlyName -notmatch 0 | foreach {[char]$_}) -join "") + "|" + (($_.SerialNumberID -notmatch 0 | foreach {[char]$_}) -join "") + "|" + $_.InstanceName}'));
|
||||||
|
|
||||||
|
const nvidiaData = nvidiaDevices();
|
||||||
|
|
||||||
Promise.all(
|
Promise.all(
|
||||||
workload
|
workload
|
||||||
).then(data => {
|
).then(data => {
|
||||||
// controller
|
// controller
|
||||||
let csections = data[0].split(/\n\s*\n/);
|
let csections = data[0].split(/\n\s*\n/);
|
||||||
result.controllers = parseLinesWindowsControllers(csections);
|
result.controllers = parseLinesWindowsControllers(csections);
|
||||||
|
// needs to be rewritten ... using no spread operators
|
||||||
|
result.controllers = result.controllers.map((controller) => { // match by subDeviceId
|
||||||
|
return mergeControllerNvidia(controller, nvidiaData.find(device => controller.subDeviceId.toLowerCase() === device.subDeviceId.split('x')[1].toLowerCase()) || {});
|
||||||
|
})
|
||||||
// displays
|
// displays
|
||||||
let dsections = data[1].split(/\n\s*\n/);
|
let dsections = data[1].split(/\n\s*\n/);
|
||||||
// result.displays = parseLinesWindowsDisplays(dsections);
|
// result.displays = parseLinesWindowsDisplays(dsections);
|
||||||
@ -732,12 +855,17 @@ function graphics(callback) {
|
|||||||
if (sections[i].trim() !== '') {
|
if (sections[i].trim() !== '') {
|
||||||
|
|
||||||
let lines = sections[i].trim().split('\r\n');
|
let lines = sections[i].trim().split('\r\n');
|
||||||
|
let subDeviceId = util.getValue(lines, 'PNPDeviceID', '=').match(/SUBSYS_[a-fA-F\d]{8}/)[0];
|
||||||
|
if (subDeviceId) {
|
||||||
|
subDeviceId = subDeviceId.split('_')[1];
|
||||||
|
}
|
||||||
controllers.push({
|
controllers.push({
|
||||||
vendor: util.getValue(lines, 'AdapterCompatibility', '='),
|
vendor: util.getValue(lines, 'AdapterCompatibility', '='),
|
||||||
model: util.getValue(lines, 'name', '='),
|
model: util.getValue(lines, 'name', '='),
|
||||||
bus: util.getValue(lines, 'PNPDeviceID', '=').startsWith('PCI') ? 'PCI' : '',
|
bus: util.getValue(lines, 'PNPDeviceID', '=').startsWith('PCI') ? 'PCI' : '',
|
||||||
vram: parseInt(util.getValue(lines, 'AdapterRAM', '='), 10) / 1024 / 1024,
|
vram: parseInt(util.getValue(lines, 'AdapterRAM', '='), 10) / 1024 / 1024,
|
||||||
vramDynamic: (util.getValue(lines, 'VideoMemoryType', '=') === '2')
|
vramDynamic: (util.getValue(lines, 'VideoMemoryType', '=') === '2'),
|
||||||
|
subDeviceId
|
||||||
});
|
});
|
||||||
_resolutionx = util.toInt(util.getValue(lines, 'CurrentHorizontalResolution', '=')) || _resolutionx;
|
_resolutionx = util.toInt(util.getValue(lines, 'CurrentHorizontalResolution', '=')) || _resolutionx;
|
||||||
_resolutiony = util.toInt(util.getValue(lines, 'CurrentVerticalResolution', '=')) || _resolutiony;
|
_resolutiony = util.toInt(util.getValue(lines, 'CurrentVerticalResolution', '=')) || _resolutiony;
|
||||||
@ -749,30 +877,6 @@ function graphics(callback) {
|
|||||||
return controllers;
|
return controllers;
|
||||||
}
|
}
|
||||||
|
|
||||||
// function parseLinesWindowsDisplays(sections) {
|
|
||||||
// let displays = [];
|
|
||||||
// for (let i in sections) {
|
|
||||||
// if (sections.hasOwnProperty(i)) {
|
|
||||||
// if (sections[i].trim() !== '') {
|
|
||||||
// let lines = sections[i].trim().split('\r\n');
|
|
||||||
// displays.push({
|
|
||||||
// vendor: util.getValue(lines, 'MonitorManufacturer', '='),
|
|
||||||
// model: util.getValue(lines, 'Name', '='),
|
|
||||||
// main: false,
|
|
||||||
// builtin: false,
|
|
||||||
// connection: '',
|
|
||||||
// sizex: -1,
|
|
||||||
// sizey: -1,
|
|
||||||
// pixeldepth: -1,
|
|
||||||
// resolutionx: util.toInt(util.getValue(lines, 'ScreenWidth', '=')),
|
|
||||||
// resolutiony: util.toInt(util.getValue(lines, 'ScreenHeight', '=')),
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return displays;
|
|
||||||
// }
|
|
||||||
|
|
||||||
function parseLinesWindowsDisplaysPowershell(ssections, msections, dsections, tsections, isections) {
|
function parseLinesWindowsDisplaysPowershell(ssections, msections, dsections, tsections, isections) {
|
||||||
let displays = [];
|
let displays = [];
|
||||||
let vendor = '';
|
let vendor = '';
|
||||||
|
|||||||
1
lib/index.d.ts
vendored
1
lib/index.d.ts
vendored
@ -255,6 +255,7 @@ export namespace Systeminformation {
|
|||||||
busAddress?: string;
|
busAddress?: string;
|
||||||
vram: number;
|
vram: number;
|
||||||
vramDynamic: boolean;
|
vramDynamic: boolean;
|
||||||
|
subDeviceId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GraphicsDisplayData {
|
interface GraphicsDisplayData {
|
||||||
|
|||||||
@ -830,3 +830,4 @@ exports.stringToLower = stringToLower;
|
|||||||
exports.stringToString = stringToString;
|
exports.stringToString = stringToString;
|
||||||
exports.stringSubstr = stringSubstr;
|
exports.stringSubstr = stringSubstr;
|
||||||
exports.stringTrim = stringTrim;
|
exports.stringTrim = stringTrim;
|
||||||
|
exports.WINDIR = WINDIR;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user