引子

<pre> public class L1CacheMiss1 { private static final int RUNS = 10; private static final int DIMENSION_1 = 1024 * 1024; private static final int DIMENSION_2 = 62; private static long[][] longs; public static void main(String[] args) throws Exception { Thread.sleep(10000); longs = new long[DIMENSION_1][]; for (int i = 0; i < DIMENSION_1; i++) { longs[i] = new long[DIMENSION_2]; for (int j = 0; j < DIMENSION_2; j++) { longs[i][j] = 0L; } } System.out.println("starting...."); final long start = System.nanoTime(); long sum = 0L; for (int r = 0; r < RUNS; r++) { for (int j = 0; j < DIMENSION_2; j++) { for (int i = 0; i < DIMENSION_1; i++) { sum += longs[i][j]; } } //for (int i = 0; i < DIMENSION_1; i++) { // for (int j = 0; j < DIMENSION_2; j++) { // sum += longs[i][j]; // } // } } System.out.println(sum); System.out.println("duration = " + (System.nanoTime() - start)); } } </pre>

<pre> public class L1CacheMiss2 { private static final int RUNS = 10; private static final int DIMENSION_1 = 1024 * 1024; private static final int DIMENSION_2 = 62; private static long[][] longs; public static void main(String[] args) throws Exception { Thread.sleep(10000); longs = new long[DIMENSION_1][]; for (int i = 0; i < DIMENSION_1; i++) { longs[i] = new long[DIMENSION_2]; for (int j = 0; j < DIMENSION_2; j++) { longs[i][j] = 0L; } } System.out.println("starting...."); final long start = System.nanoTime(); long sum = 0L; for (int r = 0; r < RUNS; r++) { //for (int j = 0; j < DIMENSION_2; j++) { // for (int i = 0; i < DIMENSION_1; i++) { // sum += longs[i][j]; // } //} for (int i = 0; i < DIMENSION_1; i++) { for (int j = 0; j < DIMENSION_2; j++) { sum += longs[i][j]; } } } System.out.println(sum); System.out.println("duration = " + (System.nanoTime() - start)); } } </pre>

这两个程序比较简单,就是 L1CacheMiss1,L1CacheMiss2 遍历数组的方向不一样。我们可以看看这两个程序各自需要的时间。 L1CacheMiss1:

<pre> [root@centos101 hushi]# time java L1CacheMiss1 starting.... 0 duration = 28704662032 real 0m44.603s user 0m54.004s sys 1m28.199s [root@centos101 hushi]# </pre>

L1CacheMiss2:

<pre> [root@centos101 hushi]# time java L1CacheMiss2 starting.... 0 duration = 3003702192 real 0m18.819s user 0m23.566s sys 1m26.321s [root@centos101 hushi]# </pre>

注意这两个值

<pre> duration = 28704662032 duration = 3003702192 </pre>

第二个访问的消耗的时间将近比第一个少了一个数量级。why ?

程序剖析

下面我们来分析造成这两个截然不同的运行时间的原因。

CPU 的结构

我们先来看看现代 CPU 的一般结构:

从上图可以看出一个 CPU 核心是分别有自己的 L1,L2 级 cache,但是所有的 CPU 核心总用一个 L3 级 cache。那 L1,L2 级 cache 有啥区别呢,请看下图

L1 级 cache 是分开的,dcache 数据缓存,icache 指令缓存。

从上面我们知道了现代的 CPU 一般都会有一级,二级,三级 cache,那为什么要有这些个 cache,我们知道一般说 cache 其实是为了平衡 read 速度的一个装置,而说 buffer 一般是为了平衡 write 的装置。cpu 这些个 cache 正是填补内存和 cpu 之间读取速度而设计。那我们可以看看到底 CPU 访问各级硬件的时间有多大的差别:

验证

perf 介绍

下面我们来验证我们的上面程序为什么会出现运行时间相差一个数量级。 首先我们介绍一个 Linux 下军工级别的监控工具 perf

Perf 是用来进行软件性能分析的工具。通过它,应用程序可以利用 PMU,tracepoint 和内核中的特殊计数器来进行性能统计。它不但可以分析指定应用程序的性能问题 (per thread),也可以用来分析内核的性能问题,当然也可以同时分析应用代码和内核,从而全面理解应用程序中的性能瓶颈。

最初的时候,它叫做 Performance counter,在 2.6.31 中第一次亮相。此后他成为内核开发最为活跃的一个领域。在 2.6.32 中它正式改名为 Performance Event,因为 perf 已不再仅仅作为 PMU 的抽象,而是能够处理所有的性能相关的事件。使用 perf,您可以分析程序运行期间发生的硬件事件,比如 instructions retired ,processor clock cycles 等;您也可以分析软件事件,比如 Page Fault 和进程切换。

这使得 Perf 拥有了众多的性能分析能力,举例来说,使用 Perf 可以计算每个时钟周期内的指令数,称为 IPC,IPC 偏低表明代码没有很好地利用 CPU。Perf 还可以对程序进行函数级别的采样,从而了解程序的性能瓶颈究竟在哪里等等。Perf 还可以替代 strace,可以添加动态内核 probe 点,还可以做 benchmark 衡量调度器的好坏。。。

我们可以使用

<pre>perf help</pre>

来查看 perf 的使用帮助,perf 的具体使用自行 google, 这里我们列出来这台机器上支持的 event

<pre> L1-dcache-loads [Hardware cache event] L1-dcache-load-misses [Hardware cache event] L1-dcache-stores [Hardware cache event] L1-dcache-store-misses [Hardware cache event] L1-dcache-prefetches [Hardware cache event] L1-dcache-prefetch-misses [Hardware cache event] L1-icache-loads [Hardware cache event] L1-icache-load-misses [Hardware cache event] L1-icache-prefetches [Hardware cache event] L1-icache-prefetch-misses [Hardware cache event] </pre>

这里我只列出来了跟 L1 级 cache 相关 event,其中 dcache 代表 data cache 数据缓存,icache 代表 instruction cache 指令缓存。

perf L1-dcache-load-misses 统计验证

<pre> [root@centos101 hushi]# perf stat -e L1-dcache-load-misses java L1CacheMiss1 starting.... 0 duration = 27936761365 Performance counter stats for 'java L1CacheMiss1': 1,914,529,933 L1-dcache-misses 43.200703471 seconds time elapsed [root@centos101 hushi]# </pre>

<pre> [root@centos101 hushi]# perf stat -e L1-dcache-load-misses java L1CacheMiss2 starting.... 0 duration = 3142251198 Performance counter stats for 'java L1CacheMiss2': 520,161,728 L1-dcache-misses 20.323997237 seconds time elapsed [root@centos101 hushi]# </pre>

从 L1-dcache-misses 的次数可以看出确实 L1CacheMiss1 要高出不少。

http://hushi55.github.io/2015/01/06/cpul1-cache-miss

参考

https://www.ibm.com/developerworks/cn/linux/l-cn-perf1/

转载于:https://my.oschina.net/u/155323/blog/375405

cpu L1 级 cache miss 研究相关推荐

  1. 中国自主可控的全数字实时仿真软件SkyEye支持龙芯CPU指令级仿真

    传统的系统开发过程,都是由工程师根据项目需求书来编写代码完成系统的开发,但随着功能的完善和版本迭代,系统中庞大的代码量很难确保正确无误,给后期测试和仿真带来了很大的压力和成本,在航空航天.卫星系统.核 ...

  2. 服务器cpu散热器性能,用于大型服务器CPU冷却的散热器性能研究.pdf

    用于大型服务器CPU冷却的散热器性能研究 62 FLUI D MACHI NERY V01.40,No .12 ,2012 文章编号: 1005-032 9( 2 012) 12-0062-04 用 ...

  3. 【嵌入式】CPU性能提升:Cache机制

    CPU性能提升:Cache机制 Cache机制是什么: Cache是CPU的缓存机制,用于提高CPU的运行效率 为什么需要Cache机制: CPU在自己的工作上是很快的,可以到达GHz频率上; 但需要 ...

  4. 【洞见研报】研报速读:东兴证券——CPU生态价值与机遇研究(CPU,构架,国产替代)

    CPU系科技行业算力基础,技术及生态是行业发展的关键要素.当前CPU市场仍主要为海外巨头占据,国内CPU厂商 起步较晚仍处于劣势,但十四五以来国产CPU自主研发受到高度重视,目前已走出三条独立自主化道 ...

  5. CPU系统级验证——测试激励——imperas公司riscvOVPsimPlus文件分析

    本分析重点关注该repo向量扩展部分. 1. repo简介 该repo是指令集验证的仿真环境包括,大部分是指令集的测试用例,也包含了一些模拟器,如riscvOVPsimPlus. 主要介绍的是risc ...

  6. CPU系统级验证——概览索引

    1. RISC-V CPU核指令集验证分析 1 wujian100 (1)SoC核分析 无剑100实际上是一款低功耗SoC,采用的CPU核是E902. core通过AHB总线与Icache相连 (2) ...

  7. 计算机的二级Cache的性能,电脑运行慢,发卡,检查一下CPU二级缓存-Cache是否打开了...

    电脑运行慢,发卡,检查一下CPU二级缓存-Cache是否打开了 (2011-07-31 23:31:59) 标签: 杂谈 转自 http://zhidao.baidu.com/question/138 ...

  8. 主存和cache每一块相等_笔记:cpu中的cache(一)

    前言:绝大部分内容来源于北京大学的慕课<计算机组成原理>,地址: https://www.coursera.org/learn/jisuanji-zucheng 存储体系(<深入理解 ...

  9. 【计算机系统结构】~ ROM/PROM/EPROM/E2PROM/FLASH、SOC 片上系统、总线、CPU 处理器、Cache、DDR、ARM 体系结构、虚拟内存、内核 kernel

    1. ROM/PROM/EPROM/E2PROM/FLASH ROM 指的是"只读存储器",即 Read-Only Memory.这是一种线路最简单半导体电路,通过掩模工艺, 一次 ...

最新文章

  1. Spring 泛型依赖注入
  2. windows64位环境下python安装numpy、scipy和matplotlib
  3. 大话移动通信pdf_移动通信是怎么实现的?
  4. dalvik对于Java方法调用的实现
  5. Magento Block设计分析(深入分析)
  6. 虚拟机安装Linux(vmware + ubuntu)
  7. python最常用的编程方式是什么_python常用模块和对象编程
  8. magicmatch java_Java-webmagic爬虫
  9. “Runtime Error”不产生dump文件的解决办法
  10. 贾跃亭又成功拿到6亿融资!九城与法拉第未来签约...
  11. java中引用数组_javaOO——引用数组
  12. 02--Tomcat总体结构分析一
  13. __gnu_cxx::hash_map使用中的一些问题
  14. 1月29日云栖精选夜读 | 拿下两个世界第一,阿里人机对话模型成人工智能国际通用标准...
  15. jquery选择器从认识到使用初级篇
  16. HTTP协议&SOCKET协议
  17. matlab interp2插值函数的使用
  18. Ubuntu“ System Program Problem Detected”问题
  19. 阿里云linux上安装,卸载mysql与重新安装配置Mysql
  20. 配置案例|Modbus转Profinet网关连接英威腾Goodrive200A 的配置案例

热门文章

  1. 笔记本/TK1安装ROS Indigo教程
  2. Android仿美团选择城市
  3. 入手评测 联想YOGA 5G怎么样
  4. 如何设置App的启动图
  5. Java OOP 6 异常
  6. 俊哥的blog的一道题
  7. am5728 使用mailbox 通信
  8. c语言时钟报告,C语言时钟图形输出系统设计报告.doc
  9. C# 创建和删除虚拟目录
  10. 玩转系统|Ventoy – 免格式化,超简单的『多合一』系统启动盘制作神器