summaryrefslogtreecommitdiffstats
path: root/tools/benchmark_infrastructure.sh
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-14 06:43:11 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-14 06:43:11 -0400
commit5dd8165f1754e156a0f9fb16c7a6bfa90e99ed60 (patch)
tree7523e29d8044d4d5b6dcd7c1c888a3491137fcd1 /tools/benchmark_infrastructure.sh
parent9a7263fce4e3156349a526631805fce66b87fb1b (diff)
downloadopen-iov-5dd8165f1754e156a0f9fb16c7a6bfa90e99ed60.tar.gz
open-iov-5dd8165f1754e156a0f9fb16c7a6bfa90e99ed60.zip
VFIO device registration fix + IOMMUFD callbacks + VFIO ioctl handlers
- Removed IOMMU group addition before vfio_register_emulated_iommu_dev() in nv_vgpu_mdev_create() - Added IOMMUFD callbacks (bind_iommufd, unbind_iommufd, attach_ioas, detach_ioas) using kernel's vfio_iommufd_emulated_* functions - Implemented VFIO ioctl handlers: GET_INFO, GET_REGION_INFO, GET_IRQ_INFO, SET_IRQS, MMAP - Added config space read/write handlers at offset 0x70000000000 - Mmap handler for config space, BAR0 (emulation shadow), BAR1-5 (physical VRAM/registers) - Interrupt handler for VFIO_DEVICE_SET_IRQS (DATA_EVENTFD, DATA_NONE, DATA_BOOL) - Added udev rules for vfio group permissions - Created stack_manager.sh unified tool - Fixed mdev remove crash with deferred cleanup in vfio_device_release callback - Kernel 6.8+ IOMMUFD compatibility - QEMU launches successfully with vGPU passthrough
Diffstat (limited to 'tools/benchmark_infrastructure.sh')
-rwxr-xr-xtools/benchmark_infrastructure.sh217
1 files changed, 217 insertions, 0 deletions
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" <<EOF
+# GSP Emulation Benchmark Summary
+Date: $(date)
+Host: $(hostname)
+Kernel: $(uname -r)
+
+## Results
+
+| Test | Bare Metal | VM | Ratio | Status |
+|------|------------|-----|-------|--------|
+EOF
+
+ for f in "$RESULTS_DIR"/bare_metal_*.json; do
+ test_name=$(basename "$f" .json | sed 's/bare_metal_//')
+ vm_f="$RESULTS_DIR/vm_${test_name}.json"
+ if [[ -f "$vm_f" ]]; then
+ python3 -c "
+import json
+with open('$f') as bf: bare = json.load(bf)
+with open('$vm_f') as vf: vm = json.load(vf)
+for k in bare:
+ if k in vm and isinstance(bare[k], (int, float)):
+ ratio = vm[k] / bare[k] * 100
+ status = '✅' if ratio > 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