简要描述我的问题:
我的计算机配备有2个AMD Opteron 6272插槽和64GB内存。
我在所有32个核心上运行一个多线程程序,与我在两个16个核心插槽上分别运行两个程序的情况相比,速度要慢15%。
如何使单个程序版本与双程序版本一样快?
更多细节:
我有大量任务并希望充分利用系统的所有32个核心。因此,我将任务分组为每组1000个。这样的一组任务需要约120Mb的输入数据,并需要大约10秒钟才能在一个核心上完成。为了使测试更加理想,我将这些组复制32次,并使用ITBB的parallel_for
循环在32个核心之间分发任务。
我使用pthread_setaffinity_np
确保系统不会让我的线程在核心之间跳跃。为了确保所有核心都被连续使用。
我使用mlockall(MCL_FUTURE)
来确保系统不会使我的内存在插槽之间跳跃。
所以代码看起来像这样:
void operator()(const blocked_range<size_t> &range) const
{
for(unsigned int i = range.begin(); i != range.end(); ++i){
pthread_t I = pthread_self();
int s;
cpu_set_t cpuset;
pthread_t thread = I;
CPU_ZERO(&cpuset);
CPU_SET(threadNumberToCpuMap[i], &cpuset);
s = pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
mlockall(MCL_FUTURE); // lock virtual memory to stay at physical address where it was allocated
TaskManager manager;
for (int j = 0; j < fNTasksPerThr; j++){
manager.SetData( &(InpData->fInput[j]) );
manager.Run();
}
}
}
对我来说只有计算时间很重要,因此我会在一个单独的parallel_for
循环中准备输入数据。并且不将准备时间包括在时间测量中。
void operator()(const blocked_range<size_t> &range) const
{
for(unsigned int i = range.begin(); i != range.end(); ++i){
pthread_t I = pthread_self();
int s;
cpu_set_t cpuset;
pthread_t thread = I;
CPU_ZERO(&cpuset);
CPU_SET(threadNumberToCpuMap[i], &cpuset);
s = pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
mlockall(MCL_FUTURE); // lock virtual memory to stay at physical address where it was allocated
InpData[i].fInput = new ProgramInputData[fNTasksPerThr];
for(int j=0; j<fNTasksPerThr; j++){
InpData[i].fInput[j] = InpDataPerThread.fInput[j];
}
}
}
现在我在32个核心上运行所有这些任务,每秒速度大约为1600个任务。
然后我创建了程序的两个版本,并使用taskset
和pthread
确保第一个版本在第一插槽的16个核心上运行,第二个版本在第二插槽上运行。 我使用简单的&
命令在shell中将它们并行运行:
program1 & program2 &
每个程序都可以达到约900个任务/秒的速度。总共有超过1800个任务/秒,比单程序版本多15%。
我错过了什么?
我认为问题可能在于我只将库加载到主线程的内存中。这可能是个问题吗?我能否复制库数据以便独立地在两个插座上使用?