Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nvapi-gpu: Add NvAPI_GPU_GetMemoryInfo/Ex #198

Merged
merged 6 commits into from
Aug 17, 2024
Merged

nvapi-gpu: Add NvAPI_GPU_GetMemoryInfo/Ex #198

merged 6 commits into from
Aug 17, 2024

Conversation

jp7677
Copy link
Owner

@jp7677 jp7677 commented Aug 14, 2024

TODO:

  • Look at the currently unknown fields
  • Tests

Closes #197

@jp7677
Copy link
Owner Author

jp7677 commented Aug 14, 2024

cc @SveSop since you are the original author.

@SveSop
Copy link
Contributor

SveSop commented Aug 15, 2024

Does not seem like an obvious way to get available memory, although it should be doable i would think. Maybe if DXVK has "used" memory and just a simple calculation.
memory.m_type->heap->stats.memoryUsed in DXVK? Not sure how this is "exposed" to DXVK-NVAPI in any way tho.. And it does not really seem to be distinguishing dedicated vs shared i suppose.

@Saancreed
Copy link
Collaborator

Isn't available memory pretty much the same thing as Budget that's returned from IDXGIAdapter3::QueryVideoMemoryInfo?

Comment on lines 408 to 441
case NV_DISPLAY_DRIVER_MEMORY_INFO_VER_1: {
auto pMemoryInfoV1 = reinterpret_cast<NV_DISPLAY_DRIVER_MEMORY_INFO_V1*>(pMemoryInfo);
pMemoryInfoV1->dedicatedVideoMemory = adapter->GetVRamSize();
pMemoryInfoV1->availableDedicatedVideoMemory = 0; // Not found in DXVK
pMemoryInfoV1->systemVideoMemory = adapter->GetDedicatedSystemRamSize();
pMemoryInfoV1->sharedSystemMemory = adapter->GetSharedSystemRamSize();
break;
}
case NV_DISPLAY_DRIVER_MEMORY_INFO_VER_2: {
auto pMemoryInfoV2 = reinterpret_cast<NV_DISPLAY_DRIVER_MEMORY_INFO_V2*>(pMemoryInfo);
pMemoryInfoV2->dedicatedVideoMemory = adapter->GetVRamSize();
pMemoryInfoV2->availableDedicatedVideoMemory = 0; // Not found in DXVK
pMemoryInfoV2->systemVideoMemory = adapter->GetDedicatedSystemRamSize();
pMemoryInfoV2->sharedSystemMemory = adapter->GetSharedSystemRamSize();
pMemoryInfoV2->curAvailableDedicatedVideoMemory = 0; // Not found in DXVK
break;
}
case NV_DISPLAY_DRIVER_MEMORY_INFO_VER_3: {
auto pMemoryInfoV3 = reinterpret_cast<NV_DISPLAY_DRIVER_MEMORY_INFO_V3*>(pMemoryInfo);
pMemoryInfoV3->dedicatedVideoMemory = adapter->GetVRamSize();
pMemoryInfoV3->availableDedicatedVideoMemory = 0; // Not found in DXVK
pMemoryInfoV3->systemVideoMemory = adapter->GetDedicatedSystemRamSize();
pMemoryInfoV3->sharedSystemMemory = adapter->GetSharedSystemRamSize();
pMemoryInfoV3->curAvailableDedicatedVideoMemory = 0; // Not found in DXVK
pMemoryInfoV3->dedicatedVideoMemoryEvictionsSize = 0;
pMemoryInfoV3->dedicatedVideoMemoryEvictionCount = 0;
break;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder, can we just use the given pointer as-it without reinterpret-casting it? I think it should be possible because the offset of each member appears to be the same in every struct version in which it's present. That should allow us to make this a bit more DRY, if you don't mind some classic switch fallthrough:

Suggested change
case NV_DISPLAY_DRIVER_MEMORY_INFO_VER_1: {
auto pMemoryInfoV1 = reinterpret_cast<NV_DISPLAY_DRIVER_MEMORY_INFO_V1*>(pMemoryInfo);
pMemoryInfoV1->dedicatedVideoMemory = adapter->GetVRamSize();
pMemoryInfoV1->availableDedicatedVideoMemory = 0; // Not found in DXVK
pMemoryInfoV1->systemVideoMemory = adapter->GetDedicatedSystemRamSize();
pMemoryInfoV1->sharedSystemMemory = adapter->GetSharedSystemRamSize();
break;
}
case NV_DISPLAY_DRIVER_MEMORY_INFO_VER_2: {
auto pMemoryInfoV2 = reinterpret_cast<NV_DISPLAY_DRIVER_MEMORY_INFO_V2*>(pMemoryInfo);
pMemoryInfoV2->dedicatedVideoMemory = adapter->GetVRamSize();
pMemoryInfoV2->availableDedicatedVideoMemory = 0; // Not found in DXVK
pMemoryInfoV2->systemVideoMemory = adapter->GetDedicatedSystemRamSize();
pMemoryInfoV2->sharedSystemMemory = adapter->GetSharedSystemRamSize();
pMemoryInfoV2->curAvailableDedicatedVideoMemory = 0; // Not found in DXVK
break;
}
case NV_DISPLAY_DRIVER_MEMORY_INFO_VER_3: {
auto pMemoryInfoV3 = reinterpret_cast<NV_DISPLAY_DRIVER_MEMORY_INFO_V3*>(pMemoryInfo);
pMemoryInfoV3->dedicatedVideoMemory = adapter->GetVRamSize();
pMemoryInfoV3->availableDedicatedVideoMemory = 0; // Not found in DXVK
pMemoryInfoV3->systemVideoMemory = adapter->GetDedicatedSystemRamSize();
pMemoryInfoV3->sharedSystemMemory = adapter->GetSharedSystemRamSize();
pMemoryInfoV3->curAvailableDedicatedVideoMemory = 0; // Not found in DXVK
pMemoryInfoV3->dedicatedVideoMemoryEvictionsSize = 0;
pMemoryInfoV3->dedicatedVideoMemoryEvictionCount = 0;
break;
}
case NV_DISPLAY_DRIVER_MEMORY_INFO_VER_3:
pMemoryInfo->dedicatedVideoMemoryEvictionsSize = 0;
pMemoryInfo->dedicatedVideoMemoryEvictionCount = 0;
[[fallthrough]];
case NV_DISPLAY_DRIVER_MEMORY_INFO_VER_2:
pMemoryInfo->curAvailableDedicatedVideoMemory = …;
[[fallthrough]];
case NV_DISPLAY_DRIVER_MEMORY_INFO_VER_1:
pMemoryInfo->dedicatedVideoMemory = adapter->GetVRamSize();
pMemoryInfo->availableDedicatedVideoMemory = …;
pMemoryInfo->systemVideoMemory = adapter->GetDedicatedSystemRamSize();
pMemoryInfo->sharedSystemMemory = adapter->GetSharedSystemRamSize();
break;

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, this looks cool, we should probably do this for other places too.

@jp7677
Copy link
Owner Author

jp7677 commented Aug 15, 2024

Isn't available memory pretty much the same thing as Budget that's returned from IDXGIAdapter3::QueryVideoMemoryInfo?

See last WIP commit, I'm also thinking/playing in that direction, with thanks to @SveSop for his hint this morning.

The unit tests are currently broken, but the [@system] tests do work and print some numbers. Doesn't look that bad actually..

@@ -48,17 +58,19 @@ namespace dxvk {
private:
Vulkan& m_vulkan;
Nvml& m_nvml;
Com<IDXGIAdapter3> m_dxgiAdapter;
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess no way around to keep an adapter alive. I hope this won't give us tear down issues in titles.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless adapters are singletons (which I don't think they are) it should be fine. But if it proves to be a problem we can always try switching to manual usage of VK_EXT_memory_budget on our own.

pMemoryInfoV2->availableDedicatedVideoMemory = adapter->GetVideoMemory().Budget;
pMemoryInfoV2->systemVideoMemory = adapter->GetVideoMemory().DedicatedSystemMemory;
pMemoryInfoV2->sharedSystemMemory = adapter->GetVideoMemory().SharedSystemMemory;
pMemoryInfoV2->curAvailableDedicatedVideoMemory = adapter->GetVideoMemory().Budget - adapter->GetVideoMemory().CurrentUsage;
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about this one. The others seem to roughly match.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do I understand correctly that:

  • dedicatedVideoMemory is simply the total size of device-local heap and should probably never change,
  • availableDedicatedVideoMemory is how much of above is left for the application to allocate, so dedicatedVideoMemory reduced by other application's allocations and areas reserved for private use by the driver, if any (and current application allocating memory shouldn't affect this),
  • curAvailableDedicatedVideoMemory is how much of above is left for the application to allocate after we include allocations it already made, so availableDedicatedVideoMemory reduced by application's own allocated memory size?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is indeed more or less how I understood the terminology, based on the nvapi headers and @SveSop 's numbers:

    NvU64   dedicatedVideoMemory;              //!< Size(in bytes) of the physical framebuffer. Refers to the dedicated video memory on discrete GPUs.
                                               //!  It is more performant for GPU operations than the reserved systemVideoMemory.
    NvU64   availableDedicatedVideoMemory;     //!< Size(in bytes) of the available physical framebuffer for allocating video memory surfaces.
    NvU64   systemVideoMemory;                 //!< Size(in bytes) of system memory the driver allocates at load time. It is a substitute for dedicated video memory.
                                               //!< Typically used with integrated GPUs that do not have dedicated video memory.
    NvU64   sharedSystemMemory;                //!< Size(in bytes) of shared system memory that driver is allowed to commit for surfaces across all allocations.
                                               //!< On discrete GPUs, it is used to utilize system memory for various operations. It does not need to be reserved during boot.
                                               //!< It may be used by both GPU and CPU, and has an �on-demand� type of usage.
    NvU64   curAvailableDedicatedVideoMemory;  //!< Size(in bytes) of the current available physical framebuffer for allocating video memory surfaces. 

