在C,并使用静态变量的函数使其更快?
-
26-09-2019 - |
题
我的函数将被调用数千次。如果我想,使其更快,会改变局部函数变量静态有什么用处?我这背后的逻辑是,由于静态变量的函数调用之间持久的,他们被分配只在第一次,因此,每个后续调用不会为他们分配内存,并会变得更快,因为内存分配步骤尚未完成。
另外,如果上面的是真实的,那么将使用全局变量的替代参数来更快地每次被调用时,将信息传递给功能?我觉得对于参数的空间也被分配在每个函数调用,以允许递归(这就是为什么递归使用更多内存),但由于我的函数不是递归的,如果我的推论是正确的,那么起飞参数将在理论上化妆它更快。
我知道这些事情我想要做的是可怕的编程习惯,但请告诉我,如果它是明智的。我打算无论如何要尝试,但请给我你的意见。
解决方案
局部变量的开销是零。每次调用函数的时候,你已经设置栈的参数,返回值等。添加局部变量的手段,你要添加一个稍微大一点的数堆栈指针(这是在编译时计算出的数字)
此外,局部变量可能更快,因为缓存位置。
如果你只是打电话的时候你的函数“千”(没有百万或数十亿),那么你应该看着你的算法优化机会的之后的你已经运行探查。
回复:缓存局部性(读更多这里): 经常访问的全局变量可能有时间局部性。他们也可能被复制到功能执行期间寄存器,但会写一个函数返回后放回内存(缓存)(否则他们不会是别的访问;寄存器没有地址)。
局部变量通常将具有时间和空间局部性(他们得到凭借在堆栈上被创建的)。此外,它们可以被“分配”直接寄存器和永远不会被写入存储器。
其他提示
要找出最好的方法是实际运行探查。这可以简单到执行使用这两种方法的若干定时测试,然后平均化的结果和比较,或者可以考虑一个全面的分析工具,其本身附着到处理和图形出存储器使用随着时间的推移和执行速度。
不要因为你有预感这将是更快地执行随机的微码调整。编译器都拥有的东西稍有不同的实现,什么是对一个环境中的一个真正的编译器可能是在另一个配置错误。
要解决约更少的参数该评论:的“内联”的功能的过程中基本上消除有关调用函数的开销。机会是一个小功能会自动在林立的编译器,但你可以的提供一个功能,以及被内联。
在不同的语言,C ++,新标准出来支撑完美转发,并用rvalue引用完美移动语义,其消除了在某些情况下的临时这可以减少调用一个函数的成本的需要。
我怀疑你过早优化然而,你不应该这样关心性能,直到你已经发现了真正的瓶颈。
是绝对不!唯一的“性能”的区别是当变量被初始化
int anint = 42;
vs
static int anint = 42;
在第一种情况下的整数会在每个函数被调用在加载程序时OT将被设置为42的情况下,第二时间设定为42。
然而的差是如此的琐碎,几乎看不noticable。它是一种常见的误解是存储有被分配给在每次调用“自动”变量。这不是那么C使用已经分配的空间在堆栈这些变量。
静态变量实际上可能你慢下来,因为它的一些aggresive的优化是不可能的静态变量。另外,作为当地人都在栈中的一个连续的区域,他们更容易缓存效率。
有没有一个答案。它将与CPU,编译器,编译器标志,你有局部变量的数量,你之前的CPU已经做调用函数,和月亮的很可能是阶段而有所不同。
考虑两个极端;如果你只有一个或几个局部变量,它/它们可能很容易被保存在寄存器中,而不是被分配在所有的存储位置。如果寄存器“压力”是足够低的,这可能发生,而完全不执行任何指令。
在相反的极端有不具有在所有堆栈几台机器(例如,IBM大型机)。在这种情况下,有什么我们通常想象的那样栈帧是分配上的堆链表。正如你可能已经猜到,这可能是的非常的慢。
在谈到访问这些变量,情况也有些类似 - 访问机器寄存器是很好保证是不是在内存中分配的任何事物都快能为可能的希望。 OTOH,有可能访问的变量在堆栈上是相当缓慢的 - 这通常需要像索引间接访问,其中(尤其是年纪较大的CPU)往往是相当缓慢的。 OTOH,接入全球(其静态是,尽管它的名字是不是全局可见)通常需要形成一个绝对地址,其中一些的CPU违法处罚在一定程度上为好。
底线:即使建议分析代码可以被放错了地方 - 的差异可能很容易被如此的渺小,即使是分析器将检测不到它可靠,而仅的办法,以确保是检查的出品汇编语言(和花费数年时间学习汇编语言不够好,知道说什么,当你的做的了解一下吧)。这样做的另一面是,当你处理与别不同,你甚至不能可靠计量的机会,这将有真正的代码的速度产生重大影响是如此遥远,它可能不值得的麻烦。
它看起来像静态与非静态已完全覆盖,但对全局变量的话题。通常,这些会减慢一个程序的执行,而不是速度不起来。
原因是,限定范围的变量,很容易让编译器优化巨资,如果编译器必须看在你的应用实例,建立全球可能被使用,则它的优化也不会好。
此配混时你介绍指针,假定有以下代码:
int myFunction()
{
SomeStruct *A, *B;
FillOutSomeStruct(B);
memcpy(A, B, sizeof(A);
return A.result;
}
编译器知道指针A和B不能重叠,因此它可以优化副本。如果A和B是全球性的,然后他们可能指向重叠或相同的内存,这意味着编译器必须“明哲保身”,这是比较慢。该问题通常被称为“指针别名”和在很多情况,就可能出现不只是存储副本。
您可以随时计时您的应用程序真正确定什么是最快的。以下是我的理解:(所有这一切都取决于你的处理器的架构,顺便说一句)
C函数创建栈帧,这是在传递的参数被放置,变量和局部变量被放置,以及所述返回指针回其中呼叫者调用的函数。这里没有内存管理分配。通常一个简单的指针运动,这就是它。访问数据从堆栈也相当快。处罚通常会发挥作用时,你正在处理的指针。
对于全局或静态变量,它们是相同的......从的角度来看,他们打算在相同的内存区域进行分配。访问这些可能使用比局部变量访问的不同的方法,依赖于编译器。
您方案之间的主要区别是内存占用,与其说速度。
使用静态变量实际上可以使你的代码显著的慢的。静态变量必须存在于记忆的“数据”区域。为了使用该变量,该函数必须执行的加载指令从主存储器,或存储指令写入到它来读取。如果该区域不在缓存中,你失去了很多次。局部变量是在栈上的生命将确有在高速缓存中的地址,甚至可能是一个CPU寄存器中,从来没有出现在内存中。
我同意有关分析,找出类似的东西,但总的来讲,功能静态变量应该是比较慢的人的意见。如果你希望他们,你真的以后有什么是全球性的。功能静态插入代码/数据,以检查是否东西已经被那获取运行每次你的函数被调用时初始化。
剖析可能看不出来区别,拆卸和知道要寻找什么威力。
我怀疑你只是要得到一个变化高达每个环路几个时钟周期(平均取决于编译器等)。有时,变化将是显着的改善或慢得多,而且不会一定是因为变量家里已经从堆栈移动到/。比方说,你每次保存函数调用四个时钟周期上2GHz的处理器10000个呼叫。非常粗略的计算:20微秒保存。为20微秒的多还是少相比,当前的执行时间?
您可能会通过使所有的char和short变量为整数,除其他事项外获得更多的性能改进。微优化是一件好事,知道,但需要大量的时间进行实验,拆卸,定时你的代码的执行,理解是较少的指令并不意味着例如更快。
把你的具体方案,拆机都在讨论的功能和调用它的代码。带和不带静电。如果你获得只有一个或两个指令,这是你要做的唯一的优化,它可能是不值得的。你可能无法看出区别,同时剖析。在将高速缓存行命中可以在例如代码更改之前仿形显示
的变化。