分析C程序功能的缓存命中率

如何解决分析C程序功能的缓存命中率

我想获取在Linux机器上运行的C / C ++程序( foo )的特定功能的高速缓存命中率。我正在使用gcc并且没有编译器优化。使用 perf ,我可以使用以下命令获得整个程序的命中率。

性能统计-e L1-dcache-loads,L1-dcache-load-misses,L1-dcache-stores,L1-dcache-store-misses ./a.out

但是我只对内核 foo 感兴趣。

是否可以使用 perf 或任何其他工具来仅获取 foo 的点击率?

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>


#define NI 192
#define NJ NI

#ifndef DATA_TYPE
    #define DATA_TYPE float
#endif


static 
void* xmalloc(size_t num)
{
    void * nnew = NULL;
    int ret = posix_memalign (&nnew,32,num);
    if(!nnew || ret)
    {
        fprintf(stderr,"Can not allocate Memory\n");
        exit(1);
    }
    return nnew;
}

void* alloc_data(unsigned long long int n,int elt_size)
{
    size_t val = n;
    val *= elt_size;
    void* ret = xmalloc(val);
    return ret;
}


/* Array initialization. */
static
void init_array(int ni,int nj,DATA_TYPE A[NI][NJ],DATA_TYPE R[NJ][NJ],DATA_TYPE Q[NI][NJ])
{
  int i,j;

  for (i = 0; i < ni; i++)
    for (j = 0; j < nj; j++) {
      A[i][j] = ((DATA_TYPE) i*j) / ni;
      Q[i][j] = ((DATA_TYPE) i*(j+1)) / nj;
    }
  for (i = 0; i < nj; i++)
    for (j = 0; j < nj; j++)
      R[i][j] = ((DATA_TYPE) i*(j+2)) / nj;
}


/* Main computational kernel.*/

static
void foo(int ni,j,k;

  DATA_TYPE nrm;
  for (k = 0; k < nj; k++)
  {
    nrm = 0;
    for (i = 0; i < ni; i++)
      nrm += A[i][k] * A[i][k];
    R[k][k] = sqrt(nrm);
    for (i = 0; i < ni; i++)
      Q[i][k] = A[i][k] / R[k][k];
    for (j = k + 1; j < nj; j++)
    {
      R[k][j] = 0;
      for (i = 0; i < ni; i++)
        R[k][j] += Q[i][k] * A[i][j];
      for (i = 0; i < ni; i++)
        A[i][j] = A[i][j] - Q[i][k] * R[k][j];
    }
  }
}


int main(int argc,char** argv)
{
  /* Retrieve problem size. */
  int ni = NI;
  int nj = NJ;

  /* Variable declaration/allocation. */
  DATA_TYPE (*A)[NI][NJ];
  DATA_TYPE (*R)[NI][NJ];
  DATA_TYPE (*Q)[NI][NJ];

  A = ((DATA_TYPE (*)[NI][NJ])(alloc_data((NI*NJ),(sizeof(DATA_TYPE)))));
  R = ((DATA_TYPE (*)[NI][NJ])(alloc_data((NI*NJ),(sizeof(DATA_TYPE)))));
  Q = ((DATA_TYPE (*)[NI][NJ])(alloc_data((NI*NJ),(sizeof(DATA_TYPE)))));
  
/* Initialize array(s). */
  init_array (ni,nj,(*A),(*R),(*Q));


  /* Run kernel. */
  foo (ni,*A,*R,*Q);

  /* Be clean. */
  free((void *)A);
  free((void *)R);
  free((void *)Q);

  return 0;
}

lscpu命令的输出为:

Architecture:          x86_64
CPU op-mode(s):        32-bit,64-bit
Byte Order:            Little Endian
CPU(s):                16
On-line CPU(s) list:   0-15 
Thread(s) per core:    2
Core(s) per socket:    8
Socket(s):             1
NUMA node(s):          1
Vendor ID:             GenuineIntel 
CPU family:            6
Model:                 63
Model name:            Intel(R) Core(TM) i7-5960X CPU @ 3.00GHz
Stepping:              2
CPU max MHz:           3500.0000
CPU min MHz:           1200.0000
L1d cache:             32K
L1i cache:             32K
L2 cache:              256K
L3 cache:              20480K
NUMA node0 CPU(s):     0-15

解决方法

您也可以使用 Likwid 及其 Marker-API。它使检测代码的某些区域变得非常容易。您可以在 haswell 架构上使用预定义的性能组 ICACHE 来确定 L1 缓存未命中率,或者为 L1 命中率定义您自己的性能组。

#include likwid.h
LIKWID_MARKER_INIT;
LIKWID_MARKER_START("region foo");

foo();

