特定C++随机数生成的Clang性能下降
Clang performance drop for specific C++ random number generation
使用C++11的随机模块,当将std::mt19937
(32位和64位版本)与uniform_real_distribution
(浮点或双精度,无关紧要)结合使用时,我遇到了一个奇怪的性能下降。与g++编译相比,它慢了一个数量级!
罪魁祸首不仅仅是mt生成器,因为它使用uniform_int_distribution
的速度很快。这并不是uniform_real_distribution
中的一般缺陷,因为它与default_random_engine
等其他生成器相比速度很快。仅仅是这种特定的组合就异常缓慢。
我对本质不太熟悉,但Mersenne Twister算法或多或少都有严格的定义,所以我想实现上的差异不能解释这种差异?measure程序如下,但以下是我在64位linux机器上对clang 3.4和gcc 4.8.1的结果:
gcc 4.8.1
runtime_int_default: 185.6
runtime_int_mt: 179.198
runtime_int_mt_64: 175.195
runtime_float_default: 45.375
runtime_float_mt: 58.144
runtime_float_mt_64: 94.188
clang 3.4
runtime_int_default: 215.096
runtime_int_mt: 201.064
runtime_int_mt_64: 199.836
runtime_float_default: 55.143
runtime_float_mt: 744.072 <--- this and
runtime_float_mt_64: 783.293 <- this is slow
生成这个并自己尝试的程序:
#include <iostream>
#include <vector>
#include <chrono>
#include <random>
template< typename T_rng, typename T_dist>
double time_rngs(T_rng& rng, T_dist& dist, int n){
std::vector< typename T_dist::result_type > vec(n, 0);
auto t1 = std::chrono::high_resolution_clock::now();
for (int i = 0; i < n; ++i)
vec[i] = dist(rng);
auto t2 = std::chrono::high_resolution_clock::now();
auto runtime = std::chrono::duration_cast<std::chrono::microseconds>(t2-t1).count()/1000.0;
auto sum = vec[0]; //access to avoid compiler skipping
return runtime;
}
int main(){
const int n = 10000000;
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
std::default_random_engine rng_default(seed);
std::mt19937 rng_mt (seed);
std::mt19937_64 rng_mt_64 (seed);
std::uniform_int_distribution<int> dist_int(0,1000);
std::uniform_real_distribution<float> dist_float(0.0, 1.0);
// print max values
std::cout << "rng_default_random.max(): " << rng_default.max() << std::endl;
std::cout << "rng_mt.max(): " << rng_mt.max() << std::endl;
std::cout << "rng_mt_64.max(): " << rng_mt_64.max() << std::endl << std::endl;
std::cout << "runtime_int_default: " << time_rngs(rng_default, dist_int, n) << std::endl;
std::cout << "runtime_int_mt: " << time_rngs(rng_mt_64, dist_int, n) << std::endl;
std::cout << "runtime_int_mt_64: " << time_rngs(rng_mt_64, dist_int, n) << std::endl;
std::cout << "runtime_float_default: " << time_rngs(rng_default, dist_float, n) << std::endl;
std::cout << "runtime_float_mt: " << time_rngs(rng_mt, dist_float, n) << std::endl;
std::cout << "runtime_float_mt_64: " << time_rngs(rng_mt_64, dist_float, n) << std::endl;
}
分别通过CCD_ 6或g++编译。有什么想法吗?
编辑:最后,Matthieu M.想出了一个好主意:罪魁祸首是内联,或者更确切地说是缺少内联。增加clang内联限制消除了性能损失。这实际上解决了我遇到的一些性能问题。谢谢,我学到了一些新东西。
如注释中所述,问题是由gcc内联比clang更具攻击性这一事实引起的。如果我们非常激进地使clang内联,效果就会消失:
使用g++ -O3
编译代码会产生
runtime_int_default: 3000.32
runtime_int_mt: 3112.11
runtime_int_mt_64: 3069.48
runtime_float_default: 859.14
runtime_float_mt: 1027.05
runtime_float_mt_64: 1777.48
而CCD_ 8产生
runtime_int_default: 3623.89
runtime_int_mt: 751.484
runtime_int_mt_64: 751.132
runtime_float_default: 1072.53
runtime_float_mt: 968.967
runtime_float_mt_64: 1781.34
显然,clang现在在int_mt
的情况下内联gcc,但所有其他运行时现在都处于相同的数量级。我在Fedora 20 64位上使用了gcc 4.8.3和clang 3.4。
相关文章:
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- OpenMP阵列性能较差
- 递归列出所有目录中的C++与Python与Ruby的性能
- 奇怪的结构&GCC&clang(void*返回类型)
- 数据成员SFINAE的C++17测试:gcc vs clang
- 当我编译webrtc服务器时,Windows上只支持clang-cl
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- 大小相等但成员数量不同的结构之间的性能差异
- 我可以将一个用clang c++11编译的对象与另一个用c++17编译的对象链接起来吗
- Clang bug?使用指针作为模板参数
- 为什么constexpr的性能比正常表达式差
- clang整洁10忽略了我的NOLINT命令
- 如何防止clang格式在流运算符调用之间添加换行符<<
- 在clang++预处理器中确定gcc工具链版本
- 为什么 Clang 不允许"and"作为函数名称?
- GCC 和 Clang 代码性能的巨大差异
- 使用双包装器类进行位操作(C++、clang)修复性能下降问题
- 为什么链接到librt会在g++和clang之间交换性能
- 如何使用PCH或PTH提高clang解析性能
- 特定C++随机数生成的Clang性能下降