From 4acc01020a345abfe0e12f3df59e5606d5a41b0a Mon Sep 17 00:00:00 2001 From: yummybomb <19238148+yummybomb@users.noreply.github.com> Date: Mon, 10 Aug 2026 16:12:47 +0000 Subject: [PATCH 1/2] Report conservative per-GPU vGPU profile capacity Counting every free VF advertising a type overreports concurrent capacity: sibling VFs share their parent GPU's framebuffer, so one 48Q assignment revokes the type from every other VF on that GPU. Bound each GPU's contribution by both its free VFs and how many times the profile framebuffer fits into the GPU's remaining framebuffer, using the largest still-creatable profile as a lower bound on what remains. --- lib/devices/vendor_vfio_linux.go | 51 ++- lib/devices/vendor_vfio_linux_test.go | 28 +- lib/oapi/oapi.go | 445 +++++++++++++------------- lib/resources/monitoring.go | 2 +- openapi.yaml | 2 +- 5 files changed, 293 insertions(+), 235 deletions(-) diff --git a/lib/devices/vendor_vfio_linux.go b/lib/devices/vendor_vfio_linux.go index ceab85ec..d67ddbc0 100644 --- a/lib/devices/vendor_vfio_linux.go +++ b/lib/devices/vendor_vfio_linux.go @@ -81,22 +81,37 @@ func (s vendorVFIOSysfs) discoverVFs() ([]VirtualFunction, error) { return vfs, nil } -// listProfiles counts each free VF advertising a type as one creatable -// instance, matching the driver-reported units that mdev sums through -// available_instances. This is a best-effort snapshot because creating on one -// VF may revoke the type from siblings that share its GPU framebuffer. +// listProfiles reports a conservative estimate of how many instances of each +// profile are concurrently creatable. Free VFs on the same GPU share its +// framebuffer, so counting every advertising VF overreports capacity: one 48Q +// assignment can revoke the type from all sibling VFs. Each GPU instead +// contributes min(free VFs advertising the type, remaining framebuffer / +// profile framebuffer), where the largest profile still creatable on the GPU +// is a lower bound on its remaining framebuffer. func (s vendorVFIOSysfs) listProfiles(vfs []VirtualFunction) ([]GPUProfile, error) { profilesByType := make(map[string]profileMetadata) - creatableVFs := make(map[string]int) + freeVFsByGPU := make(map[string]map[string]int) + remainingFBByGPU := make(map[string]int) for _, vf := range vfs { creatable, err := s.readCreatableProfiles(vf.PCIAddress) if err != nil { return nil, err } + gpu := vf.ParentGPU + if gpu == "" { + gpu = vf.PCIAddress + } for _, profile := range creatable { profilesByType[profile.TypeName] = profile - if !vf.Allocated { - creatableVFs[profile.TypeName]++ + if vf.Allocated { + continue + } + if freeVFsByGPU[gpu] == nil { + freeVFsByGPU[gpu] = make(map[string]int) + } + freeVFsByGPU[gpu][profile.TypeName]++ + if profile.FramebufferMB > remainingFBByGPU[gpu] { + remainingFBByGPU[gpu] = profile.FramebufferMB } } } @@ -109,15 +124,35 @@ func (s vendorVFIOSysfs) listProfiles(vfs []VirtualFunction) ([]GPUProfile, erro profiles := make([]GPUProfile, 0, len(metadata)) for _, profile := range metadata { + available := 0 + for gpu, freeVFs := range freeVFsByGPU { + available += gpuProfileCapacity(freeVFs[profile.TypeName], remainingFBByGPU[gpu], profile.FramebufferMB) + } profiles = append(profiles, GPUProfile{ Name: profile.Name, FramebufferMB: profile.FramebufferMB, - Available: creatableVFs[profile.TypeName], + Available: available, }) } return profiles, nil } +// gpuProfileCapacity estimates how many instances of a profile one GPU can +// still create concurrently. When a profile's framebuffer is unknown (0), the +// free VF count is the only signal available. +func gpuProfileCapacity(freeVFs, remainingFB, profileFB int) int { + if freeVFs == 0 { + return 0 + } + if profileFB <= 0 || remainingFB <= 0 { + return freeVFs + } + if byFB := remainingFB / profileFB; byFB < freeVFs { + return byFB + } + return freeVFs +} + func (s vendorVFIOSysfs) create(ctx context.Context, profileName, instanceID string) (*VGPUDevice, error) { vendorVFIOMu.Lock() defer vendorVFIOMu.Unlock() diff --git a/lib/devices/vendor_vfio_linux_test.go b/lib/devices/vendor_vfio_linux_test.go index 4555f5c2..b68a9f91 100644 --- a/lib/devices/vendor_vfio_linux_test.go +++ b/lib/devices/vendor_vfio_linux_test.go @@ -184,7 +184,7 @@ func TestVendorVFIODestroyRetainsAssignmentWhenOneVFIOPathIsMissing(t *testing.T } } -func TestVendorVFIOListProfilesCountsFreeVFs(t *testing.T) { +func TestVendorVFIOListProfilesReportsPerGPUCapacity(t *testing.T) { t.Parallel() sysfs := newTestVendorVFIOSysfs(t) @@ -196,8 +196,30 @@ func TestVendorVFIOListProfilesCountsFreeVFs(t *testing.T) { require.NoError(t, err) profiles, err := sysfs.listProfiles(vfs) require.NoError(t, err) - assert.Equal(t, 3, profileAvailability(profiles, "NVIDIA L40S-48Q"), - "each free VF advertising the type counts as one creatable instance") + assert.Equal(t, 2, profileAvailability(profiles, "NVIDIA L40S-48Q"), + "one 48Q consumes a whole GPU, so two GPUs mean two creatable instances despite three free VFs") + assert.Equal(t, 3, profileAvailability(profiles, "NVIDIA L40S-2Q"), + "small profiles stay capped by the free VF count") +} + +func TestVendorVFIOListProfilesCapsCapacityByRemainingFramebuffer(t *testing.T) { + t.Parallel() + + // One 48G GPU with a 24Q already assigned: siblings only advertise up to + // 24Q, so at most one more 24Q fits despite two free VFs. + remaining := "ID : vGPU Name\n1147 : NVIDIA L40S-1Q\n1153 : NVIDIA L40S-24Q\n" + sysfs := newTestVendorVFIOSysfs(t) + sysfs.addVF(t, "0000:82:00.0", "0000:82:00.4", "42", "1153", remaining) + sysfs.addVF(t, "0000:82:00.0", "0000:82:00.5", "43", "0", remaining) + sysfs.addVF(t, "0000:82:00.0", "0000:82:00.6", "44", "0", remaining) + + vfs, err := sysfs.discoverVFs() + require.NoError(t, err) + profiles, err := sysfs.listProfiles(vfs) + require.NoError(t, err) + assert.Equal(t, 1, profileAvailability(profiles, "NVIDIA L40S-24Q")) + assert.Equal(t, 2, profileAvailability(profiles, "NVIDIA L40S-1Q"), + "framebuffer allows more 1Q instances than free VFs, so the VF count caps it") } func TestVendorVFIOCreateReportsCapacityWhenAllGPUsFull(t *testing.T) { diff --git a/lib/oapi/oapi.go b/lib/oapi/oapi.go index 44930346..bd0f0453 100644 --- a/lib/oapi/oapi.go +++ b/lib/oapi/oapi.go @@ -833,7 +833,7 @@ type GPUConfig struct { // GPUProfile Available vGPU profile type GPUProfile struct { - // Available Number of virtual functions currently able to create this profile. Best-effort: creating an instance may reduce availability on sibling functions sharing GPU framebuffer. + // Available Conservative estimate of instances concurrently creatable with this profile across all GPUs, bounded per GPU by free virtual functions and remaining framebuffer. Best-effort: recomputed from driver state on each query. Available int `json:"available"` // FramebufferMb Frame buffer size in MB @@ -17703,227 +17703,228 @@ var swaggerSpec = []string{ "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", + "fvm/AQAA//9dup1U9LgBAA==", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/lib/resources/monitoring.go b/lib/resources/monitoring.go index dc6992a2..1aef5a2b 100644 --- a/lib/resources/monitoring.go +++ b/lib/resources/monitoring.go @@ -203,7 +203,7 @@ func newMonitoringMetrics(meter metric.Meter, mgr *Manager) error { gpuProfileSlots, err := meter.Int64ObservableGauge( "hypeman_resources_gpu_profile_slots", - metric.WithDescription("Virtual functions able to create each vGPU profile (best-effort snapshot)"), + metric.WithDescription("Estimated concurrently creatable instances per vGPU profile (best-effort snapshot)"), ) if err != nil { return err diff --git a/openapi.yaml b/openapi.yaml index 23ec8574..4e2e34f0 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -1566,7 +1566,7 @@ components: example: 1024 available: type: integer - description: "Number of virtual functions currently able to create this profile. Best-effort: creating an instance may reduce availability on sibling functions sharing GPU framebuffer." + description: "Conservative estimate of instances concurrently creatable with this profile across all GPUs, bounded per GPU by free virtual functions and remaining framebuffer. Best-effort: recomputed from driver state on each query." example: 59 PassthroughDevice: From bfbcedc71f94478751dd0e3ebb3a80f45c4347a2 Mon Sep 17 00:00:00 2001 From: yummybomb <19238148+yummybomb@users.noreply.github.com> Date: Mon, 10 Aug 2026 16:12:47 +0000 Subject: [PATCH 2/2] Preserve the create failure cause in vGPU cleanup errors The vgpu_cleanup_pending response replaced the original create error with cleanup guidance, leaving the cause only in server logs. Prefix the message with the wrapped error so callers see why creation failed as well as how to recover. --- cmd/api/api/instances.go | 4 ++-- cmd/api/api/instances_test.go | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/cmd/api/api/instances.go b/cmd/api/api/instances.go index 89c927a6..9b259035 100644 --- a/cmd/api/api/instances.go +++ b/cmd/api/api/instances.go @@ -349,10 +349,10 @@ func (s *ApiService) CreateInstance(ctx context.Context, request oapi.CreateInst // errors.Is case would match the cause and hide the pending vGPU cleanup. case errors.As(err, &vgpuPending): log.ErrorContext(ctx, "failed to create instance", "error", err, "image", request.Body.Image) - message := fmt.Sprintf("failed to create instance; vGPU release failed during rollback and instance %s retains the assignment, delete it to retry", vgpuPending.InstanceID) + message := fmt.Sprintf("failed to create instance: %v; vGPU release failed during rollback and instance %s retains the assignment, delete it to retry", vgpuPending.Err, vgpuPending.InstanceID) innerCode := "vgpu_retained_instance" if !vgpuPending.Retained { - message = fmt.Sprintf("failed to create instance; vGPU release failed during rollback and the retention record for instance %s could not be saved; the assignment is recovered on the next startup reconcile", vgpuPending.InstanceID) + message = fmt.Sprintf("failed to create instance: %v; vGPU release failed during rollback and the retention record for instance %s could not be saved; the assignment is recovered on the next startup reconcile", vgpuPending.Err, vgpuPending.InstanceID) innerCode = "vgpu_unretained_instance" } return oapi.CreateInstance500JSONResponse{ diff --git a/cmd/api/api/instances_test.go b/cmd/api/api/instances_test.go index 848661ed..c4138cf6 100644 --- a/cmd/api/api/instances_test.go +++ b/cmd/api/api/instances_test.go @@ -76,6 +76,8 @@ func TestCreateInstance_VGPUCleanupPendingBeatsWrappedErrorMapping(t *testing.T) require.True(t, ok, "expected 500 vgpu_cleanup_pending, got %T", resp) assert.EqualValues(t, "vgpu_cleanup_pending", pending.Code) assert.Contains(t, pending.Message, "inst-1") + assert.Contains(t, pending.Message, network.ErrNameExists.Error(), + "the underlying create failure must survive the cleanup guidance") assert.Contains(t, pending.Message, "delete it to retry") require.NotNil(t, pending.InnerError) require.NotNil(t, pending.InnerError.Code) @@ -101,6 +103,8 @@ func TestCreateInstance_VGPUCleanupPendingWithoutRetentionUsesReconcileGuidance( require.True(t, ok, "expected 500 vgpu_cleanup_pending, got %T", resp) assert.EqualValues(t, "vgpu_cleanup_pending", pending.Code) assert.Contains(t, pending.Message, "retention record for instance inst-1 could not be saved") + assert.Contains(t, pending.Message, network.ErrNameExists.Error(), + "the underlying create failure must survive the cleanup guidance") assert.Contains(t, pending.Message, "startup reconcile") assert.NotContains(t, pending.Message, "delete") require.NotNil(t, pending.InnerError)