iCache dCache

news2024/11/25 20:49:48

前言

CPU 和 RAM 之间存在多级高速缓存,一般分为 3 级,分别是 L1、L2、L3。
另外,我们的代码都是由两部分组成的:指令、数据。
L1 Cache 比较特殊,每个 CPU 会有两个 L1 Cache,分别为 iCache(指令高速缓存,Instruction Cache)和 dCache(数据高速缓存,Data Cache)。
L2 和 L3 一般不区分指令和数据,可以同时缓存指令和数据。

在这里插入图片描述
下图是使用 CPU-Z 查看的两台 PC 的缓存情况
在这里插入图片描述

在这里插入图片描述

iCache Vs dCache

为什么要区分指令和数据呢?
原因是指令一般不会被修改,所以 iCache 在硬件设计上是只读的,这在一定程度上可以降低硬件设计成本。
另外一方面是出于性能的考量,ARM 是哈佛结构,即指令存储和数据存储是分开的。硬件上地址总线和数据总线是分开的,地址总线取的数据就是指令,数据总线取的数据就是数据。CPU 在执行程序时,可以同时获取指令和数据,做到硬件上并行,提升性能。
在这里插入图片描述

hit or miss

之前我们介绍过缓存一致性的问题,今天我们主要介绍缓存的命中与否对性能的影响。

iCache 命中与否对性能的影响

icache.c

#include <stdio.h>
#include <time.h>

void func1()
{
	int a = 0;
	int b = 0;
	int c = 0;
	int d = 0;

	if (a == b)
		a = b - 1;

	if (c == d)
		c = d - 1;
}

void func2()
{
	int a = 0;
	int b = 0;
	int c = 0;
	int d = 0;

	if (a == b)
		a = b - 1;

	if (c == d)
		c = d - 1;
}

void (*get_func(int i))()
{
	if (i % 2 == 0) {
		return &func1;
	} else {
		return &func2;
	}
}

void run(int use_icache)
{
	clock_t start, end;
	double time_used;
	void (*func)();

	start = clock();
	for (int i = 0; i < 100000000; i++) {
		if (use_icache == 0) {
			func = get_func(i);
			__builtin___clear_cache(func, func + sizeof(func));	 // 清除指令缓存
		}
		func = get_func(i);
		func();
	}
	end = clock();
	time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
	printf("%s use icache, time_used=%lf\n", use_icache == 1 ? "   " : "not", time_used);
}

int main()
{
	run(0);	 // 不使用指令缓存
	run(1);	 // 使用指令缓存
	return 0;
}

$ ./performance/cache/icache.out 
not use icache, time_used=1.142477
    use icache, time_used=0.962193
$ ./performance/cache/icache.out 
not use icache, time_used=1.154025
    use icache, time_used=0.937854
$ ./performance/cache/icache.out 
not use icache, time_used=1.135354
    use icache, time_used=0.963610

使用 iCache 性能提升 (1.14 - 0.96) / 1.14 = 15.8%

dCache 命中与否对性能的影响

dcache.c

#include <stddef.h>
#include <stdlib.h>
#include <time.h>

int binary_search(int *array, int number_of_elements, int key)
{
	int low = 0, high = number_of_elements - 1, mid;

	while (low <= high) {
		mid = (low + high) / 2;
#ifdef DO_PREFETCH
		__builtin_prefetch(&array[(mid + 1 + high) / 2], 0, 1);
		__builtin_prefetch(&array[(low + mid - 1) / 2], 0, 1);
#endif
		if (array[mid] < key)
			low = mid + 1;
		else if (array[mid] == key)
			return mid;
		else if (array[mid] > key)
			high = mid - 1;
	}

	return -1;
}

int main()
{
	int SIZE = 1024 * 1024 * 512;
	int *array = malloc(SIZE * sizeof(int));

	for (int i = 0; i < SIZE; i++) {
		array[i] = i;
	}

	int NUM_LOOKUPS = 1024 * 1024 * 4;
	srand(time(NULL));
	int *lookups = malloc(NUM_LOOKUPS * sizeof(int));
	for (int i = 0; i < NUM_LOOKUPS; i++) {
		lookups[i] = rand() % SIZE;
	}

	for (int i = 0; i < NUM_LOOKUPS; i++) {
		binary_search(array, SIZE, lookups[i]);
	}

	free(array);
	free(lookups);

	return 0;
}
$ gcc -O3 -std=c11 dcache.c -o nopre
$ gcc -O3 -std=c11 -DDO_PREFETCH dcache.c -o pre
$ time ./nopre 

real    0m12.516s
user    0m11.721s
sys     0m0.791s
$ time ./pre 

real    0m10.124s
user    0m9.463s
sys     0m0.660s
$ time ./nopre 

