CacheLine

众所周知,计算机将数据从主存读入Cache时,是把要读取数据附近的一部分数据都读取进来这样一次读取的一组数据就叫做CacheLine,每一级缓存中都能放很多的CacheLine

两种方法查看:

1.cat /sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size

2. cat /proc/cpuinfo

3.lscpu

多核CUP

L1、L2、L3指一级缓存,二级缓存,三级缓存。其中一级缓存分指令缓存和数据缓存,通过lscpu命令,可以看到l1d和l1i。
CUP中的每个核均可单独处理一个线程
每个核公用L3

超线程

一个核中有多套PC和Register,他们公用一个ALU,这样一个核可以处理多个线程
如四核八线程就由此而来

Volatile的可见性

1、x被标记了volatile
2、两个线程运算时是将缓存中要被运算数所在的整条CacheLine复制到线程自己的存储,并进行运算,运算之后写回缓存
3、假设线程1修改了x并写回,但是线程2中的x还是未修改的x
4、由于x被标记了volatile,在线程1写回x缓存时,线程1会通知线程2重新读取缓存中的x

伪共享


1、线程1、2公共使用同一个CacheLine
2、x、y在同一个CacheLine
3、x、y都是volatile(x和y不是线程安全的,如果不是volatile,数据会不同步)
4、如果线程1不断修改x,线程2不断修改y,那么修改的时候线程1就要不断通知线程2更新x、线程2就要不断通知线程1更新y
5、这样的不断通知不断重新读取很浪费性能
6、这就叫伪共享

CacheLine对齐

多线程会有上面的伪共享的问题,如果在缓存读取数据到CacheLine时,两个volatile的数被读取到不同的CacheLine中的话,就不需要一直通知另一个线程更新数据了,因为另一个线程根本没有这个数据

那么如何让两个数据一定在不同的CacheLine呢,方法就是Cache Line对齐

一般一个CacheLine是64字节,也就是8个long,我们可以把x定义为long,并同时定义7个没有用的long变量,这样这8个数就在同一个CacheLine中
之后再定义y,y自然也就在下一个CacheLine中了
这就叫CacheLine对齐,这样两线程就不会出现伪共享的现象了

CPU的高速缓存一般分为一级缓存、二级缓存和三级缓存。CPU在运行时首先从一级缓存读取数据,如果读取失败则会从二级缓存读取数据,如果仍然失败则再从三级缓存,再失败最后从内存中存读取数据。而CPU从缓存或主内存中最终读取到数据所耗费的时钟周期差距是非常之大的。因此高速缓存的容量和速度直接影响到CPU的工作性能。一级缓存都内置在CPU内部并与CPU同速运行,可以有效的提高CPU的运行效率。一级缓存越大,CPU的运行效率往往越高。

缓存对齐如何编码

一级缓存又分为数据缓存和指令缓存,他们都由高速缓存行组成,对于X86_64架构的CPU来说,高速缓存行一般是64个字节,CPU大约只有512行高速缓存行,也就是说约32k的一级缓存。二级缓存一般有1-2MB,三级缓存可以达到33MB-64MB.

查看cpu0 的一级缓存中的有多少组

  1. $ cat /sys/devices/system/cpu/cpu0/cache/index0/number_of_sets

  2. $64

查看cpu0的一级缓存中一组中的行数

  1. $cat /sys/devices/system/cpu/cpu0/cache/index0/ways_of_associativity

  2. $8

当CPU需要读取一个变量时,该变量所在的以64字节分组的内存数据将被一同读入高速缓存行,所以,对于性能要求严格的程序来说,充分利用高速缓存行的优势非常重要。一次性将访问频繁的64字节数据对齐后读入高速缓存中,减少CPU高级缓存与低级缓存、内存的数据交换。

但是对于多CPU的计算机,情况却又不一样了。例如:

1、      CPU1 读取了一个字节,和它相邻的字节被读入 CPU1 的高速缓存。

2、      CPU2 做了上面同样的工作。这样 CPU1 , CPU2 的高速缓存拥有同样的数据。

3、      CPU1 修改了那个字节,被修改后,那个字节被放回 CPU1 的高速缓存行。但是该信息并没有被写入RAM 。

4、      CPU2 访问该字节,但由于 CPU1 并未将数据写入 RAM ,导致了数据不同步。

