cache line提升程序性能

1.局部性

内存和cache交换的最小单位是cacheline。比如cacheline 64字节,每一次缓存数据的单位都是以一个 CacheLine 64 字节为单位进行存储的。假如说要查询的数据在 L1 中不存在,那么 CPU 的做法是一次性从 L2 中把要访问的数据及其后面的 64 个字节全部缓存进来。假如下一次再执行的时候要访问的指令在上一次已经在 L1 中存在了,那么就直接访问 L1,就不必再从 L2 来读取了,通过一个代码示例来分析:

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

int a[10000][10000];

void bad_cache() {
    int i = 0,j =0;
    for(i = 0; i < 10000; i++) {
        for(j = 0; j< 10000; j++) {
            a[j][i] = 1;
        }
    }
}

void good_cache() {
    int i = 0,j =0;
    for(i = 0; i < 10000; i++) {
        for(j = 0; j< 10000; j++) {
            a[i][j] = 1;
        }
    }
}

调用good_cache的性能数据:

#simpleperf  stat -e cache-references,cache-misses cache

Performance counter statistics:

  1,788,304,622  cache-references   # 665.594 M/sec        (100%)
      7,106,477  cache-misses       # 0.397386% miss rate  (100%)

Total test time: 2.686779 seconds.

可以看到共花费2.68s,cache-misses比例很低,而bad_cache的性能数据:

#simpleperf  stat -e cache-references,cache-misses cache


Performance counter statistics:

  1,611,937,854  cache-references   # 126.103 M/sec         (100%)
    171,774,619  cache-misses       # 10.656405% miss rate  (100%)

Total test time: 12.782758 seconds.

由于cache-misses率过高导致时间花费了12.78s时间。

2.cache伪共享(false sharing)

多处理器架构下,多线程并行写入同一内存位置,由于缓存一致性问题会导致性能问题,这种现象称为cache伪共享。

2.1 结构体对齐cache line

内核代码中经常看到某个结构体对齐到cache line size。如果有很多结构体的数组,结构体内存对齐将有助于性能提升。

示例代码:

#define ____cacheline_aligned __attribute__((__aligned__(64)))
#define LOOP 10000 * 10000
struct data {
    int32_t x;
}/*____cacheline_aligned*/;

typedef struct data Data;

Data dArray[2];

void f1() {
    int64_t i = 0;
    for(i = 0; i < LOOP; i++) {
        dArray[0].x = 2;
    }
    printf("f1 complete\n");
}

void f2() {
    int64_t i = 0;
    for(i= 0; i < LOOP; i++) {
        dArray[1].x = 1;
    }
    printf("f2 complete\n");
}

int main() {
    printf("sizeof(Data):%d\n", sizeof(Data)); 
    std::thread t1(f1);
    std::thread t2(f2);
    t1.join();
    t2.join();
    printf("complete\n");
    return 0;
}

如果Data结构体不对齐到cache line,那么dArray[0]和dArray[1]会在同一个cacheline上面,两个线程同时修改结构体成员变量,由于缓存一致性机制,会导致缓存失效。

上面代码的cache-miss比例 6.2%

Performance counter statistics:

  1,217,787,043  cache-references   # 1.374 G/sec          (100%)
     75,934,256  cache-misses       # 6.235430% miss rate  (100%)

将____cacheline_aligned打开以后,结构体对齐到64字节,这样dArray[0]和dArray[1]将分别占用不同的cache line,写cache失效后两者不会互相影响,cache-miss比例0.017%:

  1,216,454,682  cache-references   # 1.413 G/sec          (100%)
        205,538  cache-misses       # 0.016896% miss rate  (100%)

2.2 结构体成员分布在不同cache line

数据结构中频繁访问的成员可以单独占用一个cache line或者相关的成员在不同的cache line中错开,以提高访问效率。比如linux内核struct zone数据结构中zone->lock和zone->lru_lock两个频繁访问的锁,可以让他们在不同的cache line中,以提高获取锁的效率。

    ZONE_PADDING(_pad1_)                                                                                                                                   
    /* free areas of different sizes */
    struct free_area    free_area[MAX_ORDER];

    /* zone flags, see below */
    unsigned long       flags;

    /* Write-intensive fields used from the page allocator */
    spinlock_t      lock;

    ZONE_PADDING(_pad2_)

    /* Write-intensive fields used by page reclaim */

    /* Fields commonly accessed by the page reclaim scanner */
    spinlock_t      lru_lock;

3. 数组对齐到cacheline

atomic_long_t vm_zone_stat[NR_VM_ZONE_STAT_ITEMS] __cacheline_aligned_in_smp;                                                         
atomic_long_t vm_numa_stat[NR_VM_NUMA_STAT_ITEMS] __cacheline_aligned_in_smp;
atomic_long_t vm_node_stat[NR_VM_NODE_STAT_ITEMS] __cacheline_aligned_in_smp;

内核代码将vm_zone_stat等几个内存系统频繁访问的数组对齐到cacheline,确保该数组成员在一个cacheline中 

参考文章:

【Cache篇】Cache伪共享_漫游嵌入式的博客-CSDN博客_cache伪共享

【Cache篇】Cache伪共享_漫游嵌入式的博客-CSDN博客_cache伪共享

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值