real    0m12.536s
user    0m11.816s
sys     0m0.717s
$ time ./pre 

real    0m10.280s
user    0m9.474s
sys     0m0.804s

使用 dCache 性能提升 (12.5 - 10.2) / 12.5 = 18.4%

linux 内核

内核中也经常见到调整 cacheline 来提升性能的提交,如 ceph: reorder fields in ‘struct ceph_snapid_map’

在这里插入图片描述
通过调整结构体成员的次序,适配缓存行,提高 dCache 命中率,进而提升性能。

实际工程

在我们的 WiFi 驱动中,通过链接脚本 lds 来让相同功能(rx、tx)的代码段排在一起,进而提升 iCache 的命中率,提升 WiFi 性能。
而提升 dCache 命中率的操作是,
RX 方向:WiFi 收到了一个 skb,我们很快就要访问这个 skb 里面的数据来进行 packet 的分类以及提交给 IP stack 处理了,不如我们先 prefetch 一下,这样后面需要访问这个 skb-> data 的时候,流水线可以直接命中 dCache。
参考:wil6210: prefetch head of packet
在这里插入图片描述
TX 方向:来自 PON/Ethernet 的报文需要通过 WiFi 发送出去时,在 WiFi Driver 中会去访问 skb->data 的头部(保存了 DA)来决定发给哪个 station,所以在报文交给 WiFi Driver 之前,就调用 prefetch(skb->data) 来将数据缓存到 dCache,这样等到 WiFi Driver 处理时就可以直接命中 dCache 了,其实和上述 RX 原理一致。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/644025.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

互联网 Java 工程师高级面试八股文汇总(1260 道题目附解析)

今年的行情&#xff0c;让招聘面试变得雪上加霜。已经有不少大厂&#xff0c;如腾讯、字节跳动的招聘名额明显减少&#xff0c;面试门槛却一再拔高&#xff0c;如果不用心准备&#xff0c;很可能就被面试官怼得哑口无言&#xff0c;甚至失去了难得的机会。 现如今&#xff0c;…

苹果将在 iOS 17 引入新功能,Safari隐私浏览有重大更新

苹果公司正在对Safari隐私浏览系统进行重大更新&#xff0c;为用户在浏览网页时提供更好的保护&#xff0c;防止第三方跟踪器。 iPhone制造商说&#xff1a;先进的跟踪和指纹保护有助于防止网站使用最新的技术来跟踪或识别用户的设备。隐私浏览现在可以在不使用时锁定&#xf…

MODIS数据下载

MODIS数据常用下载网址&#xff1a; Find Data - LAADS DAAC 在下载之前需要注册一个账号&#xff0c;才可进行下载。 1.选择数据产品&#xff0c;本人选取MOD09Q1数据产品&#xff08;250m8天合成的反射率数据&#xff09; 2.设置时间限制如下 3.找到感研究区域所在的位置&…

chatgpt赋能python:Python怎么拦截Windows浏览器的请求

Python怎么拦截Windows浏览器的请求 Python是一种流行的编程语言&#xff0c;并且被广泛用于Web开发。在这篇文章中&#xff0c;我们将深入探讨Python如何拦截Windows浏览器的请求。 什么是拦截请求? 拦截请求是指在网络传输过程中&#xff0c;对请求进行截获并进行处理的过…

C++结构体

目录 一、结构体的概念 二、结构体定义和使用 三、结构体数组 四、结构体指针 五、结构体嵌套结构体 六、结构体做函数参数 七、结构体中const使用场景 一、结构体的概念 结构体属于用户自定义的数据类型&#xff0c;允许用户存储不同的数据类型 二、结构体定义和使用 语法&…

对称二叉树(C++)

题目描述 一棵有点权的有根树如果满足以下条件&#xff0c;则被轩轩称为对称二叉树: 1. 二叉树; 2. 将这棵树所有节点的左右子树交换&#xff0c;新树和原树对应位置的结构相同且点权相等。 下图中节点内的数字为权值&#xff0c;节点外的 id 表示节点编号。 现在给出一棵二叉…

Spring 事务的相关配置、传播行为、隔离级别及注解配置声明式事务

目录 一、事务的相关配置 1. 添加测试标签 2. 添加对应方法 3. 测试 二、事务的传播行为 三、事务的隔离级别 四、注解配置声明式事务 1. 注册事务注解驱动 2. 加上注解 3. 配置类代替xml文件中的注解事务支持 4. 测试 往期专栏&文章相关导读 1. Maven系列专栏…

用了【WRITE-BUG数字空间】,其他文档软件可以卸载、注销账号了