当一个 CPU 修改高速缓存行中的字节时,计算机中的其它 CPU会被通知,它们的高速缓存将视为无效。于是,在上面的情况下, CPU2 发现自己的高速缓存中数据已无效, CPU1 将立即把自己的数据写回 RAM ,然后 CPU2 重新读取该数据。 可以看出,高速缓存行在多处理器上会导致一些不利。

从上面的情况可以看出,在设计数据结构的时候,应该尽量将只读数据与读写数据分开,并具尽量将同一时间访问的数据组合在一起。这样 CPU 能一次将需要的数据读入。

如:

struct __a
{int id; // 不易变int factor;// 易变char name[64];// 不易变int value;// 易变
};

这样的数据结构就很不利。

在 X86_64 下,可以试着修改和调整它

struct __a
{char name[64];// 不易变int id; // 不易变char __Align[64 – sizeof(int)+sizeof(name)*sizeof(name[0])%64]int factor;// 易变int value;// 易变char __Align2[64 – 2* sizeof(int)%64]
};

64 – sizeof(int)+sizeof(name)*sizeof(name[0])%64

64表示 X86_64 架构缓存中,高速缓存行为64字节 大小。 __Align 用于显式对齐。

再来一个有利于高速缓存行的例子:

struct CUSTINFO
{DWORD dwCustomerID; //Mostly read-onlyint nBalanceDue; //Read-writechar szName[100]; //Mostly read-onlyFILETIME ftLastOrderDate; //Read-write
};

改版后的结构定义 :

// Determine the cache line size for the host CPU.
//为各种CPU定义告诉缓存行大小
#ifdef _X86_
#define CACHE_ALIGN 32
#endif#ifdef _X86_64
#define CACHE_ALIGN 64
#endif#ifdef _ALPHA_
#define CACHE_ALIGN 64
#endif#ifdef _IA64_
#define CACHE_ALIGN ??
#endif#define CACHE_PAD(Name, BytesSoFar) \
BYTE Name[CACHE_ALIGN - ((BytesSoFar) % CACHE_ALIGN)]struct CUSTINFO
{DWORD dwCustomerID; // Mostly read-onlychar szName[100]; // Mostly read-only//Force the following members to be in a different cache line.//这句很关键用一个算出来的Byte来填充空闲的告诉缓存行//如果指定了告诉缓存行的大小可以简写成这样//假设sizeof(DWORD) + 100 = 108;告诉缓存行大小为32//BYTE[12];//作用呢就是强制下面的数据内容与上面数据内容不在同一高速缓存行中。CACHE_PAD(bPad1, sizeof(DWORD) + 100);int nBalanceDue; // Read-writeFILETIME ftLastOrderDate; // Read-write//Force the following structure to be in a different cache line.CACHE_PAD(bPad2, sizeof(int) + sizeof(FILETIME));
};

高速缓存控制器是针对数据块,而不是字节进行操作的。从程序设计的角度讲,高速缓存其实就是一组称之为缓存行(cache line)的固定大小的数据块,其大小是以突发读或者突发写周期的大小为基础的。

每个高速缓存行完全是在一个突发读操作周期中进行填充或者下载的。即使处理器只存取一个字节的存储器,高速缓存控制器也启动整个存取器访问周期并请求整个数据块。缓存行第一个字节的地址总是突发周期尺寸的倍数。缓存行的起始位置总是与突发周期的开头保持一致。

现代处理器有专门的功能单元来执行加载和存储操作。加载单元每个时钟周期只有启动一条加载操作;与加载操作一样,在大多数情况下,存储操作能够在完整流水线化的模式中工作,每个周期开始一条新的存储。

关于内存字节对齐

https://blog.csdn.net/yizhiniu_xuyw/article/details/109622878