LIKWID_MARKER_STOP("region foo");
LIKWID_MARKER_CLOSE;

运行应用程序:

./likwid-perfctr -g ICACHE -m <your application>

确保使用 -DLIKWID-PERFMON 编译并添加 Likwid 包含和库路径并链接 Likwid 库:-L$LIKWID_LIB -I$LIKWID_INCLUDE -llikwid。 一切都在他们的 github wiki

上得到了很好的记录 ,

您可能对gprof(1)感兴趣。它不会衡量缓存的命中率(这没有意义,因为一旦启用了优化功能,一旦调用GCC,可能会内嵌对foo的某些调用)。

您可以在代码中使用libbacktrace。另请参见time(7)signal(7)

您可以在其中使用gcc -Wall -Wextra -O2 -g -pg编译代码,然后在其中使用libbacktrace(例如GCCRefPerSys),然后在gprof(1)中使用{{ 3}}。

通过努力(因此先读gdb(1)然后读Advanced Linux Programmingsyscalls(2)),您可以将signal-safety(7)setitimer(2)和/或sigaction(2)一起使用。 / p>

还考虑生成一些C代码(例如,在您自己的C代码生成器中使用profil(3)和/或GPP)并查看GNU bison。 J.Pitrat的书this answer(ISBN-13:978-1848211018)可能是鼓舞人心的。您可能需要生成一些C代码以进行额外的检测。

您可能会在运行时在插件中生成一些代码(例如,使用Artificial Beings: the Conscience of a Conscious Machinelibgccjit ...),然后GNU lightningdlopen(3)。阅读有关dlsym(3)的更多信息,并查看我的partial evaluation示例,更认真地查看manydl.cOcaml的源代码。

您可以编写自己的SBCL以比GCC的-pg选项更聪明的方式自动生成一些测量值。您的GCC插件会将大多数函数调用(在GCC plugin级别上转换为更复杂的东西,从而进行一些基准测试(这是-pg在GCC内部的工作方式,您可以研究GCC的源代码)。尝试将foo.c编译为gcc -Wall -Wextra -O2 -pg -S -fverbose-asm foo.c,并查看生成的foo.s,也许添加更多的GIMPLEoptimizationsstatic analysis选项。>

您可能对instrumentation的最新论文感兴趣。

最后,对未经优化的 编译的C程序进行基准测试毫无意义。考虑改用至少gcc -flto -O2 -Wall

编译和链接程序

foo中,您可以巧妙地使用ACM SIGPLAN来测量CPU时间。

如果性能非常重要,并且允许您花费数周的时间对其进行改进,则可以考虑使用clock_gettime(2)(或也许OpenCL)在功能强大的GPGPU上计算内核。当然,您需要专用的硬件。否则,请考虑使用CUDAOpenMP(或者也许使用OpenACC)。一些最近的GCC编译器(至少在2020年10月为MPI)可以支持这些。当然,请阅读GCC 10 上的文档。

,

首先,请注意,处理器不支持L1-dcache-store-missesperf stat将在输出中告诉您。

perf stat不允许您仅分析选定的代码区域。为此,您必须手动检测代码,以便根据需要在感兴趣的区域周围控制指定的事件。

如果不在处理器上进行多路复用(Haswell),就不可能对事件L1-dcache-loadsL1-dcache-load-missesL1-dcache-stores进行计数。它们分别映射到本地事件MEM_UOPS_RETIRED.ALL_LOADSL1D.REPLACEMENTMEM_UOPS_RETIRED.ALL_STORES。这些事件中的每一个都只能计入前四个通用计数器。此外,i7-5960X的规范更新文档中未记录该错误,而i7-5960X中存在此错误(在其他Haswell处理器和某些其他微体系结构的处理器的规范更新文档中记录了该错误)。在不同版本的perf中,此错误的处理方式有所不同。从内核版本4.1-rc7开始,如果在逻辑核心上启用了受错误影响的事件之一,并且在引导时启用了超线程,则逻辑核心最多只能使用其四个通用目的中的两个柜台。 MEM_UOPS_RETIRED.*事件是受该错误影响的事件之一。您可以做的一件事就是禁用超线程。

了解这些事件可以衡量哪种“缓存命中率”很重要。您可能不想测量没有意义的东西。可能有意义的一个比率是L1-dcache-load-misses /(L1-dcache-loads + L1-dcache-stores),它表示出于任何原因进行L1D替换的次数(高速缓存中填充的行导致其他人被逐出)除以退休负载和存储单位的数量。并非所有未命中都会导致更换,并且所有未命中的很大一部分都可能击中LFB,这也不会引起更换。同样,并非所有替换都是由uops的访问导致最终退出所导致的。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-