CPU 中的乱序执行意味着 CPU 可以重新排序指令以获得更好的性能,这意味着 CPU 必须做一些非常漂亮的簿记等。还有其他处理器方法,例如超线程。
一些花哨的编译器在有限的程度上理解指令的(非)相关性,并且会自动交错指令流(可能在比 CPU 看到的窗口更长的窗口中)以更好地利用处理器。浮点和整数指令的故意编译时交错是另一个例子。
现在我有高度并行的任务。而且我通常有一个没有超线程的老化单核 x86 处理器。
是否有一种直接的方法可以让我的“for”循环的主体交错进行这个高度并行的任务,以便两个(或更多)迭代一起完成? (这与我理解的“循环展开”略有不同。)
我的任务是运行一组指令的“虚拟机”,为了说明,我将真正简化为:
无效运行(int num){
for(int n=0; n vm_t 数据(n);
for(int i=0; i data.insn(i).parse();
data.insn(i).eval();
}
}
}
所以执行轨迹可能如下所示:
数据(1)insn(0)解析
数据(1)insn(0)评估
数据(1)insn(1)解析
...
数据(2)insn(1)评估
数据(2)insn(2)解析
数据(2)insn(2)评估
现在,我想要的是能够显式地并行执行两个(或更多)迭代:
数据(1)insn(0)解析
data(2) insn(0) parse\processor 可以做 OOO 因为这两个流入
数据(1)insn(0)评估/
data(2) insn(0) eval\OOO 机会也在这里
数据(1)insn(1)解析/
数据(2)insn(1)解析
我知道,从分析中(例如,将 Callgrind 与 --simulate-cache=yes 一起使用),解析是关于随机内存访问(缓存丢失),而 eval 是关于在寄存器中执行操作,然后将结果写回。每一步都有几千条指令。因此,如果我可以将两个步骤混合在一起进行两次迭代,那么处理器有望在解析步骤的缓存未命中发生时有所作为...
是否有一些 C++ 模板疯狂来生成这种显式并行性?
当然,我可以在代码中对自己进行交织——甚至是惊人的——但它使代码的可读性大大降低。如果我真的想要不可读,我可以做汇编!但这种事情肯定有某种模式吗?
最佳答案
听起来您遇到了芯片设计人员面临的相同问题:执行一条指令需要付出很多努力,但它涉及到一系列不同的步骤,这些步骤可以串连在 execution pipeline 中。 (当您可以从单独的硬件块中构建它们时,并行执行事物会更容易。)
最明显的方法是将每个任务拆分为不同的线程。您可能希望创建一个线程来执行每条指令直到完成,或者为两个执行步骤中的每一个创建一个线程并在它们之间传递数据。无论哪种情况,您都必须非常小心如何在线程之间共享数据,并确保处理一条指令影响下一条指令结果的情况。即使您只有一个内核并且在任何给定时间只能运行一个线程,您的操作系统也应该能够调度计算密集型线程,而其他线程正在等待它们的缓存未命中。
(花费几个小时的时间可能会为一台速度非常快的计算机买单,但是如果您试图在廉价硬件上广泛部署它,那么以您看待问题的方式来考虑问题可能是有意义的。无论如何,这是一个需要考虑的有趣问题。)