From 68cdd7728a7cc6715bbbff7decfe2b11c3bdf558 Mon Sep 17 00:00:00 2001 From: Open-IOV Date: Wed, 23 Sep 2026 05:44:08 -0400 Subject: Open-IOV: initial public release Open-IOV virtualizes NVIDIA GPUs so that unmodified guest drivers run with real GPU functionality - CUDA first, 3D and video to follow - on unmodified hosts, without a proprietary vGPU license and without patching any driver, firmware or hypervisor. Core principle: emulate the interface, pass through the work. kernel/ open-iov-vfio.ko - host VFIO mdev driver: virtual GPU device (PCI config space, BAR shadows, MSI-X), GSP boot emulation, GSP-RM message-queue/RPC emulation, memory model (GPU-VA to guest-PA discovery) and the semaphore-completion service that advances guest UVM progress. userspace/ libiov.so management API and examples. tools/ guest diagnostics, firmware analysis wrappers, RM probes. scripts/ stack manager, VM harness, build/load/test automation. config/ hardware/version profiles (the portability surface). docs/ documentation tree - start at docs/README.md. wiki/ long-form firmware and protocol deep dives. Status: initialization works end to end for a stock 570.144 Linux guest on Turing (TU104): driver probe, nvidia-smi, the full GSP-RM control battery, object creation and the early CUDA/UVM start-up path. GPU work forwarding - the step that makes CUDA kernels execute on real hardware - is the active work item; see docs/04-implementation/01-known-knowns-and-unknowns.md. License: BSD-3-Clause for the project; GPL-2.0 for kernel modules that link GPL-only kernel interfaces. See LICENSE and docs/09-reference/legal-and-licensing.md. --- tools/benchmark_infrastructure.sh | 217 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100755 tools/benchmark_infrastructure.sh (limited to 'tools/benchmark_infrastructure.sh') diff --git a/tools/benchmark_infrastructure.sh b/tools/benchmark_infrastructure.sh new file mode 100755 index 0000000..606aa10 --- /dev/null +++ b/tools/benchmark_infrastructure.sh @@ -0,0 +1,217 @@ +#!/bin/bash +# benchmark_infrastructure.sh - Benchmark runner for VM vs bare metal comparison + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BASE_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" + +RESULTS_DIR="/tmp/gsp_emu_benchmarks/$(date +%Y%m%d_%H%M%S)" +mkdir -p "$RESULTS_DIR" + +log_info() { echo -e "\033[0;34m[INFO]\033[0m $1"; } +log_ok() { echo -e "\033[0;32m[OK]\033[0m $1"; } +log_warn() { echo -e "\033[1;33m[WARN]\033[0m $1"; } + +run_bare_metal() { + local test_name=$1 + shift + log_info "Running $test_name on bare metal..." + local output="$RESULTS_DIR/bare_metal_${test_name}.json" + "$@" --benchmark --output "$output" 2>&1 | tee "$RESULTS_DIR/bare_metal_${test_name}.log" +} + +run_in_vm() { + local test_name=$1 + shift + log_info "Running $test_name in VM..." + local output="$RESULTS_DIR/vm_${test_name}.json" + # This would run inside the guest via guest_test_agent + # For now, placeholder + echo '{"test": "'$test_name'", "status": "not_implemented"}' > "$output" +} + +compare_results() { + local test_name=$1 + local bare_file="$RESULTS_DIR/bare_metal_${test_name}.json" + local vm_file="$RESULTS_DIR/vm_${test_name}.json" + + if [[ -f "$bare_file" && -f "$vm_file" ]]; then + python3 -c " +import json, sys +with open('$bare_file') as f: bare = json.load(f) +with open('$vm_file') as f: vm = json.load(f) +print(f'Test: $test_name') +for key in bare: + if key in vm and isinstance(bare[key], (int, float)) and isinstance(vm[key], (int, float)): + ratio = vm[key] / bare[key] * 100 + print(f' {key}: bare={bare[key]:.2f} vm={vm[key]:.2f} ratio={ratio:.1f}%') +" + fi +} + +# CUDA benchmarks +benchmark_cuda() { + log_info "=== CUDA Benchmarks ===" + + # vectorAdd + run_bare_metal "vectorAdd" /usr/local/cuda/samples/1_Utilities/vectorAdd/vectorAdd + run_in_vm "vectorAdd" + compare_results "vectorAdd" + + # matrixMul + run_bare_metal "matrixMul" /usr/local/cuda/samples/0_Simple/matrixMul/matrixMul + run_in_vm "matrixMul" + compare_results "matrixMul" + + # deviceQuery (bandwidth) + run_bare_metal "deviceQuery" /usr/local/cuda/samples/1_Utilities/deviceQuery/deviceQuery + run_in_vm "deviceQuery" + compare_results "deviceQuery" + + # bandwidthTest + run_bare_metal "bandwidthTest" /usr/local/cuda/samples/1_Utilities/bandwidthTest/bandwidthTest + run_in_vm "bandwidthTest" + compare_results "bandwidthTest" +} + +# cuBLAS benchmarks +benchmark_cublas() { + log_info "=== cuBLAS Benchmarks ===" + run_bare_metal "cublas_sgemm" /usr/local/cuda/samples/7_CUDALibraries/simpleCUBLAS/simpleCUBLAS + run_in_vm "cublas_sgemm" + compare_results "cublas_sgemm" +} + +# Graphics benchmarks +benchmark_graphics() { + log_info "=== Graphics Benchmarks ===" + + # vkcube (frame time) + run_bare_metal "vkcube" vkcube --duration 10 --benchmark + run_in_vm "vkcube" + compare_results "vkcube" + + # glmark2 + run_bare_metal "glmark2" glmark2 --benchmark + run_in_vm "glmark2" + compare_results "glmark2" +} + +# Video benchmarks +benchmark_video() { + log_info "=== Video Benchmarks ===" + + # NVENC encode + run_bare_metal "nvenc_encode" ffmpeg -i test_1080p.yuv -c:v h264_nvenc -f null - + run_in_vm "nvenc_encode" + compare_results "nvenc_encode" + + # NVDEC decode + run_bare_metal "nvdec_decode" ffmpeg -i test_1080p.h264 -c:v h264_nvdec -f null - + run_in_vm "nvdec_decode" + compare_results "nvdec_decode" +} + +# PyTorch benchmarks +benchmark_pytorch() { + log_info "=== PyTorch Benchmarks ===" + + cat > /tmp/bench_pytorch.py <<'EOF' +import torch, time, json, sys +device = 'cuda' if torch.cuda.is_available() else 'cpu' +results = {} + +# Matmul benchmark +for size in [512, 1024, 2048, 4096]: + x = torch.randn(size, size, device=device) + y = torch.randn(size, size, device=device) + torch.cuda.synchronize() if device == 'cuda' else None + start = time.time() + for _ in range(10): + z = torch.mm(x, y) + torch.cuda.synchronize() if device == 'cuda' else None + elapsed = (time.time() - start) / 10 + gflops = 2 * size**3 / elapsed / 1e9 + results[f'matmul_{size}'] = {'time': elapsed, 'gflops': gflops} + print(f"Matmul {size}x{size}: {elapsed:.4f}s ({gflops:.1f} GFLOPS)") + +# ResNet-50 forward +import torchvision.models as models +model = models.resnet50().to(device) +model.eval() +x = torch.randn(32, 3, 224, 224).to(device) +torch.cuda.synchronize() if device == 'cuda' else None +start = time.time() +for _ in range(10): + with torch.no_grad(): + _ = model(x) +torch.cuda.synchronize() if device == 'cuda' else None +elapsed = (time.time() - start) / 10 +results['resnet50_forward'] = {'time': elapsed, 'fps': 32/elapsed} +print(f"ResNet-50 forward: {elapsed:.4f}s ({32/elapsed:.1f} FPS)") + +with open(sys.argv[1], 'w') as f: + json.dump(results, f, indent=2) +EOF + + run_bare_metal "pytorch" python3 /tmp/bench_pytorch.py + run_in_vm "pytorch" + compare_results "pytorch" +} + +# Generate summary report +generate_summary() { + log_info "Generating summary report..." + cat > "$RESULTS_DIR/summary.md" < 85 else '⚠️' if ratio > 70 else '❌' + print(f'| {test_name} / {k} | {bare[k]:.2f} | {vm[k]:.2f} | {ratio:.1f}% | {status} |') +" >> "$RESULTS_DIR/summary.md" + fi + done + + log_ok "Summary: $RESULTS_DIR/summary.md" +} + +main() { + case "${1:-all}" in + cuda) benchmark_cuda ;; + cublas) benchmark_cublas ;; + graphics) benchmark_graphics ;; + video) benchmark_video ;; + pytorch) benchmark_pytorch ;; + all) + benchmark_cuda + benchmark_cublas + benchmark_graphics + benchmark_video + benchmark_pytorch + ;; + *) echo "Usage: $0 {cuda|cublas|graphics|video|pytorch|all}"; exit 1 ;; + esac + generate_summary +} + +main "$@" \ No newline at end of file -- cgit v1.2.3