第一次在 Linux 上执行 c++ 代码的时间非常慢
Execution time of c++ code on Linux for the first time is extremly slow
我相信很多人都经历过。第一次在 Linux 上执行 c++ 代码总是需要更长的时间。
就像第一次打电话::clock_gettime(CLOCK_REALTIME, &ts);
比在我的 linux 盒子上第三次慢五倍。
第一次分配记忆比第二次慢 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
.... }
只是想知道,什么会导致第一次执行缓慢?有没有办法避免它?
埃雷农的回答有很大帮助。我认为这可能是因为 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.
首次引用动态链接的符号时,需要在动态加载的符号集中查找它们。要查看这是否真的是问题所在,请执行以下操作:
$ LD_BIND_NOW=1 ./your_program
LD_BIND_NOW
将指示链接器修复 GOT 和 PLT 中的每个条目的地址:这将使启动速度稍慢,但也可能会解决"第一次调用很慢"的问题作为交换。
如果这被证明是问题所在,您可以尝试静态链接库或预链接。
除了 erenon 在他们的答案中谈到的惰性链接之外,还有另外两个因素导致首次运行时执行缓慢:冷缓存和冷分支预测。
总体而言,后续调用的加速来自:
- 外部符号:一旦链接器解析了一个符号,它就是程序的生命周期,之后实际上是无操作的;
- data:当数据被CPU处理时,它暂时存储在CPU缓存中。将内存加载到该缓存中是一项成本高昂的操作。但是一旦它进入那里,由于缓存是一个非常靠近CPU的超快内存,因此下次可以快速获得相同的数据。您可以阅读有关缓存的其他答案。
- CPU:分支预测通过尝试和预测代码分支的方式,显著改进了代码执行。这也需要热身。这是关于分支预测的一个很好的答案。
总体而言,代码在首次执行时往往很慢。如果这是一个问题,解决方案是:
LD_BIND_NOW
,在启动时链接;- 缓存预热;
- 分支预测预热。
- C++为构建时间获取QDateTime的可靠方法
- 从持续时间构造std::chrono::system_clock::time_point
- 向量 <int> a {N, 0} 和 int arr a[N] = {0} 的时间复杂度有什么区别
- while循环中while循环的时间复杂度是多少
- 使用简单类型列表实现的指数编译时间.为什么
- 是否可以在编译时初始化数组,以便在运行时不会花费时间?
- 为什么std::互斥需要很长的、非常不规则的时间来共享
- 超过CPU时间限制:当MPI_Sent一个非常大的int*时
- 我看到将我的类成员函数指定为内联实际上会增加执行时间,即使函数体非常小
- 第一次在 Linux 上执行 c++ 代码的时间非常慢
- 如果将功能的非常简单的定义移动到.cpp,则编译时间的减少是多少
- C++在堆上分配相同类型的变量所花费的时间非常不同
- 寻找非常精确的delta时间计数器.想要限制闪电战游戏中的帧数
- 在 Linux 中,非常高的经过(挂钟)时间和低系统时间的含义
- boost::signals2编译时间非常慢
- 对于静态初始化的大数组(例如65536条目),编译时间非常长
- 如何测量c++中特定函数的运行时间{非常准确}
- 如果使用预定义的映射,重建项目将花费非常长的时间
- 如何得到非常精确的运行时间c++
- 与这些代码的性能有关?一个非常快,另一个超过了时间限制