@infersec/conduit 1.112.0 → 1.112.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +135 -42
- package/dist/cli.sea.cjs +135 -42
- package/dist/utils/machineInfo.d.ts +18 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -137936,12 +137936,20 @@ async function detectVRAMViaSysfs(pciBusSuffix) {
|
|
|
137936
137936
|
const deviceDir = path$1.join(DRM_PATH, entry, "device");
|
|
137937
137937
|
const totalStr = await readSysfsFile(path$1.join(deviceDir, "mem_info_vram_total"));
|
|
137938
137938
|
const usedStr = await readSysfsFile(path$1.join(deviceDir, "mem_info_vram_used"));
|
|
137939
|
+
const gttTotalStr = await readSysfsFile(path$1.join(deviceDir, "mem_info_gtt_total"));
|
|
137940
|
+
const gttUsedStr = await readSysfsFile(path$1.join(deviceDir, "mem_info_gtt_used"));
|
|
137939
137941
|
const totalBytes = totalStr !== null ? parseInt(totalStr, 10) : null;
|
|
137940
137942
|
const usedBytes = usedStr !== null ? parseInt(usedStr, 10) : null;
|
|
137943
|
+
const gttTotalBytes = gttTotalStr !== null ? parseInt(gttTotalStr, 10) : null;
|
|
137944
|
+
const gttUsedBytes = gttUsedStr !== null ? parseInt(gttUsedStr, 10) : null;
|
|
137941
137945
|
const validTotal = totalBytes !== null && Number.isFinite(totalBytes) && totalBytes >= 0;
|
|
137942
137946
|
const validUsed = usedBytes !== null && Number.isFinite(usedBytes) && usedBytes >= 0;
|
|
137947
|
+
const validGttTotal = gttTotalBytes !== null && Number.isFinite(gttTotalBytes) && gttTotalBytes >= 0;
|
|
137948
|
+
const validGttUsed = gttUsedBytes !== null && Number.isFinite(gttUsedBytes) && gttUsedBytes >= 0;
|
|
137943
137949
|
if (validTotal) {
|
|
137944
137950
|
return {
|
|
137951
|
+
gttTotalBytes: validGttTotal ? gttTotalBytes : null,
|
|
137952
|
+
gttUsedBytes: validGttUsed ? gttUsedBytes : null,
|
|
137945
137953
|
memoryTotalBytes: totalBytes,
|
|
137946
137954
|
memoryUsedBytes: validUsed ? usedBytes : null
|
|
137947
137955
|
};
|
|
@@ -137951,36 +137959,74 @@ async function detectVRAMViaSysfs(pciBusSuffix) {
|
|
|
137951
137959
|
catch {
|
|
137952
137960
|
// sysfs not available
|
|
137953
137961
|
}
|
|
137954
|
-
return {
|
|
137962
|
+
return {
|
|
137963
|
+
gttTotalBytes: null,
|
|
137964
|
+
gttUsedBytes: null,
|
|
137965
|
+
memoryTotalBytes: null,
|
|
137966
|
+
memoryUsedBytes: null
|
|
137967
|
+
};
|
|
137955
137968
|
}
|
|
137956
|
-
|
|
137969
|
+
// rocm-smi accepts a single --showmeminfo type per invocation, so VRAM and GTT
|
|
137970
|
+
// arrive from separate calls; both share this per-card parser.
|
|
137971
|
+
function parseRocmSmiMemory({ keyPrefix, stdout }) {
|
|
137972
|
+
const parsed = JSON.parse(stdout);
|
|
137973
|
+
const results = [];
|
|
137974
|
+
const cards = Object.entries(parsed).filter(([key]) => key.startsWith("card"));
|
|
137975
|
+
for (const [, data] of cards) {
|
|
137976
|
+
const bus = data["PCI Bus"] ?? null;
|
|
137977
|
+
const totalStr = data[`${keyPrefix} Total Memory (B)`] ?? null;
|
|
137978
|
+
const usedStr = data[`${keyPrefix} Total Used Memory (B)`] ?? null;
|
|
137979
|
+
const totalBytes = totalStr !== null ? parseInt(totalStr, 10) : null;
|
|
137980
|
+
const usedBytes = usedStr !== null ? parseInt(usedStr, 10) : null;
|
|
137981
|
+
const validTotal = totalBytes !== null && Number.isFinite(totalBytes) && totalBytes >= 0;
|
|
137982
|
+
const validUsed = usedBytes !== null && Number.isFinite(usedBytes) && usedBytes >= 0;
|
|
137983
|
+
if (bus) {
|
|
137984
|
+
results.push({
|
|
137985
|
+
bus,
|
|
137986
|
+
memoryTotalBytes: validTotal ? totalBytes : null,
|
|
137987
|
+
memoryUsedBytes: validUsed ? usedBytes : null
|
|
137988
|
+
});
|
|
137989
|
+
}
|
|
137990
|
+
}
|
|
137991
|
+
return results;
|
|
137992
|
+
}
|
|
137993
|
+
const ROCM_SMI_TIMEOUT_MS = 10_000;
|
|
137994
|
+
async function detectVRAMViaRocmSmi({ logger }) {
|
|
137957
137995
|
try {
|
|
137958
|
-
const
|
|
137959
|
-
"--showbus",
|
|
137960
|
-
|
|
137961
|
-
|
|
137962
|
-
"--json"
|
|
137996
|
+
const [vramResult, gttResult] = await Promise.allSettled([
|
|
137997
|
+
execa("rocm-smi", ["--showbus", "--showmeminfo", "vram", "--json"], {
|
|
137998
|
+
timeout: ROCM_SMI_TIMEOUT_MS
|
|
137999
|
+
}),
|
|
138000
|
+
execa("rocm-smi", ["--showbus", "--showmeminfo", "gtt", "--json"], {
|
|
138001
|
+
timeout: ROCM_SMI_TIMEOUT_MS
|
|
138002
|
+
})
|
|
137963
138003
|
]);
|
|
137964
|
-
|
|
137965
|
-
|
|
137966
|
-
|
|
137967
|
-
|
|
137968
|
-
|
|
137969
|
-
|
|
137970
|
-
|
|
137971
|
-
|
|
137972
|
-
const usedBytes = usedStr !== null ? parseInt(usedStr, 10) : null;
|
|
137973
|
-
const validTotal = totalBytes !== null && Number.isFinite(totalBytes) && totalBytes >= 0;
|
|
137974
|
-
const validUsed = usedBytes !== null && Number.isFinite(usedBytes) && usedBytes >= 0;
|
|
137975
|
-
if (bus) {
|
|
137976
|
-
results.push({
|
|
137977
|
-
bus,
|
|
137978
|
-
memoryTotalBytes: validTotal ? totalBytes : null,
|
|
137979
|
-
memoryUsedBytes: validUsed ? usedBytes : null
|
|
138004
|
+
if (vramResult.status !== "fulfilled")
|
|
138005
|
+
return [];
|
|
138006
|
+
let gttEntries = [];
|
|
138007
|
+
if (gttResult.status === "fulfilled") {
|
|
138008
|
+
try {
|
|
138009
|
+
gttEntries = parseRocmSmiMemory({
|
|
138010
|
+
keyPrefix: "GTT",
|
|
138011
|
+
stdout: gttResult.value.stdout
|
|
137980
138012
|
});
|
|
137981
138013
|
}
|
|
138014
|
+
catch (error) {
|
|
138015
|
+
// Unusable GTT output (e.g. older rocm-smi) degrades to VRAM-only
|
|
138016
|
+
logger.warn("rocm-smi GTT output parse failed", { error: asError(error) });
|
|
138017
|
+
}
|
|
137982
138018
|
}
|
|
137983
|
-
|
|
138019
|
+
const gttByBus = new Map(gttEntries.map(entry => [entry.bus, entry]));
|
|
138020
|
+
return parseRocmSmiMemory({ keyPrefix: "VRAM", stdout: vramResult.value.stdout }).map(vram => {
|
|
138021
|
+
const gtt = gttByBus.get(vram.bus);
|
|
138022
|
+
return {
|
|
138023
|
+
bus: vram.bus,
|
|
138024
|
+
gttTotalBytes: gtt?.memoryTotalBytes ?? null,
|
|
138025
|
+
gttUsedBytes: gtt?.memoryUsedBytes ?? null,
|
|
138026
|
+
memoryTotalBytes: vram.memoryTotalBytes,
|
|
138027
|
+
memoryUsedBytes: vram.memoryUsedBytes
|
|
138028
|
+
};
|
|
138029
|
+
});
|
|
137984
138030
|
}
|
|
137985
138031
|
catch {
|
|
137986
138032
|
return [];
|
|
@@ -138045,8 +138091,9 @@ async function detectGPUsViaNvidiaSmi({ logger }) {
|
|
|
138045
138091
|
vendor: "NVIDIA"
|
|
138046
138092
|
});
|
|
138047
138093
|
}
|
|
138048
|
-
//
|
|
138049
|
-
// memory. Their compute pool is system RAM, so fall back to
|
|
138094
|
+
// Shared/unified-memory devices (e.g. NVIDIA GB10 on DGX Spark) report
|
|
138095
|
+
// "[N/A]" for memory. Their compute pool is system RAM, so fall back to
|
|
138096
|
+
// /proc/meminfo. (AMD iGPUs get the same treatment via GTT merging.)
|
|
138050
138097
|
if (gpus.some(gpu => gpu.memoryTotalBytes === null)) {
|
|
138051
138098
|
const systemMemory = await readSystemMemoryBytes({ logger });
|
|
138052
138099
|
const total = systemMemory.totalBytes;
|
|
@@ -138070,7 +138117,7 @@ async function detectGPUsViaNvidiaSmi({ logger }) {
|
|
|
138070
138117
|
}
|
|
138071
138118
|
}
|
|
138072
138119
|
function buildMergedGPUs(options) {
|
|
138073
|
-
const { lspciGPUs, nvidiaGPUs, rocmVRAM, siGPUs, sysfsVRAMMap } = options;
|
|
138120
|
+
const { lspciGPUs, nvidiaGPUs, rocmVRAM, siGPUs, systemTotalBytes, sysfsVRAMMap } = options;
|
|
138074
138121
|
const rocmByBus = new Map();
|
|
138075
138122
|
for (const entry of rocmVRAM) {
|
|
138076
138123
|
const key = normalizeBusAddress(entry.bus);
|
|
@@ -138111,6 +138158,7 @@ function buildMergedGPUs(options) {
|
|
|
138111
138158
|
gpu: existing,
|
|
138112
138159
|
key,
|
|
138113
138160
|
rocmByBus,
|
|
138161
|
+
systemTotalBytes,
|
|
138114
138162
|
sysfsVRAMMap
|
|
138115
138163
|
});
|
|
138116
138164
|
}
|
|
@@ -138130,30 +138178,73 @@ function buildMergedGPUs(options) {
|
|
|
138130
138178
|
gpu,
|
|
138131
138179
|
key,
|
|
138132
138180
|
rocmByBus,
|
|
138181
|
+
systemTotalBytes,
|
|
138133
138182
|
sysfsVRAMMap
|
|
138134
138183
|
});
|
|
138135
138184
|
byBus.set(key, gpu);
|
|
138136
138185
|
}
|
|
138137
138186
|
return [...byBus.values()];
|
|
138138
138187
|
}
|
|
138139
|
-
|
|
138188
|
+
// Shared-memory GPUs (AMD iGPUs) expose a small dedicated VRAM carve-out via
|
|
138189
|
+
// mem_info_vram_total while the real usable pool - GTT - is carved dynamically
|
|
138190
|
+
// from system RAM. When GTT exceeds VRAM the device is treated as integrated
|
|
138191
|
+
// and the two pools combine (capped by installed RAM). Note that GTT defaults
|
|
138192
|
+
// to half of system RAM even on discrete GPUs, so a dGPU with less VRAM than
|
|
138193
|
+
// that also merges - acceptable, since GTT remains real addressable memory
|
|
138194
|
+
// for amdgpu compute (albeit slower over PCIe).
|
|
138195
|
+
function mergeGTTMemory({ gttTotalBytes, gttUsedBytes, systemTotalBytes, vramTotalBytes, vramUsedBytes }) {
|
|
138196
|
+
if (vramTotalBytes === null || !Number.isFinite(vramTotalBytes)) {
|
|
138197
|
+
return { memoryTotalBytes: null, memoryUsedBytes: null };
|
|
138198
|
+
}
|
|
138199
|
+
const isIntegrated = gttTotalBytes !== null && gttTotalBytes > vramTotalBytes;
|
|
138200
|
+
if (!isIntegrated) {
|
|
138201
|
+
return { memoryTotalBytes: vramTotalBytes, memoryUsedBytes: vramUsedBytes };
|
|
138202
|
+
}
|
|
138203
|
+
const combined = vramTotalBytes + gttTotalBytes;
|
|
138204
|
+
const capped = systemTotalBytes !== null && systemTotalBytes > 0
|
|
138205
|
+
? Math.min(combined, systemTotalBytes)
|
|
138206
|
+
: combined;
|
|
138207
|
+
const hasCompleteUsage = vramUsedBytes !== null &&
|
|
138208
|
+
Number.isFinite(vramUsedBytes) &&
|
|
138209
|
+
gttUsedBytes !== null &&
|
|
138210
|
+
Number.isFinite(gttUsedBytes);
|
|
138211
|
+
const memoryUsedBytes = hasCompleteUsage
|
|
138212
|
+
? Math.min(vramUsedBytes + gttUsedBytes, capped)
|
|
138213
|
+
: null;
|
|
138214
|
+
return { memoryTotalBytes: capped, memoryUsedBytes };
|
|
138215
|
+
}
|
|
138216
|
+
function applySysfsOrRocmVRAM({ gpu, key, rocmByBus, systemTotalBytes, sysfsVRAMMap }) {
|
|
138140
138217
|
const sysfs = sysfsVRAMMap.get(key);
|
|
138141
|
-
let
|
|
138142
|
-
let
|
|
138143
|
-
|
|
138218
|
+
let vramTotalBytes = sysfs?.memoryTotalBytes ?? null;
|
|
138219
|
+
let vramUsedBytes = sysfs?.memoryUsedBytes ?? null;
|
|
138220
|
+
let gttTotalBytes = sysfs?.gttTotalBytes ?? null;
|
|
138221
|
+
let gttUsedBytes = sysfs?.gttUsedBytes ?? null;
|
|
138222
|
+
if (vramTotalBytes === null) {
|
|
138144
138223
|
const rocm = rocmByBus.get(key);
|
|
138145
138224
|
if (rocm) {
|
|
138146
|
-
|
|
138147
|
-
|
|
138148
|
-
|
|
138149
|
-
|
|
138150
|
-
|
|
138225
|
+
vramTotalBytes = rocm.memoryTotalBytes;
|
|
138226
|
+
vramUsedBytes = rocm.memoryUsedBytes;
|
|
138227
|
+
gttTotalBytes = rocm.gttTotalBytes;
|
|
138228
|
+
gttUsedBytes = rocm.gttUsedBytes;
|
|
138229
|
+
}
|
|
138230
|
+
}
|
|
138231
|
+
const merged = mergeGTTMemory({
|
|
138232
|
+
gttTotalBytes,
|
|
138233
|
+
gttUsedBytes,
|
|
138234
|
+
systemTotalBytes,
|
|
138235
|
+
vramTotalBytes,
|
|
138236
|
+
vramUsedBytes
|
|
138237
|
+
});
|
|
138238
|
+
if (merged.memoryTotalBytes === null || !Number.isFinite(merged.memoryTotalBytes))
|
|
138151
138239
|
return;
|
|
138152
|
-
gpu.memoryTotalBytes =
|
|
138153
|
-
gpu.memoryUsedBytes =
|
|
138240
|
+
gpu.memoryTotalBytes = merged.memoryTotalBytes;
|
|
138241
|
+
gpu.memoryUsedBytes =
|
|
138242
|
+
merged.memoryUsedBytes !== null && Number.isFinite(merged.memoryUsedBytes)
|
|
138243
|
+
? merged.memoryUsedBytes
|
|
138244
|
+
: null;
|
|
138154
138245
|
gpu.memoryFreeBytes =
|
|
138155
|
-
|
|
138156
|
-
? Math.max(
|
|
138246
|
+
gpu.memoryUsedBytes !== null
|
|
138247
|
+
? Math.max(gpu.memoryTotalBytes - gpu.memoryUsedBytes, 0)
|
|
138157
138248
|
: null;
|
|
138158
138249
|
}
|
|
138159
138250
|
async function collectMachineMetadata({ logger }) {
|
|
@@ -138164,7 +138255,7 @@ async function collectMachineMetadata({ logger }) {
|
|
|
138164
138255
|
si.graphics(),
|
|
138165
138256
|
detectGPUsViaLspci(),
|
|
138166
138257
|
detectGPUsViaNvidiaSmi({ logger }),
|
|
138167
|
-
detectVRAMViaRocmSmi()
|
|
138258
|
+
detectVRAMViaRocmSmi({ logger })
|
|
138168
138259
|
]);
|
|
138169
138260
|
const cpuInfo = cpuResult.status === "fulfilled" ? cpuResult.value : null;
|
|
138170
138261
|
const memInfo = memResult.status === "fulfilled" ? memResult.value : null;
|
|
@@ -138219,6 +138310,7 @@ async function collectMachineMetadata({ logger }) {
|
|
|
138219
138310
|
nvidiaGPUs: resolvedNvidiaGPUs,
|
|
138220
138311
|
rocmVRAM: resolvedRocmVRAM,
|
|
138221
138312
|
siGPUs,
|
|
138313
|
+
systemTotalBytes: memInfo?.total ?? null,
|
|
138222
138314
|
sysfsVRAMMap
|
|
138223
138315
|
});
|
|
138224
138316
|
const machineMetadata = {
|
|
@@ -342892,12 +342984,13 @@ async function runModelFit(options) {
|
|
|
342892
342984
|
console.log();
|
|
342893
342985
|
const feasible = filterFeasibleModels({ detection, models: recommendedModels });
|
|
342894
342986
|
if (feasible.length === 0) {
|
|
342987
|
+
const smallestTierGB = Math.min(...recommendedModels.map(model => model.vramTierGB));
|
|
342895
342988
|
console.error("No recommended models fit this hardware. " +
|
|
342896
342989
|
`Budget: ${formatBytes$1(detection.gpus.some(gpu => gpu.memoryTotalBytes)
|
|
342897
342990
|
? Math.max(...detection.gpus
|
|
342898
342991
|
.map(gpu => gpu.memoryTotalBytes ?? 0)
|
|
342899
342992
|
.filter(bytes => bytes > 0))
|
|
342900
|
-
: detection.memory.totalBytes)}. Smallest tier starts at
|
|
342993
|
+
: detection.memory.totalBytes)}. Smallest tier starts at ${smallestTierGB} GB.`);
|
|
342901
342994
|
process.exitCode = 1;
|
|
342902
342995
|
return;
|
|
342903
342996
|
}
|
package/dist/cli.sea.cjs
CHANGED
|
@@ -158165,12 +158165,20 @@ async function detectVRAMViaSysfs(pciBusSuffix) {
|
|
|
158165
158165
|
const deviceDir = path$1.join(DRM_PATH, entry, "device");
|
|
158166
158166
|
const totalStr = await readSysfsFile(path$1.join(deviceDir, "mem_info_vram_total"));
|
|
158167
158167
|
const usedStr = await readSysfsFile(path$1.join(deviceDir, "mem_info_vram_used"));
|
|
158168
|
+
const gttTotalStr = await readSysfsFile(path$1.join(deviceDir, "mem_info_gtt_total"));
|
|
158169
|
+
const gttUsedStr = await readSysfsFile(path$1.join(deviceDir, "mem_info_gtt_used"));
|
|
158168
158170
|
const totalBytes = totalStr !== null ? parseInt(totalStr, 10) : null;
|
|
158169
158171
|
const usedBytes = usedStr !== null ? parseInt(usedStr, 10) : null;
|
|
158172
|
+
const gttTotalBytes = gttTotalStr !== null ? parseInt(gttTotalStr, 10) : null;
|
|
158173
|
+
const gttUsedBytes = gttUsedStr !== null ? parseInt(gttUsedStr, 10) : null;
|
|
158170
158174
|
const validTotal = totalBytes !== null && Number.isFinite(totalBytes) && totalBytes >= 0;
|
|
158171
158175
|
const validUsed = usedBytes !== null && Number.isFinite(usedBytes) && usedBytes >= 0;
|
|
158176
|
+
const validGttTotal = gttTotalBytes !== null && Number.isFinite(gttTotalBytes) && gttTotalBytes >= 0;
|
|
158177
|
+
const validGttUsed = gttUsedBytes !== null && Number.isFinite(gttUsedBytes) && gttUsedBytes >= 0;
|
|
158172
158178
|
if (validTotal) {
|
|
158173
158179
|
return {
|
|
158180
|
+
gttTotalBytes: validGttTotal ? gttTotalBytes : null,
|
|
158181
|
+
gttUsedBytes: validGttUsed ? gttUsedBytes : null,
|
|
158174
158182
|
memoryTotalBytes: totalBytes,
|
|
158175
158183
|
memoryUsedBytes: validUsed ? usedBytes : null
|
|
158176
158184
|
};
|
|
@@ -158180,36 +158188,74 @@ async function detectVRAMViaSysfs(pciBusSuffix) {
|
|
|
158180
158188
|
catch {
|
|
158181
158189
|
// sysfs not available
|
|
158182
158190
|
}
|
|
158183
|
-
return {
|
|
158191
|
+
return {
|
|
158192
|
+
gttTotalBytes: null,
|
|
158193
|
+
gttUsedBytes: null,
|
|
158194
|
+
memoryTotalBytes: null,
|
|
158195
|
+
memoryUsedBytes: null
|
|
158196
|
+
};
|
|
158184
158197
|
}
|
|
158185
|
-
|
|
158198
|
+
// rocm-smi accepts a single --showmeminfo type per invocation, so VRAM and GTT
|
|
158199
|
+
// arrive from separate calls; both share this per-card parser.
|
|
158200
|
+
function parseRocmSmiMemory({ keyPrefix, stdout }) {
|
|
158201
|
+
const parsed = JSON.parse(stdout);
|
|
158202
|
+
const results = [];
|
|
158203
|
+
const cards = Object.entries(parsed).filter(([key]) => key.startsWith("card"));
|
|
158204
|
+
for (const [, data] of cards) {
|
|
158205
|
+
const bus = data["PCI Bus"] ?? null;
|
|
158206
|
+
const totalStr = data[`${keyPrefix} Total Memory (B)`] ?? null;
|
|
158207
|
+
const usedStr = data[`${keyPrefix} Total Used Memory (B)`] ?? null;
|
|
158208
|
+
const totalBytes = totalStr !== null ? parseInt(totalStr, 10) : null;
|
|
158209
|
+
const usedBytes = usedStr !== null ? parseInt(usedStr, 10) : null;
|
|
158210
|
+
const validTotal = totalBytes !== null && Number.isFinite(totalBytes) && totalBytes >= 0;
|
|
158211
|
+
const validUsed = usedBytes !== null && Number.isFinite(usedBytes) && usedBytes >= 0;
|
|
158212
|
+
if (bus) {
|
|
158213
|
+
results.push({
|
|
158214
|
+
bus,
|
|
158215
|
+
memoryTotalBytes: validTotal ? totalBytes : null,
|
|
158216
|
+
memoryUsedBytes: validUsed ? usedBytes : null
|
|
158217
|
+
});
|
|
158218
|
+
}
|
|
158219
|
+
}
|
|
158220
|
+
return results;
|
|
158221
|
+
}
|
|
158222
|
+
const ROCM_SMI_TIMEOUT_MS = 10_000;
|
|
158223
|
+
async function detectVRAMViaRocmSmi({ logger }) {
|
|
158186
158224
|
try {
|
|
158187
|
-
const
|
|
158188
|
-
"--showbus",
|
|
158189
|
-
|
|
158190
|
-
|
|
158191
|
-
"--json"
|
|
158225
|
+
const [vramResult, gttResult] = await Promise.allSettled([
|
|
158226
|
+
execa("rocm-smi", ["--showbus", "--showmeminfo", "vram", "--json"], {
|
|
158227
|
+
timeout: ROCM_SMI_TIMEOUT_MS
|
|
158228
|
+
}),
|
|
158229
|
+
execa("rocm-smi", ["--showbus", "--showmeminfo", "gtt", "--json"], {
|
|
158230
|
+
timeout: ROCM_SMI_TIMEOUT_MS
|
|
158231
|
+
})
|
|
158192
158232
|
]);
|
|
158193
|
-
|
|
158194
|
-
|
|
158195
|
-
|
|
158196
|
-
|
|
158197
|
-
|
|
158198
|
-
|
|
158199
|
-
|
|
158200
|
-
|
|
158201
|
-
const usedBytes = usedStr !== null ? parseInt(usedStr, 10) : null;
|
|
158202
|
-
const validTotal = totalBytes !== null && Number.isFinite(totalBytes) && totalBytes >= 0;
|
|
158203
|
-
const validUsed = usedBytes !== null && Number.isFinite(usedBytes) && usedBytes >= 0;
|
|
158204
|
-
if (bus) {
|
|
158205
|
-
results.push({
|
|
158206
|
-
bus,
|
|
158207
|
-
memoryTotalBytes: validTotal ? totalBytes : null,
|
|
158208
|
-
memoryUsedBytes: validUsed ? usedBytes : null
|
|
158233
|
+
if (vramResult.status !== "fulfilled")
|
|
158234
|
+
return [];
|
|
158235
|
+
let gttEntries = [];
|
|
158236
|
+
if (gttResult.status === "fulfilled") {
|
|
158237
|
+
try {
|
|
158238
|
+
gttEntries = parseRocmSmiMemory({
|
|
158239
|
+
keyPrefix: "GTT",
|
|
158240
|
+
stdout: gttResult.value.stdout
|
|
158209
158241
|
});
|
|
158210
158242
|
}
|
|
158243
|
+
catch (error) {
|
|
158244
|
+
// Unusable GTT output (e.g. older rocm-smi) degrades to VRAM-only
|
|
158245
|
+
logger.warn("rocm-smi GTT output parse failed", { error: asError(error) });
|
|
158246
|
+
}
|
|
158211
158247
|
}
|
|
158212
|
-
|
|
158248
|
+
const gttByBus = new Map(gttEntries.map(entry => [entry.bus, entry]));
|
|
158249
|
+
return parseRocmSmiMemory({ keyPrefix: "VRAM", stdout: vramResult.value.stdout }).map(vram => {
|
|
158250
|
+
const gtt = gttByBus.get(vram.bus);
|
|
158251
|
+
return {
|
|
158252
|
+
bus: vram.bus,
|
|
158253
|
+
gttTotalBytes: gtt?.memoryTotalBytes ?? null,
|
|
158254
|
+
gttUsedBytes: gtt?.memoryUsedBytes ?? null,
|
|
158255
|
+
memoryTotalBytes: vram.memoryTotalBytes,
|
|
158256
|
+
memoryUsedBytes: vram.memoryUsedBytes
|
|
158257
|
+
};
|
|
158258
|
+
});
|
|
158213
158259
|
}
|
|
158214
158260
|
catch {
|
|
158215
158261
|
return [];
|
|
@@ -158274,8 +158320,9 @@ async function detectGPUsViaNvidiaSmi({ logger }) {
|
|
|
158274
158320
|
vendor: "NVIDIA"
|
|
158275
158321
|
});
|
|
158276
158322
|
}
|
|
158277
|
-
//
|
|
158278
|
-
// memory. Their compute pool is system RAM, so fall back to
|
|
158323
|
+
// Shared/unified-memory devices (e.g. NVIDIA GB10 on DGX Spark) report
|
|
158324
|
+
// "[N/A]" for memory. Their compute pool is system RAM, so fall back to
|
|
158325
|
+
// /proc/meminfo. (AMD iGPUs get the same treatment via GTT merging.)
|
|
158279
158326
|
if (gpus.some(gpu => gpu.memoryTotalBytes === null)) {
|
|
158280
158327
|
const systemMemory = await readSystemMemoryBytes({ logger });
|
|
158281
158328
|
const total = systemMemory.totalBytes;
|
|
@@ -158299,7 +158346,7 @@ async function detectGPUsViaNvidiaSmi({ logger }) {
|
|
|
158299
158346
|
}
|
|
158300
158347
|
}
|
|
158301
158348
|
function buildMergedGPUs(options) {
|
|
158302
|
-
const { lspciGPUs, nvidiaGPUs, rocmVRAM, siGPUs, sysfsVRAMMap } = options;
|
|
158349
|
+
const { lspciGPUs, nvidiaGPUs, rocmVRAM, siGPUs, systemTotalBytes, sysfsVRAMMap } = options;
|
|
158303
158350
|
const rocmByBus = new Map();
|
|
158304
158351
|
for (const entry of rocmVRAM) {
|
|
158305
158352
|
const key = normalizeBusAddress(entry.bus);
|
|
@@ -158340,6 +158387,7 @@ function buildMergedGPUs(options) {
|
|
|
158340
158387
|
gpu: existing,
|
|
158341
158388
|
key,
|
|
158342
158389
|
rocmByBus,
|
|
158390
|
+
systemTotalBytes,
|
|
158343
158391
|
sysfsVRAMMap
|
|
158344
158392
|
});
|
|
158345
158393
|
}
|
|
@@ -158359,30 +158407,73 @@ function buildMergedGPUs(options) {
|
|
|
158359
158407
|
gpu,
|
|
158360
158408
|
key,
|
|
158361
158409
|
rocmByBus,
|
|
158410
|
+
systemTotalBytes,
|
|
158362
158411
|
sysfsVRAMMap
|
|
158363
158412
|
});
|
|
158364
158413
|
byBus.set(key, gpu);
|
|
158365
158414
|
}
|
|
158366
158415
|
return [...byBus.values()];
|
|
158367
158416
|
}
|
|
158368
|
-
|
|
158417
|
+
// Shared-memory GPUs (AMD iGPUs) expose a small dedicated VRAM carve-out via
|
|
158418
|
+
// mem_info_vram_total while the real usable pool - GTT - is carved dynamically
|
|
158419
|
+
// from system RAM. When GTT exceeds VRAM the device is treated as integrated
|
|
158420
|
+
// and the two pools combine (capped by installed RAM). Note that GTT defaults
|
|
158421
|
+
// to half of system RAM even on discrete GPUs, so a dGPU with less VRAM than
|
|
158422
|
+
// that also merges - acceptable, since GTT remains real addressable memory
|
|
158423
|
+
// for amdgpu compute (albeit slower over PCIe).
|
|
158424
|
+
function mergeGTTMemory({ gttTotalBytes, gttUsedBytes, systemTotalBytes, vramTotalBytes, vramUsedBytes }) {
|
|
158425
|
+
if (vramTotalBytes === null || !Number.isFinite(vramTotalBytes)) {
|
|
158426
|
+
return { memoryTotalBytes: null, memoryUsedBytes: null };
|
|
158427
|
+
}
|
|
158428
|
+
const isIntegrated = gttTotalBytes !== null && gttTotalBytes > vramTotalBytes;
|
|
158429
|
+
if (!isIntegrated) {
|
|
158430
|
+
return { memoryTotalBytes: vramTotalBytes, memoryUsedBytes: vramUsedBytes };
|
|
158431
|
+
}
|
|
158432
|
+
const combined = vramTotalBytes + gttTotalBytes;
|
|
158433
|
+
const capped = systemTotalBytes !== null && systemTotalBytes > 0
|
|
158434
|
+
? Math.min(combined, systemTotalBytes)
|
|
158435
|
+
: combined;
|
|
158436
|
+
const hasCompleteUsage = vramUsedBytes !== null &&
|
|
158437
|
+
Number.isFinite(vramUsedBytes) &&
|
|
158438
|
+
gttUsedBytes !== null &&
|
|
158439
|
+
Number.isFinite(gttUsedBytes);
|
|
158440
|
+
const memoryUsedBytes = hasCompleteUsage
|
|
158441
|
+
? Math.min(vramUsedBytes + gttUsedBytes, capped)
|
|
158442
|
+
: null;
|
|
158443
|
+
return { memoryTotalBytes: capped, memoryUsedBytes };
|
|
158444
|
+
}
|
|
158445
|
+
function applySysfsOrRocmVRAM({ gpu, key, rocmByBus, systemTotalBytes, sysfsVRAMMap }) {
|
|
158369
158446
|
const sysfs = sysfsVRAMMap.get(key);
|
|
158370
|
-
let
|
|
158371
|
-
let
|
|
158372
|
-
|
|
158447
|
+
let vramTotalBytes = sysfs?.memoryTotalBytes ?? null;
|
|
158448
|
+
let vramUsedBytes = sysfs?.memoryUsedBytes ?? null;
|
|
158449
|
+
let gttTotalBytes = sysfs?.gttTotalBytes ?? null;
|
|
158450
|
+
let gttUsedBytes = sysfs?.gttUsedBytes ?? null;
|
|
158451
|
+
if (vramTotalBytes === null) {
|
|
158373
158452
|
const rocm = rocmByBus.get(key);
|
|
158374
158453
|
if (rocm) {
|
|
158375
|
-
|
|
158376
|
-
|
|
158377
|
-
|
|
158378
|
-
|
|
158379
|
-
|
|
158454
|
+
vramTotalBytes = rocm.memoryTotalBytes;
|
|
158455
|
+
vramUsedBytes = rocm.memoryUsedBytes;
|
|
158456
|
+
gttTotalBytes = rocm.gttTotalBytes;
|
|
158457
|
+
gttUsedBytes = rocm.gttUsedBytes;
|
|
158458
|
+
}
|
|
158459
|
+
}
|
|
158460
|
+
const merged = mergeGTTMemory({
|
|
158461
|
+
gttTotalBytes,
|
|
158462
|
+
gttUsedBytes,
|
|
158463
|
+
systemTotalBytes,
|
|
158464
|
+
vramTotalBytes,
|
|
158465
|
+
vramUsedBytes
|
|
158466
|
+
});
|
|
158467
|
+
if (merged.memoryTotalBytes === null || !Number.isFinite(merged.memoryTotalBytes))
|
|
158380
158468
|
return;
|
|
158381
|
-
gpu.memoryTotalBytes =
|
|
158382
|
-
gpu.memoryUsedBytes =
|
|
158469
|
+
gpu.memoryTotalBytes = merged.memoryTotalBytes;
|
|
158470
|
+
gpu.memoryUsedBytes =
|
|
158471
|
+
merged.memoryUsedBytes !== null && Number.isFinite(merged.memoryUsedBytes)
|
|
158472
|
+
? merged.memoryUsedBytes
|
|
158473
|
+
: null;
|
|
158383
158474
|
gpu.memoryFreeBytes =
|
|
158384
|
-
|
|
158385
|
-
? Math.max(
|
|
158475
|
+
gpu.memoryUsedBytes !== null
|
|
158476
|
+
? Math.max(gpu.memoryTotalBytes - gpu.memoryUsedBytes, 0)
|
|
158386
158477
|
: null;
|
|
158387
158478
|
}
|
|
158388
158479
|
async function collectMachineMetadata({ logger }) {
|
|
@@ -158393,7 +158484,7 @@ async function collectMachineMetadata({ logger }) {
|
|
|
158393
158484
|
si.graphics(),
|
|
158394
158485
|
detectGPUsViaLspci(),
|
|
158395
158486
|
detectGPUsViaNvidiaSmi({ logger }),
|
|
158396
|
-
detectVRAMViaRocmSmi()
|
|
158487
|
+
detectVRAMViaRocmSmi({ logger })
|
|
158397
158488
|
]);
|
|
158398
158489
|
const cpuInfo = cpuResult.status === "fulfilled" ? cpuResult.value : null;
|
|
158399
158490
|
const memInfo = memResult.status === "fulfilled" ? memResult.value : null;
|
|
@@ -158448,6 +158539,7 @@ async function collectMachineMetadata({ logger }) {
|
|
|
158448
158539
|
nvidiaGPUs: resolvedNvidiaGPUs,
|
|
158449
158540
|
rocmVRAM: resolvedRocmVRAM,
|
|
158450
158541
|
siGPUs,
|
|
158542
|
+
systemTotalBytes: memInfo?.total ?? null,
|
|
158451
158543
|
sysfsVRAMMap
|
|
158452
158544
|
});
|
|
158453
158545
|
const machineMetadata = {
|
|
@@ -363121,12 +363213,13 @@ async function runModelFit(options) {
|
|
|
363121
363213
|
console.log();
|
|
363122
363214
|
const feasible = filterFeasibleModels({ detection, models: recommendedModels });
|
|
363123
363215
|
if (feasible.length === 0) {
|
|
363216
|
+
const smallestTierGB = Math.min(...recommendedModels.map(model => model.vramTierGB));
|
|
363124
363217
|
console.error("No recommended models fit this hardware. " +
|
|
363125
363218
|
`Budget: ${formatBytes$1(detection.gpus.some(gpu => gpu.memoryTotalBytes)
|
|
363126
363219
|
? Math.max(...detection.gpus
|
|
363127
363220
|
.map(gpu => gpu.memoryTotalBytes ?? 0)
|
|
363128
363221
|
.filter(bytes => bytes > 0))
|
|
363129
|
-
: detection.memory.totalBytes)}. Smallest tier starts at
|
|
363222
|
+
: detection.memory.totalBytes)}. Smallest tier starts at ${smallestTierGB} GB.`);
|
|
363130
363223
|
process.exitCode = 1;
|
|
363131
363224
|
return;
|
|
363132
363225
|
}
|
|
@@ -1,8 +1,26 @@
|
|
|
1
1
|
import type { InferenceAgentMachineMetadata } from "@infersec/definitions";
|
|
2
2
|
import type { Logger } from "@infersec/logger";
|
|
3
3
|
export declare function normalizeBusAddress(bus: string | null | undefined): string | null;
|
|
4
|
+
export declare function parseRocmSmiMemory({ keyPrefix, stdout }: {
|
|
5
|
+
keyPrefix: "GTT" | "VRAM";
|
|
6
|
+
stdout: string;
|
|
7
|
+
}): Array<{
|
|
8
|
+
bus: string;
|
|
9
|
+
memoryTotalBytes: number | null;
|
|
10
|
+
memoryUsedBytes: number | null;
|
|
11
|
+
}>;
|
|
4
12
|
export declare function parseNvidiaSmiNumber(value: string | undefined): number | null;
|
|
5
13
|
export declare function parseNvidiaSmiMemoryBytes(value: string | undefined): number | null;
|
|
14
|
+
export declare function mergeGTTMemory({ gttTotalBytes, gttUsedBytes, systemTotalBytes, vramTotalBytes, vramUsedBytes }: {
|
|
15
|
+
gttTotalBytes: number | null;
|
|
16
|
+
gttUsedBytes: number | null;
|
|
17
|
+
systemTotalBytes: number | null;
|
|
18
|
+
vramTotalBytes: number | null;
|
|
19
|
+
vramUsedBytes: number | null;
|
|
20
|
+
}): {
|
|
21
|
+
memoryTotalBytes: number | null;
|
|
22
|
+
memoryUsedBytes: number | null;
|
|
23
|
+
};
|
|
6
24
|
export declare function collectMachineMetadata({ logger }: {
|
|
7
25
|
logger: Logger;
|
|
8
26
|
}): Promise<InferenceAgentMachineMetadata>;
|