我试图分析英特尔Haswell的CPU(英特尔®酷睿™i7-4900MQ)与自上而下的微架构分析方法(TMAM),在各章B.1和B.4所述,在执行英特尔®64和IA-32架构优化参考手册.(如果需要,我将B.4中描述的Sandy Bridge公式调整为Haswell Microarchitecture.)
因此,我使用Perf执行性能计数器事件测量.有些结果我不明白:
CPU_CLK_UNHALTED.THREAD_P < CYCLE_ACTIVITY.CYCLES_LDM_PENDING
这仅适用于少数测量,但仍然很奇怪.PMU计数是否会停止CYCLE_ACTIVITY.CYCLES_LDM_PENDING?
CYCLE_ACTIVITY.CYCLES_L2_PENDING> CYCLE_ACTIVITY.CYCLES_L1D_PENDING
和CYCLE_ACTIVITY.STALLS_L2_PENDING>CYCLE_ACTIVITY.STALLS_L1D_PENDING这适用于所有测量.当L1D高速缓存未命中时,负载会转移到L2高速缓存,对吧?因此早先错过L2的负载也错过了L1.这里没有计算L1指令高速缓存,但是它的大小*_L2_PENDING是100倍甚至1000倍*_L1D_PENDING,可能不是这样.是否分别以某种方式测量了档位/周期?但是有这个公式:
%L2_Bound =
(CYCLE_ACTIVITY.STALLS_L1D_PENDING - CYCLE_ACTIVITY.STALLS_L2_PENDING) / CLOCKS
因此CYCLE_ACTIVITY.STALLS_L2_PENDING< CYCLE_ACTIVITY.STALLS_L1D_PENDING假定(公式的结果必须为正).(这个公式的另一个原因是它可能应该CYCLES代替STALLS.但是这不能解决上面描述的问题.)那么如何解释呢?
编辑:我的操作系统:Ubuntu 14.04.3 LTS,内核:3.13.0-65-通用x86_64,性能版本:3.13.11-ckt26
Linux内核:4.10.0-20-generic(也在4.11.3上试过)
Ubuntu:17.04
我一直试图使用收集内存访问的统计信息perf stat.我能够收集内存存储的统计信息,但内存加载的计数返回0值.
以下是内存存储的详细信息: -
perf stat -e cpu/mem-stores/u ./libquantum_base.arnab 100
N = 100, 37 qubits required
Random seed: 33
Measured 3277 (0.200012), fractional approximation is 1/5.
Odd denominator, trying to expand by 2.
Possible period is 10.
100 = 4 * 25
Performance counter stats for './libquantum_base.arnab 100':
158,115,510 cpu/mem-stores/u
0.559922797 seconds time elapsed
Run Code Online (Sandbox Code Playgroud)
对于内存加载,我得到0计数,如下所示: -
perf stat -e cpu/mem-loads/u ./libquantum_base.arnab 100
N = 100, 37 qubits required
Random seed: …Run Code Online (Sandbox Code Playgroud) RESOURCE_STALLS.RSIntel Broadwell 硬件性能事件的描述如下:
此事件对由于保留站 (RS) 中缺少合格条目而导致的停顿周期进行计数。这可能是由于 RS 溢出,或由于 RS 阵列写入端口分配方案导致的 RS 解除分配(每个 RS 条目有两个写入端口而不是四个。因此,无法使用空条目,尽管 RS 并未真正满) . 这计算管道后端阻止来自前端的 uop 传递的周期。
这基本上说有两种情况会发生 RS 停顿事件:
在第一种情况下,“合格”是什么意思?这是否意味着并非所有条目都可以被各种 uop 占用?因为我的理解是,在现代微体系结构中,任何条目都可以被任何类型的 uop 使用。还有什么是 RS 阵列写入端口分配方案,即使并非所有条目都被占用,它如何导致 RS 停顿?这是否意味着 Haswell 中有四个写端口,而现在 Broadwell 中只有两个?即使手册没有明确说明,这两种情况是否适用于 Skylake 或 Haswell?
在Linux中,只要分支了一个进程,父进程的内存映射就会被克隆到子进程中。实际上,出于性能原因,这些页面被设置为写时复制 -最初它们是共享的,并且如果两个进程之一在其中之一上进行写操作,则将其克隆(MAP_PRIVATE)。
这是获取正在运行的程序状态的快照的一种非常常见的机制-您进行了分叉,这使您可以在该时间点(一致)查看进程的内存。
我做了一个简单的基准测试,其中包含两个部分:
在某些情况下(机器/体系结构/内存位置/线程数/ ...),我能够比线程写入数组早得多地完成复制。
但是,当子进程退出时,htop我仍然可以看到大部分CPU时间都花在了内核上,这与它在父进程写入页面时用于处理写时复制是一致的。
以我的理解,如果标记为写时复制的匿名页面是由单个进程映射的,则不应复制该页面,而应直接使用它。
我如何确定这确实是在复制内存上花费的时间?
如果我是对的,如何避免这种开销?
在现代 C ++ 中,基准测试的核心如下。
定义WITH_FORK以启用快照;保留undefined可禁用子进程。
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <numaif.h>
#include <numa.h>
#include <algorithm>
#include <cassert>
#include <condition_variable>
#include <mutex>
#include <iomanip>
#include <iostream>
#include <cmath>
#include <numeric>
#include <thread>
#include <vector>
#define ARRAY_SIZE 1073741824 // 1GB …Run Code Online (Sandbox Code Playgroud) 单线程内的代码具有一定的内存保证,例如先读后写(即将一些值写入内存位置,然后读回它应该给出您写入的值)。
如果线程被重新安排在不同的 CPU 核心上执行,这样的内存保证会发生什么?假设一个线程将 10 写入内存位置 X,然后重新调度到不同的核心。该核心的 L1 缓存可能具有不同的 X 值(与之前在该核心上执行的另一个线程不同),因此现在读取 X 不会像线程期望的那样返回 10。当线程被调度到不同的核心上时,是否会发生一些 L1 缓存同步?
multithreading operating-system cpu-architecture memory-barriers cpu-cache
CPU使用分支预测来加速代码,但仅限于实际采用第一个分支.
为什么不简单地采取两个分支?也就是说,假设两个分支都将被命中,缓存两侧,并在必要时采取适当的分支.缓存不需要无效.虽然这需要编译器预先加载两个分支(更多的内存,适当的布局等),但我认为适当的优化可以简化两者,以便可以从单个预测器获得接近最优的结果.也就是说,需要更多的内存来加载两个分支(对于N个分支是指数的),大多数时候应该能够在完成执行分支之前足够快地用新代码"重新缓存"失败的分支. .
if(x)Bl else Br;
不假设采用Bl,而是假设采用Bl和Br(某种类型的并行处理或特殊交织),并且在实际确定分支之后,一个分支随后无效,然后可以释放缓存以供使用(可能是一些需要特殊技术的类型才能正确填写和使用它.
实际上,不需要预测电路,并且所有用于此的设计可以用于处理两个分支.
任何想法,如果这是可行的?
cpu cpu-architecture prefetch speculative-execution branch-prediction
根据一些操作系统的教科书,为了更快地进行上下文切换,人们在TLB标签字段中为每个进程添加了ASID,因此我们不需要在上下文切换中刷新整个TLB。
我听说有些ARM处理器和MIPS处理器在TLB中确实具有ASID。但是我不确定Intel x86处理器是否具有ASID。
同时,似乎ASID通常具有比PID(32位)少的位(例如8位)。那么,如果在上述8位ASID情况下内存中的进程比2 ^ 8多,那么系统如何处理“ ASID溢出”?
我有一本书的声明:
在全关联 TLB 中实现 LRU 非常昂贵,所以一般的方法是使用随机替换。
我不明白为什么在完整的关联缓存下它很昂贵。这不就是增加了一个额外的参考位......?
特定向量(未屏蔽)发生硬件中断,CPU 检查 IF 标志并将 RFLAGS、CS 和 RIP 压入堆栈,同时后端仍有指令完成,其中一条指令的分支预测结果是错误的。通常管道会被刷新,前端开始从正确的地址获取,但在这种情况下,中断正在进行中。
我已经读过这篇文章,显然解决方案是立即刷新管道中的所有内容,这样就不会发生这种情况,然后生成指令将 RFLAGS、CS、RIP 推送到 TSS 中内核堆栈的位置;然而,问题出现了,它如何知道与最新架构状态关联的 (CS:)RIP,以便能够将其推送到堆栈上(假设前端 RIP 现在将领先)。这类似于 port0 上的采取分支执行单元如何知道当采取预测结果错误时应该获取的 (CS:)RIP 的问题——是编码到指令中的地址以及预言?当你想到陷阱/异常时,也会出现同样的问题,CPU需要将当前指令(故障)或下一条指令(陷阱)的地址推送到内核堆栈,但是它是如何计算出这条指令的地址的当它处于管道的中途时——这让我相信地址必须被编码到指令中并使用长度信息计算出来,这可能全部在预解码阶段完成。
pipeline intel cpu-architecture interrupt-handling branch-prediction
我试图理解性能事件的含义:dTLB 加载和 dTLB 存储?