我相信很多人都经历过这种情况。第一次在Linux上执行c ++代码总是要花费更长的时间。
在我的Linux机器上,像第一次调用::clock_gettime(CLOCK_REALTIME, &ts);
大约比第三次慢大约五倍。
第一次分配内存比第二次慢100倍。
我尝试了预分配并在我的应用程序中使用了mlockall
,但是即使如此,一个函数的第一次执行比第二个函数慢大约160倍,第二个函数却慢了两倍。 >
该函数的伪代码如下。 msg
在堆上分配。但是它不包含在时间测量中。 msg2
是POD,因此slow_for_the_first_time
中根本没有内存分配。
void slow_for_the_first_time(Message * msg) {
Msg2 msg2;
//set msg2 using msg
.... }
想知道,是什么原因导致第一次执行的缓慢?还有避免这种情况的方法吗?
erenon的答案很有帮助。我认为可能是因为Msg2是在so库中定义的。
在使用LD_BIND_NOW = 1之前,第一个执行时间约为8000纳秒,第二个执行时间约为500纳秒,第三个执行时间约为200纳秒。
现在,第一个执行时间约为2000纳秒,而第二个和第三个执行时间保持不变。因此它仍比第三次执行慢10倍,应该有其他因素影响第一次执行时间。
一些有趣的发现。
在slow_for_the_first_time
之前的调用方法可以将首次执行时间再减少1微秒
void dummySet(Msg2& msg2)
{
//set all fields of msg2. msg2 has about 30 fields it won't work if only set one field of msg2.
}
值得一提的是,第一次执行的速度绝对与msg
无关,因为下面的代码中的第二次slow_for_the_first_time
char buffer[sizeof(Message)];
memset(buffer, 0, sizeof(buffer));
slow_for_the_first_time((Message*)buffer);//calling the method with a dummy buffer.
.....
slow_for_the_first_time(msg);//calling the method for the second time with a real msg.
与下面代码中的第二个slow_for_the_first_time
一样快
slow_for_the_first_time(msg);//the first time takes around 2000 nanoseconds
.....
slow_for_the_first_time(msg);//the second time takes around 500 nanoseconds.
答案 0 :(得分:2)
第一次链接引用的符号时,需要在动态加载的符号集中查找动态链接的符号。要查看这是否确实是问题所在,请执行以下操作:
$ LD_BIND_NOW=1 ./your_program
LD_BIND_NOW
将指示链接器在GOT和PLT中的每个条目都固定地址:这将使启动速度稍慢,但也可能解决交换中的“首次呼叫速度慢”的问题。
如果事实证明是问题所在,则可以尝试静态链接库或预链接。
答案 1 :(得分:2)
除了懒惰链接erenon谈论in their answer之外,还有其他两个因素会导致首次运行时执行缓慢:冷缓存和冷分支预测。
总体而言,后续通话的加速来自:
总体而言,代码在首次执行时往往会变慢。如果这是一个问题,则解决方案是:
LD_BIND_NOW
,在启动时链接;