Co-authored-by: Sveinar Søpler <cybermax@dexter.no>
src/sysinfo/nvapi_adapter.h Outdated Show resolved Hide resolved
src/sysinfo/nvapi_adapter.h Outdated Show resolved Hide resolved
@@ -48,17 +58,19 @@ namespace dxvk {
private:
Vulkan& m_vulkan;
Nvml& m_nvml;
Com<IDXGIAdapter3> m_dxgiAdapter;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless adapters are singletons (which I don't think they are) it should be fine. But if it proves to be a problem we can always try switching to manual usage of VK_EXT_memory_budget on our own.

pMemoryInfoV2->availableDedicatedVideoMemory = adapter->GetVideoMemory().Budget;
pMemoryInfoV2->systemVideoMemory = adapter->GetVideoMemory().DedicatedSystemMemory;
pMemoryInfoV2->sharedSystemMemory = adapter->GetVideoMemory().SharedSystemMemory;
pMemoryInfoV2->curAvailableDedicatedVideoMemory = adapter->GetVideoMemory().Budget - adapter->GetVideoMemory().CurrentUsage;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do I understand correctly that:

  • dedicatedVideoMemory is simply the total size of device-local heap and should probably never change,
  • availableDedicatedVideoMemory is how much of above is left for the application to allocate, so dedicatedVideoMemory reduced by other application's allocations and areas reserved for private use by the driver, if any (and current application allocating memory shouldn't affect this),
  • curAvailableDedicatedVideoMemory is how much of above is left for the application to allocate after we include allocations it already made, so availableDedicatedVideoMemory reduced by application's own allocated memory size?

@SveSop
Copy link
Contributor

SveSop commented Aug 15, 2024

@Saancreed DedicatedVideoMemory is total vram - eg. 8192MB or whatnot
availableDedicatedVideoMemory seemed to be DedicatedvideoMemory - some pre-allocation that did not seem to change on windows no matter what load/app was running. It was around 2%, so 300'ish MB on my 16GB card, and 200'ish MB on my 8GB card.
curAvailableDedicatedVideoMemory is the actual remaining.. so if you have some app using 2GB of video memory on a 8GB card, it would be 6GB. Would possibly like to verify this somehow if it would be DedicatedVideoMemory - usage, or availableDedicatedVideoMemory - usage...

@SveSop
Copy link
Contributor

SveSop commented Aug 15, 2024

Me thinks the calculation of availableDedicatedVideoMemory is not overly correct, as that goes down when video memory is used when testing with wine... On Windows it does not.

Then again, dedicatedVideoMemory is also calculated wrong, as it seems to overshoot a couple of hundred MB's

On windows i get on my 2070 8GB card: 8192MB, but using dxvk-nvapi i get 8438MB.
It more or less seem like it is "actual" physical vram + this pre-allocated bit i talked about earlier.. so instead of 8192, it is 8192 + 2%... Could be coincidence + that i have no idea if this "pre-allocated" bit is exactly the same - if at all - when using Linux.

Might be some method that DXVK calculates this as it might be adding some extra "heap" stuff-whatever? (Safeguards or whatnot)

I have a small test proggy i have compiled that runs some nvapi tests that i attach.
nvapi_test.zip

@Saancreed
Copy link
Collaborator

Thanks for the explanation @SveSop. Interestingly, for me nvapi system tests print

    GPU 0
    GPU name:                   NVIDIA GeForce RTX 4080 Laptop GPU
    GPU type:                   2 (Discrete)
    Device ID:                  0x27e010de
    Subsystem ID:               0x21ed1043
    Bus:Slot ID:                PCI:01:00
    Board ID:                   0x100
    Dedicated video memory:     12282MB
    Available dedicated v.m.:   11898MB
    System video memory:        0MB
    Shared system memory:       47937MB
    Cur. avail. dedicated v.m.: 11898MB

so dedicated video memory matches exactly. This also matches how Vulkan memory heaps are reported, which afaik is what DXVK sums up when reporting memory budget info:

memoryHeaps: count = 2
        memoryHeaps[0]:
                size   = 12878610432 (0x2ffa00000) (11.99 GiB)
                budget = 12476612608 (0x2e7aa0000) (11.62 GiB)
                usage  = 0 (0x00000000) (0.00 B)
                flags: count = 1
                        MEMORY_HEAP_DEVICE_LOCAL_BIT
        memoryHeaps[1]:
                size   = 50266269696 (0xbb41a6800) (46.81 GiB)
                budget = 50266269696 (0xbb41a6800) (46.81 GiB)
                usage  = 0 (0x00000000) (0.00 B)
                flags:
                        None

As another data point, nvidia-smi reports 6MiB / 12282MiB when no processes are running and NVML's nvmlDeviceGetMemoryInfo_v2 reports:

Total: 12878610432, in MiB: 12282
Reserved: 396034048, in MiB: 377.688
Free: 12476612608, in MiB: 11898.6
Used: 5963776, in MiB: 5.6875

So yeah, there is ~378 MiB of VRAM that's reserved for the driver and GPU firmware which we should probably subtract from dedicatedVideoMemory when calculating availableDedicatedVideoMemory but I'm not sure if we can get that number outside of NVML.

@SveSop
Copy link
Contributor

SveSop commented Aug 16, 2024

Unless it is too inconvenient we could use nvml for this, and just use dedicatedVideoMemory = availableDedicatedVideoMemory if nvml is not available? Would not be available for 32-bit, but atleast having nvml available would be some more accuracy as it is in other places aswell?

@jp7677
Copy link
Owner Author

jp7677 commented Aug 16, 2024

I'm reaching the same conclusion. What we have now is:

pMemoryInfoV1->dedicatedVideoMemory = vidMemInfo.DedicatedVideoMemory;
pMemoryInfoV1->systemVideoMemory = vidMemInfo.DedicatedSystemMemory;
pMemoryInfoV1->sharedSystemMemory = vidMemInfo.SharedSystemMemory;
pMemoryInfoV1->availableDedicatedVideoMemory = curVidMemInfo.Budget;
pMemoryInfoV1->curAvailableDedicatedVideoMemory = curVidMemInfo.Budget - curVidMemInfo.CurrentUsage;

but what we actually want to have is:

...
pMemoryInfoV1->availableDedicatedVideoMemory = vidMemInfo.DedicatedVideoMemory - vidMemInfo.Reseverd;
...

But since we don't have vidMemInfo.Reseverd without NVML I guess

...
pMemoryInfoV1->availableDedicatedVideoMemory = vidMemInfo.DedicatedVideoMemory;
...

is indeed the best we can do (that is, without NVML). That way we have a stable number, but we are also overshooting.

Just blindly subtracting 2% from DedicatedVideoMemory crossed my mind, but not sure if that is a good idea, probably not.

@jp7677 jp7677 marked this pull request as ready for review August 16, 2024 16:22
@jp7677
Copy link
Owner Author

jp7677 commented Aug 16, 2024

I suggest to create two follow up issues for picking up after this PR:

@jp7677
Copy link
Owner Author

jp7677 commented Aug 16, 2024

PS: Still not completely sure if it should be

pMemoryInfoV1->curAvailableDedicatedVideoMemory = curVidMemInfo.Budget - curVidMemInfo.CurrentUsage;

or

pMemoryInfoV1->curAvailableDedicatedVideoMemory = curVidMemInfo.Budget;

So, does curAvailableDedicatedVideoMemory includes (like Budget) the apps own allocations or not.

Copy link
Collaborator

@Saancreed Saancreed left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One comment and we should really check if we should subtract usage from budget because I would guess we shouldn't but otherwise LGTM.

src/sysinfo/nvapi_adapter.cpp Show resolved Hide resolved
@jp7677
Copy link
Owner Author

jp7677 commented Aug 17, 2024

we should subtract usage from budget because I would guess we shouldn't but otherwise LGTM.

Yes, sleeping a night over it, I also think that we should not. This would also better fit terminology since availableDedicatedVideoMemory also does not includes application usage.

@jp7677 jp7677 merged commit bda44be into master Aug 17, 2024
2 checks passed
@jp7677 jp7677 deleted the get-memory-info branch August 20, 2024 16:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add NvAPI_GPU_GetMemoryInfo
3 participants