我定义和编译了很多函数(巨大的列表)。我使用函数指针通过在运行时动态发送参数来调用和执行函数。它是一个迭代过程,每次迭代都涉及超过十万个函数调用。我想知道调用编译函数的有效方法是哪种。我觉得我的路比较慢。
答案 0 :(得分:6)
您需要对程序进行分析,以了解这是否存在问题。如果您将99%的时间花在个人职能上,那么您可以期望的最佳改进是1%,即使这样也不太可能。
答案 1 :(得分:3)
加速函数调用的唯一方法是编译器知道它将调用哪个函数。
就是这样:
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
,但是您需要对代码进行概要分析,看看它是否产生了积极的影响。
这一级别的间接不会产生巨大的差异。描述您的代码并找出实际减速的位置。
答案 2 :(得分:1)
这取决于您如何确定要调用的数十万个函数中的哪一个。如果您正在通过函数指针列表进行线性搜索,那么是的,您可能会浪费大量时间。在这种情况下,您应该考虑将函数指针放入哈希表中,或者至少将它们存储在排序列表中,以便您可以进行二进制搜索。如果没有关于你正在做什么以及你如何做的更多信息,很难给你提供有用的建议。
正如其他人所指出的那样,你肯定需要描述一下。听起来你不知道你所做的是否很慢,在这种情况下你也不知道是否值得尝试优化它。
答案 3 :(得分:1)
调用函数的开销主要是:
的组合首先,提出问题:
一旦你有一个好的算法和一个有效的实现,你将不得不向下移动到更低级别的优化方法 - 你可以使用汇编程序来做你自己的函数调用协议,这需要在堆栈上推送更少的数据。如果它们是“叶子函数”(不调用其他函数),您甚至可能不需要使用堆栈,因此可以避免每次调用时的一些开销指令。 (其中一些可能通过用gotos替换函数调用在C中完成 - 虽然它非常丑陋)
最后,您可以了解自修改代码的领域 - 使用代表函数的片段构建新的机器代码,然后调用生成的代码。这可能会使处理器特定且非常棘手 - 它的级别相当低。
答案 4 :(得分:0)
那么你可以创建自己的函数链接器,它可以链接某些函数“片段”调用命令并缓存它们以避免开销。它可能对你帮助不大。
很大程度上取决于功能的大小。他们在记忆和各种其他事情上彼此有多接近。删除函数指针没有什么意义,例如,如果第二个函数调用在内存中的第一个函数调用之后,因为该函数的开始可能已经被缓存。
即使你向我们提供了更多细节,也不是一个简单的问题。
正如马克所说......分析器是你的朋友。
答案 5 :(得分:0)
您应该使用QProf,Valgrind或gprof等工具来分析您的代码,并查看花费最多的执行时间。根据结果,您应该优化占用时间最多的功能。
如果列表迭代过程确实占用了代码的大部分时间,那么您应该尝试优化调用。如果您正在搜索列表以查找给定的函数,您可以尝试列出最常用的函数,或者按调用频率对它们进行排序,这样您的搜索算法就不必在列表中查看到找到它正在寻找的功能。
答案 6 :(得分:0)
取消引用函数指针所需的额外指令数应该是构成函数体的指令数的一小部分。积极地内联每个函数调用不会产生巨大的差异。正如之前的答案所示,您确实需要使用分析器来确定瓶颈。
在重大计划中,在这里或那里削减一些指令不会有任何重大改进。最大的胜利将来自改进算法。