我有以下C ++程序:
void testSpeed(int start, int end)
{
int temp = 0;
for(int i = start; i < end; i++)
{
temp++;
}
}
int main() {
using namespace boost;
timer aTimer;
// start two new threads that calls the "testSpeed" function
boost::thread my_thread1(&testSpeed, 0, 500000000);
boost::thread my_thread2(&testSpeed, 500000000, 1000000000);
// wait for both threads to finish
my_thread1.join();
my_thread2.join();
double elapsedSec = aTimer.elapsed();
double IOPS = 1/elapsedSec;
}
因此,我们的想法是以每秒整数运算(IOPS)的形式测试CPU速度。 有10亿次迭代(操作),所以在1Ghz CPU上我们应该每秒进行大约十亿次整数运算,我相信。
我的假设是更多线程=每秒更多整数运算。但是我尝试的线程越多,我看到的每秒操作越少(我的内核多于线程)。 什么可能导致这样的行为?这是线程开销吗?也许我应该尝试更长的实验,看看线程是否真的有用?
谢谢!
更新: 因此我将循环更改为运行了18亿次,并将temp声明为volatile。还添加了另一个具有不同名称的testSpeed方法,所以现在一个线程一个接一个地执行这两个方法,而两个线程获得每个方法;所以不应该有任何同步'问题等等......并且......行为仍然没有变化!根据计时器,单线程更快。唉唉!我找到了傻瓜,显然计时器是虚张声势。这两个线程花费了一半的时间来完成但是计时器告诉我单线程运行速度快了两秒。我现在正在努力理解为什么......谢谢大家!
答案 0 :(得分:3)
我几乎可以肯定编译器会优化你的循环。由于您没有减去创建/同步线程的开销,因此实际上只测量它。所以你拥有的线程越多,创建的开销就越多,花费的时间也就越多。
总的来说,您可以参考CPU的文档,了解它的频率以及任何给定指令需要多少滴答。使用这样的方法自己测试几乎是不可能的,而且是无用的。这是因为像上下文切换这样的开销,将执行从一个CPU /核心转移到另一个CPU /核心,调度程序交换,分支错误预测。在现实生活中,您还会遇到缓存未命中和大量内存总线延迟,因为没有适合~15个寄存器的程序。因此,您最好使用一些优秀的分析器来测试真实的程序。例如,最新的CPU可以发出CPU停顿信息,缓存未命中,分支错误预测等等。您可以使用一个好的分析器来实际决定何时以及如何并行程序。
答案 1 :(得分:2)
随着线程数增加超过某一点,它会导致缓存未命中数增加(缓存在线程之间共享),但同时内存访问延迟被大量掩盖线程(当线程正在等待从内存中获取数据时,其他线程正在运行)。因此有一个权衡。 Here是关于这个主题的非常有趣的论文。
根据这篇论文,在一个多核机器上,当线程数量非常低(核心数量级)时,性能会随着线程数量的增加而增加,因为现在核心已经完全利用。
之后,线程数量的进一步增加导致高速缓存未命中的影响,从而导致性能下降。
如果线程数变得非常大,使得每个线程的高速缓存存储量几乎几乎变为零,则所有存储器访问都是从主存储器进行的。但同时增加的线程数也非常有效地掩盖了增加的内存访问延迟。这次第二种效应占主导地位,导致性能提升。
因此,中间的山谷是性能最差的地区。