我在SSE 4.2和AVX 2的2个向量之间矢量化了点积,如下所示.该代码使用GCC 4.8.4和-O2优化标志进行编译.正如预期的那样,两者的性能都有所提高(和AVX 2比SSE 4.2快),但是当我用PAPI分析代码时,我发现未命中的总数(主要是L1和L2)增加了很多:
没有矢量化:
PAPI_L1_TCM: 784,112,091
PAPI_L2_TCM: 195,315,365
PAPI_L3_TCM: 79,362
Run Code Online (Sandbox Code Playgroud)
使用SSE 4.2:
PAPI_L1_TCM: 1,024,234,171
PAPI_L2_TCM: 311,541,918
PAPI_L3_TCM: 68,842
Run Code Online (Sandbox Code Playgroud)
使用AVX 2:
PAPI_L1_TCM: 2,719,959,741
PAPI_L2_TCM: 1,459,375,105
PAPI_L3_TCM: 108,140
Run Code Online (Sandbox Code Playgroud)
我的代码可能有问题或者这种行为是否正常?
AVX 2代码:
double vec_dotProduct(const vec& vecs, const unsigned int& start_a, const unsigned int& start_b, const int& n) {
double dot = 0;
register int i = 0;
const int loopBound = n-3;
__m256d vsum, vecPi, vecCi, vecQCi;
vsum = _mm256_set1_pd(0);
double * const pA = vecs.x+start_a ;
double * const …Run Code Online (Sandbox Code Playgroud) 我正在开发一个项目,我们必须实现一个在理论上被证明是缓存友好的算法.简单来说,如果N是输入,并且B是每次我们有高速缓存未命中时在高速缓存和RAM之间传输的元素数,则该算法将需要O(N/B)访问RAM.
我想表明这确实是实践中的行为.为了更好地理解如何测量各种缓存相关的硬件计数器,我决定使用不同的工具.一个是Perf,另一个是PAPI库.不幸的是,我使用这些工具越多,我就越不了解他们的确切做法.
我正在使用Intel(R)Core(TM)i5-3470 CPU @ 3.20GHz,8 GB RAM,L1缓存256 KB,L2缓存1 MB,L3缓存6 MB.缓存行大小为64字节.我猜这必须是块的大小B.
我们来看下面的例子:
#include <iostream>
using namespace std;
struct node{
int l, r;
};
int main(int argc, char* argv[]){
int n = 1000000;
node* A = new node[n];
int i;
for(i=0;i<n;i++){
A[i].l = 1;
A[i].r = 4;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
每个节点需要8个字节,这意味着一个缓存行可以容纳8个节点,所以我应该期待大约1000000/8 = 125000L3缓存未命中.
没有优化(否-O3),这是perf的输出:
perf stat -B -e cache-references,cache-misses ./cachetests
Performance counter stats for …Run Code Online (Sandbox Code Playgroud) 我问自己,衡量并行程序性能(触发器)的最佳方法是什么.我读到了papi_flops.这似乎适用于串行程序.但我不知道如何衡量并行程序的整体性能.
我想测量blas/lapack函数的性能,在我的gemm下面的例子中.但我也想测量其他功能,特别是功能不知道操作次数的地方.(在gemm的情况下,ops是已知的(ops(gemm)= 2*n ^ 3),因此我可以根据操作次数和执行时间计算性能.)库(我正在使用Intel MKL)自动生成线程.所以我不能单独测量每个线程的性能然后减少它.
这是我的例子:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "mkl.h"
#include "omp.h"
#include "papi.h"
int main(int argc, char *argv[] )
{
int i, j, l, k, n, m, idx, iter;
int mat, mat_min, mat_max;
int threads;
double *A, *B, *C;
double alpha =1.0, beta=0.0;
float rtime1, rtime2, ptime1, ptime2, mflops;
long long flpops;
#pragma omp parallel
{
#pragma omp master
threads = omp_get_num_threads();
}
if(argc < 4){
printf("pass me 3 arguments!\n");
return( -1 );
} …Run Code Online (Sandbox Code Playgroud) 我想进入PAPI.我在Debian GNU/Linux上有5.3.2.0版.papi_avail只是告诉我没有可用的硬件事件:
$ papi_avail
Available events and hardware information.
--------------------------------------------------------------------------------
PAPI Version : 5.3.2.0
Vendor string and code : GenuineIntel (1)
Model string and code : Intel(R) Core(TM) i3-5010U CPU @ 2.10GHz (61)
CPU Revision : 4.000000
CPUID Info : Family: 6 Model: 61 Stepping: 4
CPU Max Megahertz : 2100
CPU Min Megahertz : 500
Hdw Threads per core : 2
Cores per Socket : 2
Sockets : 1
NUMA Nodes : 1
CPUs per Node : …Run Code Online (Sandbox Code Playgroud) 我试图了解分支预测单元如何在 CPU 中工作。
我已经使用了papilinux,perf-events但它们都没有给出准确的结果(就我而言)。
这是我的代码:
void func(int* arr, int sequence_len){
for(int i = 0; i < sequence_len; i++){
// region starts
if(arr[i]){
do_sth();
}
// region ends
}
}
Run Code Online (Sandbox Code Playgroud)
我的数组由 0 和 1 组成。它有一个大小为 的图案sequence_len。例如,如果我的尺码是 8,那么它有一个图案0 1 0 1 0 0 1 1或类似的图案。
试验 1:
我试图了解 CPU 如何预测这些分支。因此,我使用 papi 并为错误预测的分支预测设置了性能计数器(我知道它也计算间接分支)。
int func(){
papi_read(r1);
for(){
//... same as above
}
papi_read(r2);
return r2-r1;
}
int main(){
init_papi();
for(int i = 0; i < …Run Code Online (Sandbox Code Playgroud) 在运行Linux的Intel或AMD x86-64系统上,我在哪里/如何找到我的CPU具有的硬件性能计数器的数量?
我想perf在执行某些应用程序时使用Linux 工具收集硬件性能计数器数据.perf wiki的教程说如果我指定(使用-e标志perf stat或者perf record)更多硬件事件而不是我的CPU中的性能计数器,那么这些事件将在执行期间在计数器上多路复用,允许在单个事件期间跟踪它们.perf命令,但可能会降低准确性,因为并非所有计数器始终处于活动状态.(请注意,我关注这里的硬件事件,例如缓存和TLB行为 - 我知道可以跟踪大量/无限数量的内核软件跟踪点而不会出现不准确).
如果我找到我的处理器型号,是否有英特尔/ AMD网站,我可以在哪里找到这些信息?是否有一个简单的命令可以在系统上运行以检查硬件计数器的数量?我检查了cat /proc/cpuinfo和的输出x86info -a,但是找不到这些信息.
我正在测试一些内在操作的行为.当我注意到_mm_mfence()从用户空间发出加载指令时,我感到很惊讶,但它不计入L1数据缓存 - 未命中,命中或填充缓冲区命中.我正在使用papi的本机事件(如MEM_INST_RETIRED和MEM_LOAD_RETIRED)来读取性能计数器.这段代码:
for(int i=0; i < 1000000; i++){
_mm_mfence();
}
Run Code Online (Sandbox Code Playgroud)
计数ALL_LOADS:737030,L1_HIT:99,L1_MISS:10,FB_HIT:25.虽然没有mfence,读取计数器的开销是这样的:ALL_LOADS:125,L1_HIT:94,L1_MISS:11,FB_HIT:24
我查了一下,sfence和lfence没有这种影响.我正在使用-O3进行编译.从编译文件我想它调用__builtin_ia32_mfence函数,但我找不到它.
我一般都了解_mm_mfence()的作用以及我们使用它的原因,但现在问题更多的是它是如何工作的.如果有人能够解释或给出任何相关文章来理解这种行为,那将是很棒的.
PAPI_L1_LDMpapi和L1-dcache-load-missesperf有什么区别?
我使用了相同的设置,例如此处的帖子。
因此,结果我得到了木瓜籽:
PAPI_L1_DCM: 515 <- L1 data cache miss (probably L1D_READ_MISSES_ALL + L1D_READ_MISSES_RETRIED?)
PAPI_L1_ICM: 300 <- L1 Instruction cache miss
PAPI_L1_LDM: 441 <- L1 Load data miss
PAPI_L1_TCM: 815 <- L1 Total cache miss
Run Code Online (Sandbox Code Playgroud)
不幸的PAPI_L1_DCA是,这台机器不支持。
对于perf(仅在用户空间中,因为papi仅测量用户空间,而没有内核空间):调用: perf stat -B -e L1-dcache-load-misses:u,cache-misses:u ./perf
16,539 L1-dcache-load-misses
128 cache-misses:u
Run Code Online (Sandbox Code Playgroud)
16,539似乎更合理N=1000000。装入数据丢失(在papi中为PAPI_L1_LDM)和数据缓存未命中(在papi中为PAPI_L1_DCM)之间有什么区别?为什么这些数字在papi和perf中有所不同?是cache-misses:u在PERF有关L2缓存缺失?
编辑:硬件(至强E5-2600 v3系列,Haswell-EP 12核)
我试图在激活跟踪系统(extrae)的情况下运行COMPS.我第一次遇到安装问题但我解决了这个问题:
如何修复libpapi.so.*运行时不能打开共享对象文件(py)带跟踪的COMPS?
但是,现在我正面临一个新的PAPI问题.COMPS运行时似乎已正确加载但Extrae报告此错误:
Extrae: Error! Hardware counter PAPI_L3_TCM (0x80000008) cannot be added in set 1 (thread 0)
Extrae: Error! Hardware counter PAPI_FP_INS (0x80000034) cannot be added in set 1 (thread 0)
Extrae: Error! Hardware counter PAPI_SR_INS (0x80000036) cannot be added in set 2 (thread 0)
Extrae: Error! Hardware counter PAPI_BR_UCN (0x8000002a) cannot be added in set 2 (thread 0)
Extrae: Error! Hardware counter PAPI_BR_CN (0x8000002b) cannot be added in set 2 (thread 0)
Extrae: Error! Hardware counter PAPI_VEC_SP (0x80000069) cannot …Run Code Online (Sandbox Code Playgroud) 我正在使用PAPI库来调整和分析我的应用程序。
我想知道(PAPI_REF_CYC:参考时钟周期)的实际含义是什么?
提前致谢,