本文是系列文章,建议您先阅读
你真的了解CPU Cache吗?系列----基础知识
https://www.talkwithtrend.com/Article/254441
你真的了解CPU Cache吗?系列----基础知识II
https://www.talkwithtrend.com/Article/254465
为了理解cache性能,除了基础知识文章中提到的cache相关概念,您必须掌握如下提到的概念。
内存延迟(memory latency):CPU访问内存,内存返回所需数据的时间
内存带宽(memory bandwidth):CPU和内存之间拷贝数据的通道大小
内存页(page):内存页是个虚拟概念,将内存分成固定小的块,每一块就是一页,x86上通常的页大小是4KB。
内存页表(page table):内存页表保存了从虚拟地址到实际物理地址的映射关系。
TLB(Translation Lookaside Buffer): 保存了最近使用的页表的映射,可以看做页表的cache。
预取(prefetching):CPU猜测下一个需要的内存数据,并提前load到cache中。如果猜对了,会提升性能。如果猜错了,会降低性能。
内存中的某个数据被访问了,那么它很可能会被再次访问。
内存中的某个数据被访问了,那么和它地址相邻的数据也很可能会被访问。
如果有大量的cache miss,则很容易导致系统性能问题
如果有系统性能问题,最好检查一下cache hit和cache miss的比例
顺序访问内存是性能最佳的,可以发挥预取的优势。
完全随机访问内存是性能最差的,预取不会有用,TLB也不会有用。-
在结构定义时,将经常使用的数据定义在一起,这样,经常使用的数据会长时间在cache中。
将经常使用的数据和不常使用的数据分在不同的结构中。
例如:
好的示例:
struct good
{
int often_used1;
int often_used2;
}
struct good2
{
int not_often_used1;
int not_often_used2;
}
不好的示例:
struct bad
{
int often_used1;
int often_used2;
int not_often_used1;
int not_often_used2;
}
尽量减少小内存块的分配
小内存块的分配,会导致随机访问增多。另外,也会造成内存碎片增多。
考虑字节对齐
结构定义时,尽量将大小相同的数据类型放在一起,按照顺序从大到小排列。
如果不注意字节对齐,会造成内存空洞。
尽量以行的顺序来访问数据,这样会尽量的利用cache line。
上面的循环中,如果 bigsize 特别大,那么每次迭代都会重新load数据到cache line。如果改为下面的写法,就要好很多。
这样,在j从0到10的迭代时,cache line 不需要重新load。
伪共享 (False Sharing)
现代CPU都已经是多核多线程的结构,伪共享也成为常见的由于多线程引起的cache性能问题。当本来被不同线程所有的应该互相独立的数据,被存放于同一个cache line中时,很容易出现伪共享的情况,即一个线程修改自己的数据时,顺带着就将另一个线程拥有的数据也给置为无效了。
避免伪共享的方法,可以采用Padding的方法,将结构体的大小变成和cache line一样大,这样CPU就不会将他们load到同一个cache Line中,如上图中的Sum[0]和Sum[2]。
如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!
赞0
添加新评论0 条评论