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
|
||||
|
||||
**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.
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
<p><span class="bold">Affected versions:</span>
|
||||
< 4.31.1<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>
|
||||
|
||||
<h4>Impact</h4>
|
||||
|
||||
164
lib/graphics.js
164
lib/graphics.js
@ -14,11 +14,13 @@
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
const os = require('os');
|
||||
const fs = require('fs');
|
||||
const exec = require('child_process').exec;
|
||||
const execSync = require('child_process').execSync;
|
||||
const util = require('./util');
|
||||
|
||||
let _platform = process.platform;
|
||||
let _nvidiaSmiPath = '';
|
||||
|
||||
const _linux = (_platform === 'linux');
|
||||
const _darwin = (_platform === 'darwin');
|
||||
@ -204,7 +206,8 @@ function graphics(callback) {
|
||||
bus: '',
|
||||
busAddress: '',
|
||||
vram: -1,
|
||||
vramDynamic: false
|
||||
vramDynamic: false,
|
||||
pciID: ''
|
||||
};
|
||||
let isGraphicsController = false;
|
||||
// PCI bus IDs
|
||||
@ -238,9 +241,14 @@ function graphics(callback) {
|
||||
bus: '',
|
||||
busAddress: '',
|
||||
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;
|
||||
let endpos = lines[i].search(/\[[0-9a-f]{4}:[0-9a-f]{4}]|$/);
|
||||
let parts = lines[i].substr(vgapos, endpos - vgapos).split(':');
|
||||
@ -310,7 +318,7 @@ function graphics(callback) {
|
||||
return devices
|
||||
}, {});
|
||||
for (let deviceId in devices) {
|
||||
const device = devices[deviceId]
|
||||
const device = devices[deviceId];
|
||||
if (device['CL_DEVICE_TYPE'] === 'CL_DEVICE_TYPE_GPU') {
|
||||
let busAddress;
|
||||
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) {
|
||||
// parsen EDID
|
||||
// --> model
|
||||
@ -592,6 +705,11 @@ function graphics(callback) {
|
||||
if (!error) {
|
||||
let lines = stdout.toString().split('\n');
|
||||
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";
|
||||
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('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(
|
||||
workload
|
||||
).then(data => {
|
||||
// controller
|
||||
let csections = data[0].split(/\n\s*\n/);
|
||||
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
|
||||
let dsections = data[1].split(/\n\s*\n/);
|
||||
// result.displays = parseLinesWindowsDisplays(dsections);
|
||||
@ -732,12 +855,17 @@ function graphics(callback) {
|
||||
if (sections[i].trim() !== '') {
|
||||
|
||||
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({
|
||||
vendor: util.getValue(lines, 'AdapterCompatibility', '='),
|
||||
model: util.getValue(lines, 'name', '='),
|
||||
bus: util.getValue(lines, 'PNPDeviceID', '=').startsWith('PCI') ? 'PCI' : '',
|
||||
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;
|
||||
_resolutiony = util.toInt(util.getValue(lines, 'CurrentVerticalResolution', '=')) || _resolutiony;
|
||||
@ -749,30 +877,6 @@ function graphics(callback) {
|
||||
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) {
|
||||
let displays = [];
|
||||
let vendor = '';
|
||||
|
||||
1
lib/index.d.ts
vendored
1
lib/index.d.ts
vendored
@ -255,6 +255,7 @@ export namespace Systeminformation {
|
||||
busAddress?: string;
|
||||
vram: number;
|
||||
vramDynamic: boolean;
|
||||
subDeviceId?: string;
|
||||
}
|
||||
|
||||
interface GraphicsDisplayData {
|
||||
|
||||
@ -830,3 +830,4 @@ exports.stringToLower = stringToLower;
|
||||
exports.stringToString = stringToString;
|
||||
exports.stringSubstr = stringSubstr;
|
||||
exports.stringTrim = stringTrim;
|
||||
exports.WINDIR = WINDIR;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user