【发布时间】:2011-12-26 06:49:55
【问题描述】:
解决方案:显然罪魁祸首是使用了floor(),其性能在 glibc 中被证明是依赖于操作系统的。
这是上一个问题的后续问题:Same program faster on Linux than Windows -- why?
我有一个小型 C++ 程序,当使用 nuwen gcc 4.6.1 编译时,它在 Wine 上的运行速度比 Windows XP 快得多(在同一台计算机上)。问题:为什么会发生这种情况?
Wine 和 Windows 的时间分别为 ~15.8 和 25.9 秒。请注意,我说的是同一个可执行文件,而不仅仅是同一个 C++ 程序。
源码在文末。编译后的可执行文件是here(如果你足够信任我的话)。
这个特定的程序没有任何用处,它只是从我拥有的一个更大的程序中总结出来的一个最小示例。请参阅this other question 对原始程序进行更精确的基准测试(重要!!)并排除最常见的可能性(例如其他程序在 Windows 上占用 CPU、进程启动惩罚、系统调用的差异,例如内存分配) .另请注意,虽然在这里为了简单起见我使用了rand(),但在原始版本中我使用了我自己的 RNG,我知道它不会进行堆分配。
我提出一个关于该主题的新问题的原因是,现在我可以发布一个实际的简化代码示例来重现该现象。
代码:
#include <cstdlib>
#include <cmath>
int irand(int top) {
return int(std::floor((std::rand() / (RAND_MAX + 1.0)) * top));
}
template<typename T>
class Vector {
T *vec;
const int sz;
public:
Vector(int n) : sz(n) {
vec = new T[sz];
}
~Vector() {
delete [] vec;
}
int size() const { return sz; }
const T & operator [] (int i) const { return vec[i]; }
T & operator [] (int i) { return vec[i]; }
};
int main() {
const int tmax = 20000; // increase this to make it run longer
const int m = 10000;
Vector<int> vec(150);
for (int i=0; i < vec.size(); ++i)
vec[i] = 0;
// main loop
for (int t=0; t < tmax; ++t)
for (int j=0; j < m; ++j) {
int s = irand(100) + 1;
vec[s] += 1;
}
return 0;
}
更新
似乎如果我将上面的 irand() 替换为诸如
int irand(int top) {
static int c = 0;
return (c++) % top;
}
那么时间差就消失了。我想指出,虽然在my original program 中我使用了不同的RNG,而不是系统rand()。我现在正在研究它的来源。
更新 2
现在我将irand() 函数替换为我在原始程序中的等效函数。它有点长(算法来自Numerical Recipes),但重点是表明没有显式调用系统库(可能通过floor() 除外)。但是时间差还是有的!
也许floor() 是罪魁祸首?还是编译器生成对其他东西的调用?
class ran1 {
static const int table_len = 32;
static const int int_max = (1u << 31) - 1;
int idum;
int next;
int *shuffle_table;
void propagate() {
const int int_quo = 1277731;
int k = idum/int_quo;
idum = 16807*(idum - k*int_quo) - 2836*k;
if (idum < 0)
idum += int_max;
}
public:
ran1() {
shuffle_table = new int[table_len];
seedrand(54321);
}
~ran1() {
delete [] shuffle_table;
}
void seedrand(int seed) {
idum = seed;
for (int i = table_len-1; i >= 0; i--) {
propagate();
shuffle_table[i] = idum;
}
next = idum;
}
double frand() {
int i = next/(1 + (int_max-1)/table_len);
next = shuffle_table[i];
propagate();
shuffle_table[i] = idum;
return next/(int_max + 1.0);
}
} rng;
int irand(int top) {
return int(std::floor(rng.frand() * top));
}
【问题讨论】:
-
静态/动态链接(什么 dll 依赖项?)
-
@sehe 我有一个 32 位 CPU,都是 32 位操作系统
-
您能否消除对
std::floor()和std::rand()的调用,例如通过将irand()替换为返回相同确定性模式的函数?看看性能差异是否仍然存在会很有趣。 -
@aix 好点,如果我用
int irand(int top) { static int c=0; return (c++) % top; }替换irand,时间差就会消失(或变得非常小)。奇怪的是,在我的原始程序中,我使用的是来自 Numerical Recipes 的 RNG,而不是 systenrand()。我现在正在研究 RNG。 -
@celtschk 原来差异是由于
floor()!我从没想过floor()可能依赖于操作系统,但显然在 glibc 中它是。
标签: c++ windows linux performance benchmarking