为什么OpenGL和CUDA上下文需要占用大量内存?

4
我开发的软件通常包括OpenGL和Nvidia CUDA SDK。最近,我也开始寻找优化运行时内存占用的方法。我注意到以下情况(Debug和Release版本之间仅相差4-7 Mb):
应用程序启动 - 小于1 Mb总计
OpenGL 4.5上下文创建(+ GLEW加载程序初始化)- 45 Mb总计
CUDA 8.0上下文(Driver API)创建114 Mb总计。
如果我在“无头”模式下创建OpenGL上下文,则GL上下文使用3 Mb以下,这可能会分配给默认帧缓冲区分配。这是有道理的,因为窗口大小为640x360。
因此,在OpenGL和CUDA上下文启动后,进程已经消耗了114 Mb。
现在,我对GL和CUDA上下文创建时在操作系统特定方面所发生的事情并不了解,但对于GL和CUDA来说,45 Mb和68 Mb似乎太多了。我知道通常有几兆字节用于系统帧缓冲区、函数指针(可能大量分配发生在驱动器侧)。但仅使用“空”上下文超过100 Mb看起来太多了。
我想知道:
  1. 为什么GL/CUDA上下文创建会消耗如此大量的内存?

  2. 有没有优化的方法?

测试系统配置如下:

Windows 10 64位,NVIDIA GTX 960 GPU(驱动版本:388.31),8 GB RAM,Visual Studio 2015,64位C++控制台项目。

使用Visual Studio内置的诊断工具中的“进程内存”部分来测量内存使用情况。

更新:

根据datenwolf的建议,我尝试了Process Explorer。以下是我得到的截图(我的进程在底部,用黄色标记):

enter image description here

我希望能够对这些信息进行一些解释。我一直在查看“VS诊断工具”窗口中的“私有字节”。但是在这里,我还看到了“工作集”,“WS私有”等等。哪一个正确显示了我的进程当前使用的内存量?281,320K看起来太多了,因为如我所说,启动时该进程什么也不做,只是创建CUDA和OpenGL上下文。

@datenwolf,我猜向像你这样的Linux大佬询问在Windows上如何查看那些相对较大的资源分配部分是否实际上是进程独占的,可能是浪费时间。 ;) - Michael IV
2
@MichaelIV 1. 安装Microsoft Technet上的Process Explorer。2. 在进程表中启动后,右键单击表头→选择列。3. 在“进程内存”选项卡中选择“WS可共享字节”和“WS共享字节”(WS =工作集)。4. 应用。此外,您还可以为每个进程打开属性页面,在“性能”选项卡中查看保留的工作集内存有多少是共享的。 - datenwolf
@datenwolf 我在使用Process Explorer检查后添加了更多信息。希望能得到您的评论。谢谢。 - Michael IV
@einpoklum 好吧,这是一个老问题了。自那时以来,我转向使用Vulkan,它带有自己的驱动程序奇怪之处(例如在AWS服务器上的设备设置延迟)。我从未就此问题提交过错误报告。 - Michael IV
这部分内存可以是映射到GPU内存的内存。GLEW是否注册了任何纹理? - Bruno Coutinho
显示剩余9条评论
1个回答

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
  • 处理器:Intel 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 特定的函数,不在标准库中。)

总结结果并剪辑无关部分:

程序点 总字节数 正在使用 最大 MMAP 区域数 最大 MMAP 字节数
初始状态 135168 1632 0 0
CUDA 驱动程序初始化后 552960 439120 2 307200
上下文创建后 9314304 6858208 8 6643712
上下文销毁后 7016448 580688 8 6643712
所以CUDA从0.5 MB开始,分配上下文后占用9.3 MB(销毁上下文后回到7.0 MB)。9 MB的内存对于没有做任何事情来说仍然很多;但也许其中一些是全零、未初始化或写时复制,那么它实际上就不会占用那么多内存。
驱动程序发布的两年时间里,CUDA 8和CUDA 10之间可能内存使用有了显著改善,但我不太相信。因此,看起来你的问题是Windows特定的。
此外,我应该提到我没有创建OpenGL上下文 - 这是OP问题的另一个部分;因此,我没有估计它需要多少内存。OP提出了这样一个问题,即是否总和大于其部分,即如果同时存在CUDA上下文和OpenGL上下文,CUDA上下文是否会占用更多的内存;我认为这不应该是这种情况,但读者可以尝试并报告...

1
你的应用程序只有文本,如果你打开一个窗口并创建OpenGL上下文,它会使用更多的内存。我怀疑在你的情况下,Cuda绕过了整个图形堆栈,在Windows中它无法这样做。 - Bruno Coutinho
@BrunoCoutinho:首先,我确实没有回答关于OpenGL上下文的问题,我会澄清一下。但是-如果存在OpenGL上下文,则不太可能CUDA上下文占用更多内存。CUDA不(直接)涉及图形,而且创建CUDA上下文时,它很可能是无意识的-无论您是否正在进行图形处理。当然,Windows可能会强制CUDA通过“图形堆栈”运行-由于我不是Windows开发人员,所以我不知道。 - einpoklum
嗨@einpoklum。我特别是在谈论图形应用程序。例如,CUDA上下文用于提供OpenGL和NVIDIA视频编码器API之间的互操作性。此外,也许自那时以来驱动程序已经得到了优化。这个问题已经快4年了。 - Michael IV
@MichaelIV:我知道这是一个老问题了,但是-我只是几天前才注意到它 :-) 我也提到了CUDA 8和10之间驱动程序改进的可能性。 - einpoklum

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接