【发布时间】:2011-12-08 19:59:14
【问题描述】:
我的应用场景是这样的:我想评估在四核机器上处理相同数量的数据可以实现的性能增益。我有以下两种配置:
i) 1-Process:没有任何线程并处理来自 1M .. 1G 的数据的程序,而假设系统仅运行其 4 核中的单个核。
ii) 4-threads-Process:具有 4 个线程(所有线程执行相同操作)但处理 25% 的输入数据的程序。
在创建 4 线程的程序中,我使用了 pthread 的默认选项(即,没有任何特定的 pthread_attr_t)。我相信与 1-Process 配置相比,4-thread 配置的性能提升应该接近 400%(或介于 350% 和 400% 之间)。
我分析了创建线程所花费的时间,如下所示:
timer_start(&threadCreationTimer);
pthread_create( &thread0, NULL, fun0, NULL );
pthread_create( &thread1, NULL, fun1, NULL );
pthread_create( &thread2, NULL, fun2, NULL );
pthread_create( &thread3, NULL, fun3, NULL );
threadCreationTime = timer_stop(&threadCreationTimer);
pthread_join(&thread0, NULL);
pthread_join(&thread1, NULL);
pthread_join(&thread2, NULL);
pthread_join(&thread3, NULL);
由于输入数据大小的增加也可能增加每个线程的内存需求,所以提前加载所有数据绝对不是一个可行的选择。因此,为了保证不增加每个线程的内存需求,每个线程以小块读取数据,处理它,然后读取下一个块处理它等等。因此,我的线程运行的函数的代码结构是这样的:
timer_start(&threadTimer[i]);
while(!dataFinished[i])
{
threadTime[i] += timer_stop(&threadTimer[i]);
data_source();
timer_start(&threadTimer[i]);
process();
}
threadTime[i] += timer_stop(&threadTimer[i]);
变量dataFinished[i] 在接收并处理所有需要的数据时被进程标记为true。 Process() 知道什么时候这样做:-)
在主函数中,我正在计算 4 线程配置所花费的时间,如下所示:
execTime4Thread = max(threadTime[0], threadTime[1], threadTime[2], threadTime[3]) + threadCreationTime.
而性能增益的计算方式很简单
gain = execTime1process / execTime4Thread * 100
问题: 在 1M 到 4M 左右的小数据大小上,性能增益通常很好(在 350% 到 400% 之间)。然而,随着输入大小的增加,性能增益的趋势呈指数下降。它一直在下降,直到一些数据大小达到 50M 左右,然后稳定在 200% 左右。一旦达到这一点,即使是 1GB 的数据,它也几乎保持稳定。
我的问题是任何人都可以提出这种行为的主要原因(即,开始时性能下降,但后来保持稳定)?
以及如何解决这个问题的建议?
为了您的信息,我还调查了每个线程的threadCreationTime 和threadTime 的行为,以了解发生了什么。对于 1M 的数据,这些变量的值很小,但是随着数据大小的增加,这两个变量都呈指数增长(但无论数据大小如何,threadCreationTime 应该保持几乎相同,threadTime 应该以对应于数据的速率增加正在处理中)。在继续增加直到 50M 左右之后,threadCreationTime 变得稳定,threadTime(就像性能下降变得稳定一样)和threadCreationTime 以恒定的速率持续增加,对应于要处理的数据的增加(这被认为是可以理解的)。
你认为增加每个线程的堆栈大小、进程优先级的东西或其他参数类型的调度程序的自定义值(使用pthread_attr_init)会有帮助吗?
PS:结果是在 Linux 的故障安全模式下以 root 运行程序时获得的(即,最小的操作系统在没有 GUI 和网络的情况下运行)。
【问题讨论】:
-
你的CPU是什么型号的?
-
最有可能在线程之间交叉污染缓存。您是否尝试过改变数据块的大小?您还应该在测量中包含数据加载,因为它可能是一个瓶颈,即 2 个内核可能会使您的内存总线饱和。 (另外,如果你还没有这样做,你应该把你的定时器放在不同的缓存行上。)
-
@Mats:处理器是 Intel(R) Core(TM)2 Quad CPU Q9950 @ 2.83GHz。不,我没有验证数据块的大小。好的,我将尝试更改数据块的大小。但是,我不明白您所说的缓存线是什么意思。如何将定时器缓存起来?
-
@Junaid:您的 threadTimer 数组元素应以 64 个字节分隔。这通常是缓存行的大小。
-
@Junaid:首先阅读这个 - en.wikipedia.org/wiki/MESI_protocol 和这个 - en.wikipedia.org/wiki/False_sharing。
标签: linux multithreading performance pthreads multicore