为啥 OpenGL 和 CUDA 上下文内存贪婪?

Posted

技术标签:

【中文标题】为啥 OpenGL 和 CUDA 上下文内存贪婪?【英文标题】:Why are OpenGL and CUDA contexts memory greedy?为什么 OpenGL 和 CUDA 上下文内存贪婪? 【发布时间】:2018-05-07 20:32:06 【问题描述】:

我开发的软件通常包括 OpenGL 和 Nvidia CUDA SDK。最近,我也开始寻找优化运行时内存占用的方法。我注意到以下情况(调试和发布版本仅相差 4-7 Mb):

应用程序启动 - 总共不到 1 Mb

OpenGL 4.5 上下文创建(+ GLEW 加载程序初始化)- 45 Mb 总计

CUDA 8.0 上下文(驱动程序 API)创建总共 114 Mb

如果我在“无头”模式下创建 OpenGL 上下文,GL 上下文会少用 3 Mb,这可能会用于默认帧缓冲区分配。这是有道理的,因为窗口大小是 640x360。

所以在 OpenGL 和 CUDA 上下文启动后,进程已经消耗 114 Mb

现在,对于在 GL 和 CUDA 上下文创建过程中发生的操作系统特定的东西,我没有深入的了解,但是 45 Mb 的 GL 和 68 的 CUDA 对我来说似乎很多。我知道通常有几兆字节用于系统帧缓冲区、函数指针(可能大部分分配发生在驱动程序端)。但是仅使用“空”上下文达到 100 Mb 以上看起来太多了。

我想知道:

    为什么 GL/CUDA 上下文创建会消耗如此大量的内存?

    有没有办法优化它?

被测系统设置: Windows 10 64 位。 NVIDIA GTX 960 GPU(驱动程序版本:388.31)。 8 Gb 内存。 Visual Studio 2015,64 位 C++ 控制台项目。

我使用 Visual Studio 内置的诊断工具 -> 进程内存部分测量内存消耗。

更新

按照 datenwolf 的建议,我尝试了 Process Explorer。这是我得到的截图,(我的过程在底部标有黄色):

我将不胜感激有关该信息的一些解释。我总是在“VS 诊断工具”窗口中查看“私人字节”。但在这里我还看到“工作集”、“WS Private”等。哪一个正确显示了我的进程当前使用了多少内存? 281,320K 看起来太多了,因为正如我上面所说,启动时的进程什么都不做,而是创建了 CUDA 和 OpenGL 上下文。

【问题讨论】:

您使用的是哪个 CUDA API,何时测量内存占用? 驱动程序 API。正如我所说,我在进程启动后使用诊断工具进行测量。 但是您在测量时是否将任何内容加载到上下文中? 不,这就是我称之为“空”上下文的原因 :) 在 GL 情况下,我只加载了 API 函数指针 (GLEW) @MichaelIV 1. 安装Process Explorer from Microsoft Technet 2. 在进程表中启动它后,右键单击表头 → 选择列 3. 在“进程内存”选项卡中选择“WS 可共享字节”并“WS 共享字节”(WS = 工作集) 4. 应用。您还可以为每个进程打开一个属性页,并在“性能”选项卡中查看共享了多少保留的工作集内存。 【参考方案1】:

部分回答:这是一个特定于操作系统的问题;在 Linux 上,CUDA 占用 9.3 MB。


我在 GNU/Linux 上使用 CUDA(不是 OpenGL):

CUDA 版本:10.2.89 操作系统发行版:Devuan GNU/Linux Beowulf(~= Debian Buster without systemd) 内核:Linux 5.2.0 处理器:英特尔 x86_64

为了检查 CUDA 在创建上下文时使用了多少内存,我运行了以下 C 程序(它还检查了上下文销毁后会发生什么):

#include <stdio.h>
#include <cuda.h>
#include <malloc.h>
#include <stdlib.h>