都3202年了文档都进化成在线协同编辑文档了 让我看看谁还在用本地软件写文档啊~滋滋滋 使用【WRITE-BUG数字空间】云文档全键盘写作不是梦&#xff01;铁汁&#xff0c;听我句劝&#xff0c;把本地软件卸载了奥&#xff0c;你把握不住~ 程序员兄弟姐妹们的最爱编辑器&#x…

Zotero jasminum茉莉花插件

github地址&#xff1a;https://github.com/l0o0/jasminum 一个简单的Zotero 插件&#xff0c;用于识别中文元数据 非常感谢作者开发了这么好用的工具 安装步骤 首先要安装zotero 下载茉莉花插件安装包 https://github.com/l0o0/jasminum/releases 下载这个xpi格式的文件…

chatgpt赋能python:Python怎么抢优惠券?优惠不再是梦想!

Python怎么抢优惠券&#xff1f;优惠不再是梦想&#xff01; 在如今的消费社会&#xff0c;优惠券已成为人们购物时追逐的目标。而优惠券的数量有限且抢手&#xff0c;往往仅能在短时间内领取&#xff0c;因此初次抢到心仪的优惠券可谓令人欣喜不已。而对于程序员们而言&#…

《springboot使用篇》——只为使用,一篇就够

目录 环境&#xff1a; spring boot概述 一&#xff0c;springboot快速入门 1.创建maven项目 2.引入起步依赖 3.自定义controller 4.编写启动类 5.开始测试 二.快捷方式创建sprinboot工程 补充 三&#xff0c;配置文件 1.配置文件之间的关系 2.yml配置文件 1.基本…

【ROS】ROS+Gazebo强化学习:训练

1、安装ROS1 【ROS】Ubuntu20.04安装ROS1 2、安装Anaconda 【AI】PyTorch入门&#xff08;一&#xff09;&#xff1a;通过Anaconda安装PyTorch 【PyThon】Anaconda常用命令 3、源码下载 使用论文 Goal-Driven Autonomous Exploration Through Deep Reinforcement Learnin…

VMware虚拟机安装win10系统教程

执行本教程前请依次阅读以下2篇文章&#xff0c;完成环境准备&#xff1a; 1.VMware虚拟机下载安装教程【详细步骤 - 图文结合】 VMware虚拟机下载安装教程【详细步骤 - 图文结合】_西晋的no1的博客-CSDN博客 2.如何在微软官网下载win10镜像文件 如何在微软官网下载win10镜像文…

IDEA中Node.js环境下npm报错Error:0308010C:digital envelope routines:unsupported

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。 Node.js 是一个开源的、跨平台的 JavaScript 运行时环境。Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型&#xff0c;使其轻量又高效。Node.js 的包管理器 npm,是目前最流行的Node.js 的包管理器。 一、安装nod…

快速幂(简单 C++)

快速幂&#xff1a;就是能够快速地计算出以 a 为底数&#xff0c;b 为指数的幂&#xff0c;相较于传统的求幂算法&#xff0c;当指数 b 非常大时&#xff0c;使用快速幂算法&#xff0c;可以大大地降低循环的次数。 以3 ^ 13 为例&#xff1a; 首先将 b 转换成二进制&#xff…

Kubernetes配置Jenkins Slave

Kubernetes配置Jenkins Slave 部署在kubernetes集群内 1、部署jenkins 1.1、命名空间 apiVersion: v1 kind: Namespace metadata:name: jenkinscilabels:app: jenkinsci1.2、Deployment apiVersion: apps/v1 kind: Deployment metadata:name: jenkinscinamespace: jenkinsci…

软考A计划-系统架构师-案例分析考前背诵-上篇

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff…

〖数据结构〗一棵有点自律的树——搜索二叉树

文章目录 &#x1f490;专栏导读&#x1f490;文章导读&#x1f337;搜索二叉树概念&#x1f337;二叉搜索树的构建&#x1f33a;查找操作&#x1f33a;插入操作&#x1f33a;删除操作&#x1f33a;遍历操作☘️测试 &#x1f3f5;️拓展——递归实现&#x1f343;递归查找&…

MATLAB与物联网:如何应用MATLAB进行物联网数据的处理和分析

第一章&#xff1a;引言 物联网&#xff08;Internet of Things, IoT&#xff09;作为当今科技领域的热门话题&#xff0c;正在改变我们的生活方式和工作方式。随着物联网设备的普及和数据的不断增长&#xff0c;如何高效地处理和分析物联网数据成为了一个重要的挑战。MATLAB作…

【C语言之操作符1】

C语言之操作符1 1. 操作符分类2. 算术操作符3. 移位操作符3.1 左移操作符3.2 右移操作符 4. 位操作符5. 赋值操作符 1. 操作符分类 算术操作符 移位操作符 位操作符 赋值操作符 单目操作符 关系操作符 逻辑操作符 条件操作符 逗号表达式 下标引用、函数调用和结构成员 2. 算术…