我有一个多线程的c ++应用程序,可以在Windows,Mac和一些Linux风格上运行.
简而言之:为了使它以最高效率运行,我必须能够为每个物理处理器/核心实例化一个线程.创建比物理处理器/内核更多的线程会大大降低程序的性能.我已经可以在所有这三个平台上正确检测逻辑处理器/核心的数量.为了能够正确检测物理处理器/内核的数量,我必须检测是否支持超级交叉和活动.
因此,我的问题是,是否有办法检测是否支持超线程并启用?如果是这样,究竟如何.
显然,可以使用比较和交换指令以原子方式递增两个整数.这个谈话声称存在这样的算法,但它没有详细说明它的样子.
如何才能做到这一点?
(注意,一个接一个地递增整数的明显解决方案不是原子的.另外,将多个整数填充到一个机器字中并不算数,因为它会限制可能的范围.)
我正在开发大密集矩阵乘法代码.当我对代码进行分析时,它有时会获得我的四个核心系统中大约75%的峰值触发器,而其他时间则大约为36%.在执行代码之间效率不会改变.它要么以75%开始并继续保持效率,要么从36%开始并继续保持这种效率.
我已经将问题追溯到超线程以及我将线程数设置为4而不是默认值8的事实.当我在BIOS中禁用超线程时,我一致地获得大约75%的效率(或者至少我从未看到大幅下降到36%).
在我调用任何并行代码之前omp_set_num_threads(4).我export OMP_NUM_THREADS=4在运行代码之前也尝试过,但它似乎是等效的.
我不想在BIOS中禁用超线程.我想我需要将四个线程绑定到四个核心.我已经测试了一些不同的情况,GOMP_CPU_AFFINITY但到目前为止,我仍然存在效率为36%的问题. 超线程和核心的映射是什么? 例如,线程0和线程1对应于同一个核心和线程2,线程3对应另一个核心吗?
如何在没有线程迁移的情况下将线程绑定到每个核心,这样我就不必在BIOS中禁用超线程? 也许我需要研究使用sched_setaffinity?
我当前系统的一些细节:Linux内核3.13,GCC 4.8,Intel Xeon E5-1620(四个物理内核,八个超线程).
编辑:到目前为止,这似乎运作良好
export GOMP_CPU_AFFINITY="0 1 2 3 4 5 6 7"
Run Code Online (Sandbox Code Playgroud)
要么
export GOMP_CPU_AFFINITY="0-7"
Run Code Online (Sandbox Code Playgroud)
编辑:这似乎也运作良好
export OMP_PROC_BIND=true
Run Code Online (Sandbox Code Playgroud)
编辑: 这些选项也很好用(gemm是我的可执行文件的名称)
numactl -C 0,1,2,3 ./gemm
Run Code Online (Sandbox Code Playgroud)
和
taskset -c 0,1,2,3 ./gemm
Run Code Online (Sandbox Code Playgroud) 我想将代码中的线程绑定到每个物理核心.使用GCC我已成功完成此操作,sched_setaffinity因此我不再需要设置export OMP_PROC_BIND=true.我想在Windows中使用MSVC做同样的事情.Windows和Linux使用不同的线程拓扑.当Windows使用紧凑形式时,Linux会分散线程.换句话说,在具有四个内核和八个超线程的Linux中,我只需要将线程绑定到前四个处理单元.在Windows中,我将它们设置为每个其他处理单元.
我已成功完成此操作SetProcessAffinityMask.当我右键单击进程并单击"Set Affinity"时,我可以从Windows Task Manger中看到每个其他CPU都已设置(我的8个超线程系统上的0,2,4,6).问题是我运行时代码的效率不稳定.有时它几乎不变,但大部分时间都有很大的变化.我把优先级改为高,但没有区别.在Linux中,效率是稳定的.也许Windows还在迁移线程?在Windows中绑定线程还需要做些什么吗?
这是我正在使用的代码
#ifdef _WIN32
HANDLE process;
DWORD_PTR processAffinityMask = 0;
//Windows uses a compact thread topology. Set mask to every other thread
for(int i=0; i<ncores; i++) processAffinityMask |= 1<<(2*i);
//processAffinityMask = 0x55;
process = GetCurrentProcess();
SetProcessAffinityMask(process, processAffinityMask);
#else
cpu_set_t mask;
CPU_ZERO(&mask);
for(int i=0; i<ncores; i++) CPU_SET(i, &mask);
sched_setaffinity(0, sizeof(mask), &mask);
#endif
Run Code Online (Sandbox Code Playgroud)
编辑:这是我现在使用的代码,它似乎在Linux和Windows上稳定
#ifdef _WIN32
HANDLE process;
DWORD_PTR processAffinityMask;
//Windows uses a compact thread topology. Set mask to every other …Run Code Online (Sandbox Code Playgroud)