Linux CPU cache

2021/9/21 7:30:34

本文主要是介绍Linux CPU cache,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

CPU cache

目前的CPU都是有三级缓存,一级二级是每个CPU独有的,三级缓存是所有CPU共有的,其中L1的缓存分为数据缓存和指令缓存,如下图所示:

虚拟化:                         VT-x
L1d 缓存:                       128 KiB    // L1数据缓存
L1i 缓存:                       128 KiB    // L1 指令缓存
L2 缓存:                        1 MiB
L3 缓存:                        8 MiB
NUMA 节点0 CPU:                 0-7

在这里插入图片描述

程序的数据最好能放到L1里面,大数据要进行拆分

缓存命中测试,保证测试的数据量大于L1+L2,系统会将内存放到L3缓存中,因此如下代码测试时输入的可以为 0K --> 8000 保证内存从L1 到L3的存取过程都能看到

//
// Created by andrew on 2021/9/20.
//
#include <iostream>
#include <vector>
#include <sched.h>
#include <ctime>
#include <fstream>

using namespace std;

#define CACHE_LINE_SIZE 64

struct Node {
    Node *next;
    char paddings[CACHE_LINE_SIZE - sizeof(void *)];
};

// 内存扫描,使用链表的方式每次调用指针去踩内存
#define N1(node) node=node->next;
#define N2(node) N1(node);N1(node);
#define N4(node) N2(node);N2(node);
#define N8(node) N4(node);N4(node);
#define N16(node) N8(node);N8(node);
#define N32(node) N16(node);N16(node);
#define N64(node) N32(node);N32(node);
#define N128(node) N64(node);N64(node);
#define N256(node) N128(node);N128(node);
#define N512(node) N256(node);N256(node);
#define N1024(node) N512(node);N512(node);

const long long sec2non = 1000000000;

const Node *Test(int T, const Node *c, std::size_t size, ofstream & outFile) {

    // 提前定义,防止在时间打点的时候将变量申请的时间计算在内
    struct timespec start{};
    struct timespec end{};
    const Node* node = nullptr;
    //< start
    clock_gettime(CLOCK_MONOTONIC, &start);
    // 保证测试的次数,也就是踩内存的次数和T一样
    const int M = static_cast<int>(T / size);
    for (int i = 0; i < M; i ++) {
        node  = c;
        const int s = static_cast<int>(size / 64);
        for (int  j = 0;  j < s; ++ j) {
            // 踩缓存
            N64(node);
        }
    }
    clock_gettime(CLOCK_MONOTONIC, &end);
    //< end
    // 计算总耗时
    auto elapsed = (end.tv_sec - start.tv_sec) * sec2non + end.tv_nsec - start.tv_nsec;
    // 总耗时 除缓存命中次数,计算缓存命中耗时
    std::cout << "elapsed milliseconds per elements : " << elapsed / M << "ns" << std::endl;
    outFile << elapsed / M << endl;

    return node;
}

// 代码地址 https://github.com/zzu-andrew/optimized_cplusplus.git
/*
 * @brief 系统缓存信息
 * L1d 缓存:                       128 KiB
 * L1i 缓存:                       128 KiB
 * L2 缓存:                        1 MiB
 * L3 缓存:                        8 MiB
 * */

//< rdmsr: version msr-tools-1.3 rdmsr 版本信息
//< rdmsr - tool for reading CPU machine specific registers (MSR)
int main(int argc, char*argv[]) {

    if (argc < 3) {
        std::cout << "argc : " << argc << std::endl;
        return -1;
    }

    // 清空CPU 参数,避免影响缓存命中
    cpu_set_t set;
    CPU_ZERO(&set);
    CPU_SET(0, &set);
    sched_setaffinity(0, sizeof(set), &set);
    // 16M,保证内存数量大于一二级缓存的量,才能保证系统会将缓存放到三级缓存里面
    // 如果一级 二级缓存够使用 系统将不会将内存放到三级缓存里面
    const int N = 1024 * 1024 * 16;   // * (64)
    // 使用vector搞一个环形buffer
    std::vector<Node> va;
    va.reserve(N);
    for (int i = 0; i < N - 1; i ++) {
        va[i].next = &(va[i + 1]);
    }
    va[N - 1].next = &va[0];

    const int M = 1000000;
    char *endPtr = nullptr;
    // 转换成10进制数
    const int beginKb = static_cast<int>(strtol(argv[1], &endPtr, 10));
    const int endKb = static_cast<int>(strtol(argv[2], &endPtr, 10));

    const Node* node = nullptr;
    // 耗时统计
    // 耗时统计
    ofstream outfile("./ou.csv", ios::trunc);
    for (int i = beginKb; i < endKb; i += 4) {
        std::cout << "test Kb : " << i << std::endl;
        std::cerr << i << '\t';
        node = Test(M, &va[0], i * 1024 / sizeof(Node), outfile);
    }

    outfile.close();

    std::cout << node << '\t' << &va[0] << std::endl;
    return 0;
}

在这里插入图片描述



这篇关于Linux CPU cache的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程