137 lines · 4.5 KB · TypeScript
RawDownload
// CRITICALimport { afterAll, describe, expect, it } from "bun:test";import { chmodSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";import { tmpdir } from "node:os";import { join } from "node:path";import { getGpuInfo } from "./gpu";import { parseAmdSmiMetricJson, parseAmdSmiStaticJson, parseRocmSmiText } from "./amd-gpu"; describe("AMD/ROCm GPU telemetry parsing", () => {  const metricJson = JSON.stringify({    gpu_data: [      {        gpu: 0,        mem_usage: {          total_vram: { value: 196288, unit: "MB" },          used_vram: { value: 285, unit: "MB" },          free_vram: { value: 196003, unit: "MB" },        },        usage: { gfx_activity: { value: 12, unit: "%" } },        temperature: { hotspot: { value: 34, unit: "C" } },        power: { socket_power: { value: 153, unit: "W" } },      },    ],  });   const staticJson = JSON.stringify({    gpu_data: [      {        gpu: 0,        asic: {          market_name: "AMD Instinct MI300X VF",          target_graphics_version: "gfx942",        },      },    ],  });   const temporaryDirectory = mkdtempSync(join(tmpdir(), "vllm-studio-amd-gpu-"));  afterAll(() => {    rmSync(temporaryDirectory, { recursive: true, force: true });  });   it("parses amd-smi metric/static JSON shapes", () => {    const metrics = parseAmdSmiMetricJson(metricJson);    const statics = parseAmdSmiStaticJson(staticJson);    expect(metrics).toHaveLength(1);    expect(statics).toHaveLength(1);    expect(metrics[0]?.gpu).toBe(0);    expect(statics[0]?.asic?.market_name).toContain("MI300X");  });   it("uses amd-smi when forced via env and maps into GpuInfo", () => {    const bin = join(temporaryDirectory, "amd-smi");    const script = `#!/usr/bin/env bashset -euo pipefailif [[ "$1" == "metric" ]]; then  cat <<'JSON'${metricJson}JSON  exit 0fiif [[ "$1" == "static" ]]; then  cat <<'JSON'${staticJson}JSON  exit 0fiecho "unsupported" 1>&2exit 1`;    writeFileSync(bin, script, "utf-8");    chmodSync(bin, 0o755);     const originalPath = process.env["PATH"] ?? "";    process.env["PATH"] = `${temporaryDirectory}:${originalPath}`;    process.env["VLLM_STUDIO_GPU_SMI_TOOL"] = "amd-smi";    process.env["AMD_SMI_PATH"] = "amd-smi";     const gpus = getGpuInfo();    expect(gpus).toHaveLength(1);    expect(gpus[0]?.index).toBe(0);    expect(gpus[0]?.name).toContain("MI300X");    expect(gpus[0]?.memory_total_mb).toBe(196288);    expect(gpus[0]?.memory_used_mb).toBe(285);    expect(gpus[0]?.utilization_pct).toBe(12);    expect(gpus[0]?.temp_c).toBe(34);    expect(gpus[0]?.power_draw).toBe(153);     process.env["PATH"] = originalPath;    delete process.env["VLLM_STUDIO_GPU_SMI_TOOL"];    delete process.env["AMD_SMI_PATH"];  });   it("parses rocm-smi text output", () => {    const sample = [      "GPU[0] : Card model: AMD Instinct MI300X",      "GPU[0] : Total VRAM Memory (B): 34359738368",      "GPU[0] : Used VRAM Memory (B): 1073741824",      "GPU[0] : GPU use (%): 12",      "GPU[0] : Temperature (Sensor edge) (C): 45.0",      "GPU[0] : Average Graphics Package Power (W): 120.5",      "GPU[0] : Power Cap (W): 600.0",    ].join("\n");     const parsed = parseRocmSmiText(sample);    expect(parsed).toHaveLength(1);    expect(parsed[0]?.index).toBe(0);    expect(parsed[0]?.name).toContain("MI300X");    expect(parsed[0]?.memory_total_bytes).toBe(34359738368);    expect(parsed[0]?.memory_used_bytes).toBe(1073741824);    expect(parsed[0]?.utilization_pct).toBe(12);  });   it("selects rocm-smi when forced via env", () => {    const directory = mkdtempSync(join(tmpdir(), "vllm-studio-rocm-smi-"));    const scriptPath = join(directory, "rocm-smi");    const sample = "GPU[0] : Card model: AMD Instinct MI300X\nGPU[0] : Total VRAM Memory (B): 34359738368\n";    writeFileSync(scriptPath, `#!/usr/bin/env bash\nset -euo pipefail\necho '${sample.replace(/'/g, "'\\''")}'\n`);    chmodSync(scriptPath, 0o755);     const originalPath = process.env["PATH"] ?? "";    process.env["PATH"] = `${directory}:${originalPath}`;    process.env["VLLM_STUDIO_GPU_SMI_TOOL"] = "rocm-smi";    process.env["ROCM_SMI_PATH"] = "rocm-smi";     const gpus = getGpuInfo();    expect(gpus.length).toBe(1);    expect(gpus[0]?.name).toContain("MI300X");    expect(gpus[0]?.memory_total).toBe(34359738368);     process.env["PATH"] = originalPath;    delete process.env["VLLM_STUDIO_GPU_SMI_TOOL"];    delete process.env["ROCM_SMI_PATH"];    rmSync(directory, { recursive: true, force: true });  });});