CPU高速缓存行对齐和代码优化相关推荐

  1. 软硬件协同编程 - C#玩转CPU高速缓存(附示例)

    写在前面 好久没有写博客了,一直在不断地探索响应式DDD,又get到了很多新知识,解惑了很多老问题,最近读了Martin Fowler大师一篇非常精彩的博客The LMAX Architecture, ...

  2. 高并发、低延迟之C#玩转CPU高速缓存(附示例)

    写在前面 好久没有写博客了,一直在不断地探索响应式DDD,又get到了很多新知识,解惑了很多老问题,最近读了Martin Fowler大师一篇非常精彩的博客The LMAX Architecture, ...

  3. CPU高速缓存与极性代码设计

    摘要:CPU内置少量的高速缓存的重要性不言而喻,在体积.成本.效率等因素下产生了当今用到的计算机的存储结构. 介绍 cpu缓存的结构 缓存的存取与一致 代码设计的考量 最后 CPU频率太快,其处理速度 ...

  4. 每个程序员都应该了解的 CPU 高速缓存 英文原文:Memory part 2: CPU caches

    现在的CPU比25年前要精密得多了.在那个年代,CPU的频率与内存总线的频率基本在同一层面上.内存的访问速度仅比寄存器慢那么一点点.但是,这一局面在上世纪90年代被打破了.CPU的频率大大提升,但内存 ...

  5. 每个程序员都应该了解的 CPU 高速缓存

    每个程序员都应该了解的 CPU 高速缓存 英文原文:Memory part 2: CPU caches 来源:oschina [编者按:这是Ulrich Drepper写"程序员都该知道存储 ...

  6. 【硬件设备】CPU 高速缓存知识

    目录 概述 CPU 的多级缓存 提升L1数据缓存的命中率 提升L1指令缓存的命中率 提升多核 CPU 下的缓存命中率 结论 概述 在计算机系统中,CPU高速缓存(英语:CPU Cache,在本文中简称 ...

  7. java底层知识(3)--CPU 高速缓存

    本文转载自: http://blog.jobbole.com/36263/ 尊重原创 3.CPU的高速缓存 现在的CPU比25年前要精密得多了.在那个年代,CPU的频率与内存总线的频率基本在同一层面上 ...

  8. 每个程序员都应该了解的 CPU 高速缓存 【第二部分】

    链接地址:http://www.oschina.net/translate/what-every-programmer-should-know-about-cpu-cache-part2 原文地址:h ...

  9. 每个程序员都应该了解的 CPU 高速缓存【第二部分】

    文章来源 每个程序员都应该了解的 CPU 高速缓存 [编者按:这是Ulrich Drepper写"程序员都该知道存储器"的第二部.那些没有读过第一部 的读者可能希望从这一部开始.这 ...

最新文章

  1. SPSiteManager 2.3可以下载了
  2. 显示mac电脑中隐藏的文件和文件夹
  3. 【单调栈 动态规划】bzoj1057: [ZJOI2007]棋盘制作
  4. 论文浅尝 | 基于图匹配神经网络的跨语言知识图对齐 (ACL 2019)
  5. java线程创建方式_Java创建线程安全的方法
  6. T-SQL查询-逻辑查询处理
  7. pyqt5的runJavaScript 使用模板
  8. Pig 变飞机?AI 为什么这么蠢!
  9. AndroidStudio编译引入JsonObject
  10. DSP2812开发板学习
  11. JavaScript的一些简单代码
  12. 前端面试总结之长沙五
  13. html5 图片羽化,课题:html5图像羽化(不规则区域羽化,feather,html5羽化)
  14. 一步步教你搭建Android开发环境(有图有真相)--“自吹自擂:史上最详细、最啰嗦、最新的搭建教程”
  15. 第一行代码-android-第三版-pdf扫描-思维导图-课件-源码
  16. 怎么判断数字n是否为2的x次方,即2的幂次呢,比如2,4,8,16,32
  17. RTK ? PPK ?到底该选啥
  18. python能参加奥赛吗-孩子学编程都能参加哪些含金量的比赛?
  19. 计算机网络毕业论文搭建服务,网络搭建毕业论文
  20. redflag Dc5.0,Asianux2安装时无法创建文件系统,缺少scsi驱动解决办法

热门文章

  1. HTML5 Placeholder实现input背景文字提示效果
  2. Ubuntu12下安装redis(多图版)+ Jedis连接Redis
  3. 【数据结构与算法】之深入解析“单词接龙”的求解思路与算法示例
  4. 【数据结构与算法】之深入解析“组合总和Ⅳ”的求解思路与算法示例
  5. App设计灵感之十二组精美的智能家居操作App设计案例
  6. HarmonyOS之深入解析设备标识符的功能和使用
  7. the NTP socket is in use, exiting
  8. 这年头学爬虫还就得会点 scrapy 框架
  9. Exhaustive Search Aizu - ALDS1_5_A
  10. sci_loopback_int的例程(中断程序)