例如,在X86中,两个CPU内核运行不同的软件线程。
同时,这两个线程需要同时在其CPU内核上运行。
是否有办法同步这2个CPU内核/线程,或类似的方法以使它们(几乎)同时(在指令级别)开始运行?
使用共享变量rdtsc
在两个线程之间传递基于基础的期限。例如,设置一个最后期限,例如说当前rdtsc
值加上10,000。
然后让两个线程都旋转,rdtsc
等待直到当前值和阈值之间的差距rdtsc
小于阈值T
(T = 100应该很好)。最后,使用最终间隔值(即,截止日期rdtsc
值减去最后读取的rdtsc
值)跳入从属相加指令的序列,以使相加指令的数量等于间隔。
最后一步弥补了以下事实:每个芯片相对于其rdtsc
自旋环路通常不会“同相” 。例如,假设rdtsc
读取的背对背吞吐量为30个周期,则一个芯片可能会获得890、920、950等的读数,而另一个芯片可能会读取880、910、940等,因此如果出现以下情况,则会出现10或20个周期的错误rdtsc
单独使用。使用加法滑动补偿,如果最后期限为1,000,且阈值为100,则第一个线程将触发rdtsc == 920
并执行80个加法,而第二个线程将触发rdtsc == 910
并执行90个加法。原则上,然后两个内核都大致同步。
一些注意事项:
上面假设CPU频率等于标称rdtsc
频率-如果不是这种情况,则在计算跳转到添加幻灯片的位置时,您必须基于标称频率比真实频率给定应用补偿因子。
不要指望您的CPU长时间保持同步状态:诸如中断,可变延迟操作(如高速缓存未命中)之类的操作,或许多其他事情可能会使它们失去同步。
您希望所有有效负载代码以及附加幻灯片在每个内核的icache中都很热,否则它们很可能立即不同步。您可以通过在同步之前对该代码进行一次或多次虚拟运行来预热icache。
您希望T
足够大,以使间隙始终为正,因此比背对背rdtsc
延迟要大一些,但又不要大到增加添加幻灯片期间发生中断等事件的机会。
您可以通过在同步之后在“有效负载”代码中的各个点处发出rdtsc
或来检查“同步”的有效性,rdtscp
并查看记录的值在线程之间的接近程度。
完全不同的选择是使用Intel TSX:事务扩展。为两个要进行协调的线程进行组织,以同时读取事务区域内的共享线然后旋转,并让第三个线程写入共享线。这将导致两个等待线程中止。根据内核间的拓扑,两个等待线程可能会收到无效消息,因此随后的TSX几乎同时终止。从中止处理程序中调用要同步运行的代码。