我定义和编译了很多函数(巨大的列表)。我使用函数指针通过在运行时动态发送参数来调用和执行函数。这是一个迭代过程,每次迭代涉及超过十万个函数调用。我想知道哪种是调用编译函数的有效方法。我觉得我的方式比较慢。
7 回答
您需要分析您的程序以了解这是否是一个问题。如果您将 99% 的时间花在单个功能上,那么您可以期望的最大改进是 1%,即使这样也不太可能。
加快函数调用的唯一方法是编译器知道它将调用什么函数。
也就是说,类似:
void foo(void)
{
/* do some stuff */
}
int main(void)
{
foo();
}
可以内联到:
int main(void)
{
/* do some stuff */
}
但是如果编译器不知道调用哪一个:
void foo(void)
{
/* do some stuff */
}
void bar(void)
{
/* do some other stuff */
}
typedef void(*Function)(void);
int main(void)
{
Function func = /* choose a function at runtime */
func();
}
编译器无法预测将调用哪个函数,因此无法内联它。
如果您的编译器支持它,您可以尝试使用__fastcall
,但您需要分析您的代码并查看它是否产生了积极的影响。
这一级的间接性不会产生巨大的影响。分析您的代码并找出真正的减速在哪里。
这取决于您如何确定要调用这数十万个函数中的哪一个。如果您正在通过函数指针列表进行线性搜索,那么是的,您可能会浪费很多时间。在这种情况下,您应该考虑将函数指针放入哈希表中,或者至少将它们存储在排序列表中,以便进行二进制搜索。如果没有更多关于你在做什么以及你是如何做的信息,就很难给你有用的建议。
此外,正如其他人所指出的那样,您肯定需要进行概要分析。听起来您不知道您正在做的事情是否很慢,在这种情况下您也不知道是否值得尝试对其进行优化。
调用函数的开销主要是以下几种情况的组合:
- 函数调用本身
- 你传递的参数
- 返回值
- 您需要调用该函数的次数
因此,首先,提出问题:
- 你能改变算法以减少函数调用吗?
- 你能减少来回传递的数据量吗?
- 您可以更改算法以批量调用每个函数(以便您可以在一次调用中处理一组值,或者至少为一组值重复调用相同的函数,以便所有代码都保留在 CPU 的缓存中)?
一旦你有了一个好的算法和一个有效的实现,你就必须向下移动到较低级别的优化方法——你可以使用汇编器来执行你自己的函数调用协议,这需要更少的数据被推送到堆栈上。如果它们是“叶函数”(不调用其他函数),您甚至可能不需要使用堆栈,因此可以避免每次调用的一些开销指令。(其中一些可以通过用 gotos 替换函数调用在 C 中完成 - 虽然它非常难看)
最后,您可以进入自我修改代码的领域——从代表函数的片段中构建新的机器代码,然后调用生成的代码。但是,这可能会变得非常特定于处理器并且很棘手-它的级别非常低。
好吧,您可以创建自己的函数链接器,该链接器可以将某些函数“片段”调用命令链接在一起并缓存它们以避免开销。不过,它可能对您没有多大帮助。
很大程度上取决于函数的大小。他们在记忆和其他各种事情上彼此之间的距离有多近。例如,如果第二个函数调用就在内存中的第一个函数调用之后,那么删除函数指针就没有什么意义了,因为该函数的开头可能已经被缓存了。
即使您确实向我们提供了更多详细信息,这也不是一个简单的问题。
正如马克所说......分析器是你的朋友。
取消引用函数指针所需的额外指令数量应该是构成函数主体的指令数量的一小部分。积极内联每个函数调用不会产生巨大的影响。正如前面的答案所建议的,您确实需要使用分析器来确定瓶颈。
在大的计划中,在这里或那里削减一些指令不会有任何重大改进。最大的胜利将来自改进你的算法。