CPU访问寄存器比访问内存快很多,所以有高速缓存弥补这部分性能差异。高速缓存以缓存线(cache line)为单位进行存取。缓存线的大小取决于具体的CPU,一般是64字节。高速缓存的信息可以从
/sys/devices/system/cpu/cpuX/cache/indexX中读取,比如:/sys/devices/system/cpu/cpu0/cache/index0就是读取的cpu0的L1缓存的信息,其中coherency_line_size是缓存线的大小、level是缓存级别、type是缓存类型、shared_cpu_list是共享该缓存的cpu列表、size是该缓存的大小。

当缓存中的数据被修改,还没同步到内存,就称为该缓存线脏了,会做一个标记。当缓存不足时,会销毁一些缓存线,如果是脏的,就会回写内存。降级为访问内存的速度。

下面我们来做实验,通过不同的数据大小,相同的访问次数,来看随着数据增加,访问时间增加的现象。

cache.go

package main

import (
    "fmt"
    "log"
    "os"
    "strconv"
    "time"

    "golang.org/x/sys/unix"
)

const (
    CACHE_LINE = 64
    NUM_LOOP   = 4 * 1024 * 1024 * 1024
)

func main() {
    if len(os.Args) < 2 {
        panic(fmt.Sprintf("usage: %s <size[KB]>\n", os.Args[0]))
    }

    sizeArg, _ := strconv.Atoi(os.Args[1])
    size := sizeArg * 1024
    if size < 1 {
        panic(fmt.Sprintf("size must > 0, but got %d\n", size))
    }

    buffer, err := unix.Mmap(-1, 0, size, unix.PROT_READ|unix.PROT_WRITE, unix.MAP_PRIVATE|unix.MAP_ANON)
    if err != nil {
        log.Fatalf("mmap() failed with %s\n", err)
    }
    defer unix.Munmap(buffer)

    start := time.Now()
    for i := 0; i < NUM_LOOP/(size/CACHE_LINE); i++ {
        for j := 0; j < size; j += CACHE_LINE {
            buffer[j] = 0
        }
    }
    log.Printf("cost %v\n", time.Now().Sub(start))
}

结果如下:

hoo@LAPTOP-CMIA23FA:/mnt/d/hoo/code$ go run cache.go 1
2022/08/04 09:24:46 cost 1.872088065s
hoo@LAPTOP-CMIA23FA:/mnt/d/hoo/code$ go run cache.go 2
2022/08/04 09:24:53 cost 2.674986682s
hoo@LAPTOP-CMIA23FA:/mnt/d/hoo/code$ go run cache.go 4
2022/08/04 09:24:58 cost 1.905968251s
hoo@LAPTOP-CMIA23FA:/mnt/d/hoo/code$ go run cache.go 8
2022/08/04 09:25:04 cost 1.724077179s
hoo@LAPTOP-CMIA23FA:/mnt/d/hoo/code$ go run cache.go 16
2022/08/04 09:25:09 cost 1.457848844s
hoo@LAPTOP-CMIA23FA:/mnt/d/hoo/code$ go run cache.go 32
2022/08/04 09:25:13 cost 1.311004971s
hoo@LAPTOP-CMIA23FA:/mnt/d/hoo/code$ go run cache.go 64
2022/08/04 09:25:20 cost 4.043168597s
hoo@LAPTOP-CMIA23FA:/mnt/d/hoo/code$ go run cache.go 128
2022/08/04 09:25:30 cost 4.04601697s
hoo@LAPTOP-CMIA23FA:/mnt/d/hoo/code$ go run cache.go 256
2022/08/04 09:25:38 cost 4.128703878s
hoo@LAPTOP-CMIA23FA:/mnt/d/hoo/code$ go run cache.go 512
2022/08/04 09:25:46 cost 3.919007785s
hoo@LAPTOP-CMIA23FA:/mnt/d/hoo/code$ go run cache.go 1024
2022/08/04 09:25:55 cost 4.573088897s
hoo@LAPTOP-CMIA23FA:/mnt/d/hoo/code$ go run cache.go 2048
2022/08/04 09:26:08 cost 7.934703355s
hoo@LAPTOP-CMIA23FA:/mnt/d/hoo/code$ go run cache.go 4096
2022/08/04 09:26:22 cost 8.495372193s
hoo@LAPTOP-CMIA23FA:/mnt/d/hoo/code$ go run cache.go 8192
2022/08/04 09:26:52 cost 17.472046494s
hoo@LAPTOP-CMIA23FA:/mnt/d/hoo/code/qt$ go run cache.go 16384
2022/08/04 09:28:23 cost 29.343755701s