问题标签 [superscalar]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
multithreading - 超缩放与管道内衬性能
而超标量 CPU 通常也是流水线的。为什么流水线和超标量执行被认为是不同的性能增强技术?
parallel-processing - 为什么 ILP 架构中的名称依赖性(WaR、WaW)存在问题?
假设以下两条指令同时执行:
这是一种反依赖,或读后写。假设它们同时执行,在第二条指令写回之前,第一条指令是否仍会读取正确的值$t1
?
至于输出依赖,或 Write-after-Write:
我明白为什么这是有问题的,我无法想象谁会“赢”,如果有的话。我的意思是我们说的是指令级并行性,所以理论上我想在第二条指令可以写入之前会有一个 NOP$t0
吗?在这种情况下,如果另一条指令想要在第二条指令再次写入之前从 $t0 读取,当然还有“丢失”周期,我只会看到问题。
所以真的,我的问题是:为什么读后写有问题?是不是因为在指令解码过程中,不同的地址可能会被加载到 $t1 中?
mips - 具有两个执行单元的超标量处理器的六级流水线
在设计带有两个执行单元的超标量处理器的六级流水线时需要帮助。六个阶段是指令获取 ( IF
)、指令解码 ( ID
)、从寄存器读取 ( RR
)、2 周期执行 ( EX
)、回写结果 ( WB
)。说明不能重新排序。在一个执行周期中,最多发出一条指令可能与内存(加载或存储)相关,并且最多一条指令可能与处理寄存器算术运算的非内存指令有关。Latency
Load 操作为 3 个周期,其他操作为 2 个周期。Latency
被认为是相关指令发出周期之间的时间延迟周期。现在,我们有以下指令序列:
考虑到一条指令从 RR 阶段传递到 EX 阶段时,程序需要多长时间才能发出。
我的锻炼如下:
(1)和(3)、(2)和(3)、(2)和(8)、(2)和(8)、(6)和(7)中存在RAW冲突。因此,时序图是:
请评论解决方法。
assembly - 在预测现代超标量处理器上的操作延迟时需要考虑哪些因素,以及如何手动计算它们?
我希望能够手动预测任意算术(即没有分支或内存,尽管这也很好)x86-64 汇编代码在特定架构下将花费多长时间,同时考虑到指令重新排序、超标量、延迟、CPI 等。
必须遵循什么/描述的规则来实现这一点?
我想我已经弄清楚了一些初步的规则,但是我还没有找到任何关于将任何示例代码分解到这个细节级别的参考资料,所以我不得不做出一些猜测。(例如,英特尔优化手册甚至几乎没有提到指令重新排序。)
至少,我正在寻找(1)确认每条规则是正确的,或者是每条规则的正确陈述,以及(2)我可能已经忘记的任何规则的列表。
- 每个周期发出尽可能多的指令,从当前周期按顺序开始,并且可能远在重新排序缓冲区大小之前。
- 如果满足以下条件,则可以在给定周期上发出指令:
- 没有影响其操作数的指令仍在执行。和:
- 如果是浮点指令,则在它之前的每条浮点指令都已发出(浮点指令具有静态指令重新排序)。和:
- 在该周期有一个可用于该指令的功能单元。每个(?)功能单元都是流水线的,这意味着它每个周期可以接受 1 条新指令,并且总功能单元的数量是 1/CPI,对于给定功能类的 CPI(此处模糊:大概例如使用相同的
addps
功能subps
单位?如何确定?)。和: 4
本周期已发出少于超标量宽度(通常为 0条)的指令。
- 如果不能发出任何指令,处理器就不会发出任何指令——这种情况称为“停顿”。
例如,考虑以下示例代码(计算叉积):
我预测 Haswell 延迟的尝试如下所示:
performance - 在仔细的配置文件中解释荒谬的低测量延迟(超标量效应?)
我写了一些代码来分析小函数。在高层次上:
- 将线程亲和性设置为仅一个核心,并将线程优先级设置为最大。
通过执行以下 100 次计算统计信息:
- 估计什么都不做的函数的延迟。
- 估计测试功能的延迟。
- 从第二个中减去第一个以消除执行函数调用开销的成本,从而粗略地得到测试函数内容的成本。
要估计函数的延迟,它:
- 使缓存无效(这在用户模式下实际上很难做到,但我分配了一个 L3 大小的缓冲区并将其写入内存,这可能会有所帮助)。
- 产生线程,以便配置文件循环具有尽可能少的上下文切换。
- 从 a 获取当前时间
std::chrono::high_resolution_clock
(似乎编译为system_clock
, 但是)。 - 运行配置文件循环 100,000,000 次,在其中调用测试函数。
- 从 a 中获取当前时间
std::chrono::high_resolution_clock
并减去以获得延迟。
因为在这个级别上,单独的指令很重要,所以我们必须在任何时候编写非常仔细的代码,以确保编译器不会删除、内联、缓存或区别对待函数。我已经在各种测试用例中手动验证了生成的程序集,包括我在下面介绍的那个。
在某些情况下,我报告的延迟极低(亚纳秒)。我已经尝试了我能想到的一切来解决这个问题,但找不到错误。
我正在寻找解释这种行为的原因。为什么我的配置文件花费的时间如此之少?
让我们以计算 的平方根为例float
。
函数签名是float(*)(float)
,空函数是微不足道的:
让我们通过使用sqrtss
指令和乘以倒数平方根技巧来计算平方根。即,测试的功能是:
这是配置文件循环。同样,使用空函数和测试函数调用相同的代码:
sqrt_sseinstr(float)
我的Intel 990X的计时结果是 3.60±0.13 纳秒。在此处理器的额定 3.46 GHz 下,计算结果为 12.45±0.44 个周期。这似乎很准确,因为文档说延迟sqrtss
约为 13 个周期(此处理器的 Nehalem 架构没有列出它,但它似乎也可能在 13 个周期左右)。
更奇怪的计时结果sqrt_rcpsseinstr(float)
:0.01±0.07 纳秒(或 0.02±0.24 个周期)。除非发生其他影响,否则这是完全不可信的。
我想也许处理器能够在某种程度上或完美地隐藏被测函数的延迟,因为被测函数使用不同的指令端口(即超标量隐藏了一些东西)?我试图手动分析这个,但没有走得很远,因为我真的不知道我在做什么。
(注意:为了您的方便,我清理了一些汇编符号。objdump
整个程序的未经编辑的,包括其他几个变体,在这里,我暂时在这里托管二进制文件(x86-64 SSE2+,Linux)。)
问题又来了:为什么某些异形函数会产生难以置信的小值?如果是高阶效应,解释一下?
cpu - 超线程与超标量执行
想象一个超标量(多个执行单元)并且还具有超线程 (SMT) 支持的 CPU(或内核)。
为什么 CPU 可以真正并行执行的软件线程数通常是由它拥有的逻辑内核(即所谓的硬件线程)的数量给出的,而不是它拥有的执行单元的总数?
如果我的理解是正确的,SMT 实际上并没有启用真正的并行执行,它只是通过复制 CPU 的某些部分(那些存储架构状态而不是主要执行资源的部分)来使上下文切换更快/更有效。另一方面,超标量架构允许每个时钟周期真正同时执行多条指令,因为 CPU 具有多个执行单元,即多个并行流水线,每个流水线都可以以真正的并行方式处理单独的线程。
那么举个例子,如果一个 CPU 有 2 个核心,每个核心有 2 个执行单元,那么它的硬件并发(它真正可以并行执行的线程数)不应该是 4 个吗?当 SMT 实际上并没有启用真正的并行执行时,为什么它的硬件并发性是由逻辑内核的数量决定的呢?
java - 指令并行的奇怪风格
将字段复制到堆栈上是否会切断对其他操作的依赖?基本上允许该方法在使用指令级并行性在“背景”中计算下一个值时返回?