写入内存缓冲区时的性能损失(C ++)

时间:2015-02-02 20:38:29

标签: c++ memory memory-management buffer

我正在编写一个小型渲染器(基于光栅化算法)。这是我为测试不同技术而做的个人项目。我正在测量渲染一堆三角形所花费的时间,而在这样做时我发现了一些奇怪的东西。如果给定像素与2D三角形重叠并通过一些其他测试(它在缓冲区中写入该三角形的颜色),则程序执行的操作是写入图像缓冲区(Vec3ui的1D数组)。

Vec3<unsigned char> *fb = new Vec3<unsigned char>[w * h];
...
void rasterize(
    ...,
    Vec3<unsigned char> *&fb,
    float *&zbuffer)
{
    Vec3<unsigned char> randcol(drand48() * 255, drand48() * 255, drand48() * 255);
    ...
    uint32_t x, y;
    // loop over bounding box of triangle
    // check if given pixel is in triangle
    for (y = ymin, p.y = ymin; y <= ymax; ++y, ++p.y)
    {
        for (x = xmin, p.x = xmin; x <= xmax; ++x, ++p.x)
        {
            if (pixelOverTriangle(...) {
                fb[y * w + x] = randcol;
            }
        }
    }
}

在我测量统计数据时,我认为实际上需要花费最长时间才能渲染三角形,进行所有测试等等。当我运行具有给定数量的三角形的程序时,我会得到以下渲染时间:

74 ms

但是当我注释掉我写入图像缓冲区的行时,我得到了:

5 ms

所以要明确我这样做:

if (pixelOverTriangle(...) {
    // fb[y * w + x] = randcol;
}

事实上,超过90%的时间用于写入图像缓冲区!

我不得不说我尝试优化了如何计算用于访问数组中元素的索引,但这不是时间。时间实际上是将变量向右复制到缓冲区中(所以无论如何都是这样)。

我对这些数字感到非常惊讶。

所以我有几个问题:

  • 是否有望?
  • 我做错了吗?
  • 我可以做得更好吗?我可以用什么技术来优化它?

2 个答案:

答案 0 :(得分:2)

内存读/写比C ++看起来要多得多。通常,您的处理器会缓存内存块以便快速访问;这大大提高了连续内存中数据的性能:例如数组,结构和堆栈。但是,在尝试访问尚未缓存的内存(缓存未命中)时,处理器必须缓存新的内存块,这需要更长的时间(几分钟甚至几小时缩放到第二个长周期)。通过访问长内存块的任意段 - 就像您的图像一样 - 您几乎可以保证连续缓存未命中。

更糟糕的是,计算机内存(RAM)实际上位于虚拟页面上,这些虚拟页面一直在物理内存中交换。如果你的图像大到可以跨越多个内存页面(通常每个大约4kb),那么你的操作系统实际上是从二级存储(你的硬盘驱动器)加载和卸载数据,你可以想象它比从内存直接读取的时间长得多

我从另一个有关缓存性能的stackoverflow问题中找到an article,它可能比我更好地回答您的问题。实际上,了解内存读/写实际正在做什么以及如何能够显着影响性能是非常重要的。

答案 1 :(得分:1)

您可能需要查看的答案......

编译器可能会注意到您的代码什么都不做并删除它。查看函数的反汇编,看看它是否实际进行了任何计算。