&引用;内联“;C语言中运行时的(类)函数
我在考虑一个典型的问题,这个问题非常JIT,但是用原始C很难解决。这个场景是设置一系列函数指针,这些指针将在运行时“组合”(如数学函数组合)一次,然后多次调用 显然,这样做会涉及许多虚拟调用,这是非常昂贵的,如果有足够多的嵌套函数来完全填充CPU分支预测表,那么性能将显著下降 在像Lisp这样的语言中,我可能会处理代码并用函数的实际内容替换“虚拟”调用,然后调用&引用;内联“;C语言中运行时的(类)函数,c,lisp,metaprogramming,inline,jit,C,Lisp,Metaprogramming,Inline,Jit,我在考虑一个典型的问题,这个问题非常JIT,但是用原始C很难解决。这个场景是设置一系列函数指针,这些指针将在运行时“组合”(如数学函数组合)一次,然后多次调用 显然,这样做会涉及许多虚拟调用,这是非常昂贵的,如果有足够多的嵌套函数来完全填充CPU分支预测表,那么性能将显著下降 在像Lisp这样的语言中,我可能会处理代码并用函数的实际内容替换“虚拟”调用,然后调用compile,以获得一个优化版本,但这在C中似乎非常粗糙且容易出错,使用C是这个问题的一个要求;-) 那么,你知道在C语言中是否有一种
compile
,以获得一个优化版本,但这在C中似乎非常粗糙且容易出错,使用C是这个问题的一个要求;-)
那么,你知道在C语言中是否有一种标准的、可移植的、安全的方法来实现这一点吗
干杯您可能想看看LLVM。他们有一个库,允许从C中JIT代码(以及更多的东西),它支持许多平台,并且是一个开源项目:我有两个建议来消除虚拟函数调用,如果性能需要的话。为了便于说明,假设有一个函数将函数指针作为参数:
void my_algorithm(int (*func)(...), ...)
{
/* ... */
}
并且还假设您预先知道函数指针可以采用的所有可能值。例如:
my_algorithm(func_1, ...);
//...
my_algorithm(func_2, ...);
首先将原始my_算法()转换为宏:
#define MY_ALGORITHM(func, ...) \
{ \
/* ... */ \
}
然后将我的_算法()重写为:
这当然会使编译的对象文件的大小增加一倍。而且,从表面上看,它只删除了一个间接层次。但是如果func_1和/或func_2是内联的,则可以获得相当大的速度
您甚至可以“传递”宏,如:
#define HYPOT_Y(x) hypot(x, y)
MY_ALGORITHM(HYPOT_Y, ...); //assumes y is known
第二个建议是使用X宏()的一个变体。将原始my_algorithm()的主体放在单独的文件my_algorithm.h中,而不是定义。然后将我的_算法()重写为:
如果代码超过几十行,我可能会使用X宏。其优点包括(无双关语):
- 没有难看的反斜杠
- 更容易调试(例如回溯和单步执行)
这都是标准的C语言,但比较老派。如果您只支持x86,您可以尝试嵌入TCC:
如果执行此操作,请使用switch语句并传入整数/枚举,而不是使用一堆If/else If/etc。开关速度要快得多。您可以切换常量而不是函数指针。如果不需要函数地址,则根本不获取函数地址,它会强制编译器提供函数的非内联副本,以提供指针。此外,内联(对于大多数C编译器)不能与extern一起工作,因为函数必须包含在同一个编译单元中。不幸的是,情况并非如此,要使用的函数只有在运行时才知道,它们可以以多种不同的方式组合。。。而且仍然有分支^ ^如果事先不知道所使用的函数,就永远不能在编译阶段进行内联。你需要准时制。是的,同意。我的建议只有在“您事先知道函数指针可以接受的所有可能值”的情况下才有效。关于初始分支,如果算法类似于数值积分,其成本可以忽略不计。是的,这是我在考虑的一个选项,但我在考虑更简单的问题,我不认为我需要整个JIT,只是将一些函数粘在一起,就好像它们只是一个大函数一样。无论如何,谢谢:-)遗憾的是,我需要代码能够移植到各种平台:-(不过,感谢链接,看起来可能很有趣!LLVM是您的平台。毕竟,它没有那么糟糕,而且通过普通的C API很容易使用。另一种选择是在C中实现线程化代码Forth intepreter(使用计算的goto GCC扩展),并为其生成代码。应该比下降JIT慢2-6倍,但简单且绝对可移植。它足以将函数粘合在一起。
#define HYPOT_Y(x) hypot(x, y)
MY_ALGORITHM(HYPOT_Y, ...); //assumes y is known
void my_algorithm(int (*func)(...), ...)
{
if (func == func_1)
#define func func_1
#include "my_algorithm.h"
#undef func
else if (func == func_2)
#define func func_2
#include "my_algorithm.h"
#undef func
else
assert(0 && "Unexpected function arg to my_algorithm()");
}