2

我记得在某处听到“大型函数可能具有更高的执行时间”,因为代码大小、CPU 缓存或类似的东西。

如何判断函数大小是否对我的应用程序造成了性能影响?我该如何优化呢?我有一个 CPU 密集型计算,我已经分成(与 CPU 内核一样多的线程)。主线程一直等到所有工作线程都完成后再继续。

我碰巧在 Visual Studio 2010 上使用 C++,但我不确定这是否真的很重要。

编辑:

我正在运行一个光线追踪器,它每像素发射大约 5,000 条光线。我创建 (cores-1) 个线程(每个额外内核 1 个),将屏幕分成几行,并将每一行分配给一个 CPU 线程。我trace在每个线程上运行该函数每个像素大约 5,000 次。

我实际上正在寻找加快速度的方法。 我可以通过重构来减小主跟踪函数的大小,我想知道我是否应该期望看到性能提升。

很多人似乎在这里回答了错误的问题,我正在寻找这个特定问题的答案,即使你认为我可以通过优化函数的内容做得更好,我想知道是否有功能大小/性能关系。

4

4 回答 4

5

这并不是函数的大小,而是运行时被缓存的代码的总大小。您不会通过将代码拆分为更多较小的函数来加快速度,除非其中一些函数根本没有在您的关键代码路径中调用,因此不需要占用任何缓存。此外,如果编译器决定内联它们,您将代码拆分为多个函数的任何尝试都可能被编译器反转。

因此,实际上不可能说您当前的代码是否“影响性能”。与您可以以不同方式构建代码的众多方式中的哪一种相比,这是一个成功吗?而且你不能合理地期望这种变化会对性能产生任何特别的影响。

我想您正在寻找的是很少执行的指令(您的分析器会告诉您它们是什么),但位于执行很多指令的附近(因此需要在缓存中很多,并将在它们周围拉入缓存线)。如果您可以将经常执行的代码聚集​​在一起,您将从指令缓存中获得更多收益。

但实际上,这并不是一条非常富有成效的优化路线。你不太可能有很大的不同。如果不出意外,您通常执行的代码可能已经非常小并且已经相邻,它会在某个地方有一些紧密的循环(您的分析器会告诉您在哪里)。最低级别的缓存线通常很小(大约 32 或 64 字节),因此您需要对代码进行一些非常精细的重新排列。C++ 在你和目标代码之间放置了很多东西,这阻碍了在内存中仔细放置指令。

诸如此类的工具perf可以为您提供有关缓存未命中的信息-其中大多数不适用于可执行代码,但在大多数系统上,您要避免哪些缓存未命中并不重要:如果您可以避免一些,那么您将加快您的速度码起来。也许不是很多,除非有很多失误,但有一些。

不管怎样,你是在什么背景下听到的?我听到的最常见的一种说法是,函数内联有时会适得其反,因为有时代码膨胀的开销大于避免的函数调用开销。我不确定,但如果您的编译器支持,配置文件引导的优化可能会有所帮助。一个相当合理的配置文件引导优化是优先在执行次数较多的调用站点内联,使较冷的代码更小,首先加载和修复的开销更少,并且(希望)对指令的破坏性更小当它被拉入时缓存。比我更了解编译器的人会认真考虑这是否是一个好的profile-guided optimization,因此决定是否实现它。

于 2012-06-12T15:21:41.643 回答
3

除非您要手动调整到汇编级别,以包括锁定缓存中的特定代码行,否则您不会看到一个大函数和多个小函数之间的显着执行差异。在这两种情况下,您仍然需要执行相同数量的工作,这将成为您的瓶颈。

然而,将事物分解成多个较小的函数会更容易维护和阅读——尤其是在 6 个月后,当你忘记了你最初做了什么的时候。

于 2012-06-12T15:19:06.653 回答
0

函数大小不太可能成为应用程序的瓶颈。你在函数中所做的比它的物理尺寸更重要。有些事情你的编译器可以用小函数做它不能用大函数做的事情(即内联),但通常这不是一个很大的区别。

您可以分析代码以查看真正的瓶颈在哪里。我怀疑调用一个大函数不是问题。

但是,出于代码可读性的原因,您应该将函数分解为更小的函数。

于 2012-06-12T15:18:02.493 回答
-1

这实际上与函数大小无关,而与您在其中所做的事情有关。根据您的工作,可能有一些方法可以优化它。

于 2012-06-12T15:19:03.450 回答