- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
现代 x86 CPU 将传入的指令流分解为微操作 (uops1),然后在它们的输入准备就绪时调度这些 uops out-of-order。虽然基本思想很清楚,但我想知道如何安排就绪指令的具体细节,因为它会影响微优化决策。
以下面的玩具loop2为例:
top:
lea eax, [ecx + 5]
popcnt eax, eax
add edi, eax
dec ecx
jnz top
这基本上实现了循环(具有以下对应关系:
eax -> total, c -> ecx
):
do {
total += popcnt(c + 5);
} while (--c > 0);
我熟悉通过查看uop分解,依赖链延迟等来优化任何小循环的过程。在上面的循环中,我们只有一个携带的依赖链:
dec ecx
。循环的前三个指令(
lea
、
popcnt
、
add
)是依赖链的一部分,每个循环都从新开始。
dec
和
jne
被融合。所以我们总共有 4 个融合域 uops,一个只有循环携带的依赖链,延迟为 1 个周期。因此,根据该标准,循环似乎可以执行 1 次循环/迭代。
lea
可以在端口 1 和 5 上执行 add
可以在端口 0、1、5 和 6 上执行 jnz
在端口 6 上执行 lea
必须在端口 5 上执行(绝不能在端口 1 上执行) add
必须在端口 0 上执行,而不能在其他三个端口中的任何一个上执行 jnz
无论如何只能在端口 6 上执行 add
将进入端口 1、5 或 6,这将使
popcnt
、
lea
或 0x251812231341 延迟一个周期。类似的
jnz
可以去 2 个端口,一个与
lea
共享。
Intel(R) Architecture Code Analyzer Version - 2.1
Analyzed File - l.o
Binary Format - 64Bit
Architecture - HSW
Analysis Type - Throughput
Throughput Analysis Report
--------------------------
Block Throughput: 1.05 Cycles Throughput Bottleneck: FrontEnd, Port0, Port1, Port5
Port Binding In Cycles Per Iteration:
---------------------------------------------------------------------------------------
| Port | 0 - DV | 1 | 2 - D | 3 - D | 4 | 5 | 6 | 7 |
---------------------------------------------------------------------------------------
| Cycles | 1.0 0.0 | 1.0 | 0.0 0.0 | 0.0 0.0 | 0.0 | 1.0 | 0.9 | 0.0 |
---------------------------------------------------------------------------------------
N - port number or number of cycles resource conflict caused delay, DV - Divider pipe (on port 0)
D - Data fetch pipe (on ports 2 and 3), CP - on a critical path
F - Macro Fusion with the previous instruction occurred
* - instruction micro-ops not bound to a port
^ - Micro Fusion happened
# - ESP Tracking sync uop was issued
@ - SSE instruction followed an AVX256 instruction, dozens of cycles penalty is expected
! - instruction not supported, was not accounted in Analysis
| Num Of | Ports pressure in cycles | |
| Uops | 0 - DV | 1 | 2 - D | 3 - D | 4 | 5 | 6 | 7 | |
---------------------------------------------------------------------------------
| 1 | | | | | | 1.0 | | | CP | lea eax, ptr [ecx+0x5]
| 1 | | 1.0 | | | | | | | CP | popcnt eax, eax
| 1 | 0.1 | | | | | 0.1 | 0.9 | | CP | add edi, eax
| 1 | 0.9 | | | | | | 0.1 | | CP | dec ecx
| 0F | | | | | | | | | | jnz 0xfffffffffffffff4
它几乎反射(reflect)了我上面提到的必要的“理想”调度,有一个小偏差:它显示
popcnt
在 10 个周期中的 1 个周期中从
add
窃取端口 5。它也不知道融合的分支会去端口 6,因为它被预测采用,所以它将分支的大部分 uops 放在端口 0 上,而 0x2518122231343141 的大部分 uops 放在端口 6 上,而不是而不是反过来。
lea
和add
),如何决定选择哪个端口? add
)。令人困惑的是,我将转而使用
lea
作为我的“仅在一个端口上执行”指令,因为它有许多变体,包括 3 参数版本,允许您为源和目标使用不同的寄存器。这在尝试构建依赖链时非常方便。它还避免了
perf
所具有的整个“对目的地的不正确依赖”。
imul
原则上可以窃取
popcnt
所需的
add
或
p1
所需的 12 进制:
instr p0 p1 p5 p6
xor (elim)
imul X
add X X X X
dec X
top:
xor r9, r9
add r8, rdx
imul rax, rbx, 5
dec esi
jnz top
The results is that this executes with perfect scheduling at 1.00 cycles / iteration:
560,709,974 uops_dispatched_port_port_0 ( +- 0.38% )
1,000,026,608 uops_dispatched_port_port_1 ( +- 0.00% )
439,324,609 uops_dispatched_port_port_5 ( +- 0.49% )
1,000,041,224 uops_dispatched_port_port_6 ( +- 0.00% )
5,000,000,110 instructions:u # 5.00 insns per cycle ( +- 0.00% )
1,000,281,902 cycles:u
( +- 0.00% )
正如预期的那样,
imul
和
p6
分别被
p1
和
p6
充分利用,然后 0x2513 和 0x2513 之间大约有一半的可用端口可用。粗略地注意 - 实际比率是 56% 和 44%,并且这个比率在运行中非常稳定(注意
imul
变化)。如果我调整循环对齐,拆分会发生变化(32B 对齐为 53/46,32B+4 对齐更像是 57/42)。现在,除了循环中
dec/jnz
的位置外,我们什么都不改变:
top:
imul rax, rbx, 5
xor r9, r9
add r8, rdx
dec esi
jnz top
然后突然
add
/
+- 0.49%
拆分正好是 50%/50%,变化为 0.00%:
500,025,758 uops_dispatched_port_port_0 ( +- 0.00% )
1,000,044,901 uops_dispatched_port_port_1 ( +- 0.00% )
500,038,070 uops_dispatched_port_port_5 ( +- 0.00% )
1,000,066,733 uops_dispatched_port_port_6 ( +- 0.00% )
5,000,000,439 instructions:u # 5.00 insns per cycle ( +- 0.00% )
1,000,439,396 cycles:u ( +- 0.01% )
所以这已经很有趣了,但很难说到底发生了什么。也许确切的行为取决于循环入口处的初始条件,并且对循环内的排序很敏感(例如,因为使用了计数器)。这个例子表明正在发生的不仅仅是“随机”或“愚蠢”的调度。特别是,如果您只是从循环中消除
imul
指令,则会得到以下结果:
330,214,329 uops_dispatched_port_port_0 ( +- 0.40% )
314,012,342 uops_dispatched_port_port_1 ( +- 1.77% )
355,817,739 uops_dispatched_port_port_5 ( +- 1.21% )
1,000,034,653 uops_dispatched_port_port_6 ( +- 0.00% )
4,000,000,160 instructions:u # 4.00 insns per cycle ( +- 0.00% )
1,000,235,522 cycles:u ( +- 0.00% )
在这里,
p0
现在大致平均分配
p5
,
imul
和
add
分布 - 这样的
p0
的存在确实影响了
p1
调度:它不只是一个有些“避免端口1”规则的后果。
p5
是归零惯用语,在重命名器中被消除。让我们尝试使用 4 uop 的最大压力。我希望上面启动的任何机制也能够完美地安排它。我们只将
imul
更改为
add
,因此它不再是归零习语。我们得到以下结果:
top:
xor r9, r10
add r8, rdx
imul rax, rbx, 5
dec esi
jnz top
488,245,238 uops_dispatched_port_port_0 ( +- 0.50% )
1,241,118,197 uops_dispatched_port_port_1 ( +- 0.03% )
1,027,345,180 uops_dispatched_port_port_5 ( +- 0.28% )
1,243,743,312 uops_dispatched_port_port_6 ( +- 0.04% )
5,000,000,711 instructions:u # 2.66 insns per cycle ( +- 0.00% )
1,880,606,080 cycles:u ( +- 0.08% )
哎呀!而不是在
xor
均匀地安排一切,调度一直未得到充分利用
xor r9, r9
(它只是执行一些循环〜49%),因此
xor r9, r10
和
p0156
,因为他们正在执行的
p0
和
p1
他们都需要OPS的oversubcribed。我认为这种行为与 hayesti 在他们的回答中指出的基于计数器的压力指示器一致,并且在发布时将
uops 分配给端口,而不是在执行时 作为两者
p6
和一个
imul
被阻止进行一次迭代,它们将永远是比竞争的
dec/jnz
和
imul
指令更旧,所以应该总是先安排。我正在学习的一件事是,如果端口是在发布时分配的,则此规则无济于事,因为端口是在发布时预先确定的。我想它仍然有助于支持作为长依赖链一部分的指令(因为它们往往会落后),但这并不是我认为的万能药。
dec/jnz
分配的压力比实际压力更大,因为
xor
组合理论上可以在
add
上执行。事实上,因为分支被预测采用,它只会到达
p0
,但也许该信息无法提供给压力平衡算法,因此计数器往往会在
dec/jnz
上看到相等的压力,这意味着 0x2518122313432141 和 0x2518122313433241 周围的分布与最优不同。
p06
不是一个因素......
p6
而不是
p016
,但令人难以置信的是,_IACA 没有
support it_ !
最佳答案
由于以下几个原因,您的问题很棘手:
关于performance - x86 uops 究竟是如何调度的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40681331/
我有一个带有一些功能的perl对象。每个功能从主程序中调用一次。我想并行运行某些功能以节省时间。由于某些功能取决于先前功能的结果,因此我无法将它们全部一起运行。 我想到了这样的事情: 对于每个函数,保
首先,我的代码在这里: import schedule # see https://github.com/dbader/schedule import crawler def job(): p
从 11 月 1 日开始,我必须使用quartz调度程序每4个月安排一次任务。我使用 cronExpression 来实现同样的目的。但 cronExpression 每年都会重置。所以我的任务将在
我有以下代码块,它调用两个请求,但略有延迟。 final ActorRef actor1 = getContext().actorOf( ActorClass.prop
考虑到 Linux 的情况,我们为每个用户堆栈都有一个内核堆栈,据我所知,每当发生上下文切换时,我们都会切换到当前进程的内核模式。 这里我们保存当前进程的当前状态,寄存器,程序数据等,然后调度器(不确
我有将东西移植到 OpenBSD 的奇怪爱好。我知道它有 pthreads 问题,但在 2013 年 5 月发布版本之前我不会升级。我使用的是 5.0,我对 pthreads 还很陌生。我已经学习了
给定一组任务: T1(20,100) T2(30,250) T3(100,400) (execution time, deadline=peroid) 现在我想将截止日期限制为 Di = f * Pi
使用 Django 开发一个小型日程安排 Web 应用程序,在该应用程序中,人们被分配特定的时间与他们的上级会面。员工存储为模型,与表示时间范围和他们有空的星期几的模型具有 OneToMany 关系。
我想了解贪婪算法调度问题的工作原理。 所以我一直在阅读和谷歌搜索一段时间,因为我无法理解贪心算法调度问题。 我们有 n 个作业要安排在单个资源上。作业 (i) 有一个请求的开始时间 s(i) 和结束时
这是流行的 El Goog 问题的变体。 考虑以下调度问题:有 n 个作业,i = 1..n。有 1 台 super 计算机和无限的 PC。每个作业都需要先经过 super 计算机的预处理,然后再在P
假设我有一个需要运行多次的蜘蛛 class My_spider(Scrapy.spider): #spider def 我想做这样的事 while True: runner = Cra
我已将 podAntiAffinity 添加到我的 DeploymentConfig 模板中。 但是,pod 被安排在我预计会被规则排除的节点上。 我如何查看 kubernetes 调度程序的日志以了
我已经使用 React - Redux - Typescript 堆栈有一段时间了,到目前为止我很喜欢它。但是,由于我对 Redux 很陌生,所以我一直在想这个特定的话题。 调度 Redux 操作(和
我想按照预定的计划(例如,周一至周五,美国东部时间晚上 9 点至 5 点)运行单个 Azure 实例以减少账单,并且想知道最好的方法是什么。 问题的两个部分: 能否使用服务管理 API [1] 按预定
假设最小模块安装(为了简单起见),Drupal 的 index.php 中两个顶级功能的核心“职责”是什么? ? drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); me
我正在尝试使用 Racket(以前称为 PLT Scheme)连接 URL 调度。我查看了教程和服务器文档。我不知道如何将请求路由到相同的 servlet。 具体例子: #lang 方案 (需要网络服
我想在 Airflow (v1.9.0) 上运行计划。 我的DAG需要在每个月底运行,但我不知道如何编写设置。 my_dag = DAG(dag_id=DAG_ID, cat
我正在尝试在“httpTrigger”类型函数的 function.json 中设置计划字段,但计时器功能似乎未运行。我的目标是拥有一个甚至可以在需要时进行调度和手动启动的功能,而不必仅为了调度而添加
我正在尝试制定每周、每月的 Airflow 计划,但不起作用。有人可以报告可能发生的情况吗?如果我每周、每月进行安排,它就会保持静止,就好像它被关闭一样。没有错误信息,只是不执行。我发送了一个代码示例
我希望每两周自动更新一次我的表格。我希望我的函数能够被 firebase 调用。 这可能吗? 我正在使用 Angular 2 Typescript 和 Firebase。 最佳答案 仅通过fireba
我是一名优秀的程序员,十分优秀!