static void print_allocation_stats(const char* s)

    printf("%s:\n", s);
    printf("--------------------------------------------------\n");
    malloc_stats();
    printf("--------------------------------------------------\n\n");


int main()

    display_mallinfo("Initially");

    int status = cuInit(0);
    if (status != 0 )  return EXIT_FAILURE; 
    print_allocation_stats("After CUDA driver initialization");

    int device_id = 0;
    unsigned flags = 0;
    CUcontext context_id;
    status = cuCtxCreate(&context_id, flags, device_id);
    if (status != CUDA_SUCCESS )  return EXIT_FAILURE; 
    print_allocation_stats("After context creation");

    status = cuCtxDestroy(context_id);
    if (status != CUDA_SUCCESS )  return EXIT_FAILURE; 
    print_allocation_stats("After context destruction");
    return EXIT_SUCCESS;

(请注意,这使用了一个 glibc 特定的函数,而不是在标准库中。)

总结结果并剪掉不相关的部分:

Point in program Total bytes In-use Max MMAP Regions Max MMAP bytes
Initially 135168 1632 0 0
After CUDA driver initialization 552960 439120 2 307200
After context creation 9314304 6858208 8 6643712
After context destruction 7016448 580688 8 6643712

所以 CUDA 从 0.5 MB 开始,在分配上下文后占用 9.3 MB(在销毁上下文时会下降到 7.0 MB)。 9 MB 仍然是很多内存,因为没有做任何事情;但是 - 可能其中一些是全零、未初始化或写入时复制,在这种情况下,它真的不会占用那么多内存。

在 CUDA 8 和 CUDA 10 驱动程序发布之间的两年内,内存使用可能会显着提高,但我对此表示怀疑。所以 - 看起来你的问题是特定于 Windows 的。

另外,我应该提到我没有创建 OpenGL 上下文 - 这是 OP 问题的另一部分;所以我还没有估计需要多少内存。 OP 提出了总和是否大于其部分的问题,即如果还存在 OpenGL 上下文,CUDA 上下文是否会占用更多内存;相信不应该是这样,但欢迎读者尝试举报……

【讨论】:

您的应用程序只是文本,如果您打开一个窗口并创建一个 OpenGL 上下文,它将使用更多内存。我怀疑在您的情况下,Cuda 绕过了整个图形堆栈,而在 Widows 中它无法做到这一点。 @BrunoCoutinho:首先,我确实没有解决 OpenGL 上下文的问题,我会澄清这一点。但是 - 如果存在 OpenGL 上下文,CUDA 上下文不太可能占用更多内存。 CUDA 不是(直接)关于图形的,并且 CUDA 上下文可能会在您创建它时忘记您是否正在做一些图形操作。当然,Windows 可能会强制 CUDA 通过“图形堆栈”——我不知道,因为我不是 Windows 开发人员。 嗨@einpoklum。我专门谈论图形应用程序。例如,CUDA 上下文用于提供 OpenGL 和 NVIDIA Video Encoder API 之间的互操作。此外,也许从那时起驱动程序得到了优化。这个问题已经快 4 岁了。 @MichaelIV:我意识到这是一个老问题了,但是 - 我几天前才注意到它:-) 我还提到了 CUDA 8 和 10 之间驱动程序改进的可能性。跨度>

以上是关于为啥 OpenGL 和 CUDA 上下文内存贪婪?的主要内容,如果未能解决你的问题,请参考以下文章

CUDA/OpenGL InterOp:使用灰度图像作为纹理

为啥我没有使用 GLFW 获得向前兼容的 OpenGL 上下文?

CUDA:为啥会有大量的 GPU 空闲时间?

为啥 CUDA 内存复制速度表现得像这样,一些恒定的驱动程序开销?

两个进程可以共享相同的 GPU 内存吗? (CUDA)

CUDA 内核代码的设备内存:它是不是明确可管理?