当前位置: 首页 > news >正文

Linux内核的PER_CPU机制

参考书《Linux内核模块开发技术指南》

1.原理

在多核CPU的情况下,为了提高CPU并发执行的效率,对于某些不是必须要在核间进行同步访问的资源,可以为每一个CPU创建一个副本,让每个CPU都访问自身的数据副本,而不是通过加锁等互斥手段访问内存中的同一数据,这样可以提高并发执行效率。例如:操作系统中有很多个进程,这些进程会在队列中,等待调度到某个CPU上运行,如果将这些进程放在一个队列中,各CPU需要访问这个队列并从队列取出进程运行时,则需要加锁操作以进行多核间的访问互斥,如下图所示。
在这里插入图片描述

由于访问进程所在的队列时需要加锁,上图中的四个CPU会发生资源竞争。同一时刻如果多个CPU想要同时访问队列,则只能有一个CPU能够访问成功,其他CPU则会等待,直到访问队列的CPU退出访问(这样的方式效率不高)。此时,如果创建多个队列,队列的数量和CPU核心数相同,一个队列和一个CPU绑定。让所有进程均匀分散在各队列中,而每个CPU只访问和自身绑定的队列,这时由于各队列是CPU的私有数据,CPU不会访问到不和自身绑定的队列,就不用通过加锁进行资源互斥,如此可大大提高运行效率。如下图所示。
在这里插入图片描述
以上描述的为每个CPU都创建一个私有数据副本的方式被称为PER_CPU。除了无需加锁外,PER_CPU还可以提高CPU的Cache利用。如果某些资源不是必须要在核间进行同步访问,使用PER_CPU是一个好的选择。需要注意的是,使用PER_CPU并不是意味着在任何情况下都无需进行加锁,在上图中,如果一个进程从CPU的私有队列迁移到另一个CPU的私有队列中,是需要加锁进行互斥的,因为这涉及到跨CPU的资源访问。

2.相关接口

开发人员能够通过内核提供的接口使用PER_CPU机制,这些接口在内核源码的include/linux/percpu-defs.h头文件和include/linux/percpu.h头文件中声明。这里将其分为两组接口:静态声明PER_CPU接口和动态分配PER_CPU接口。
(1)静态声明
PER_CPU的静态声明接口指的是PER_CPU变量使用的内存空间在编译期间分配,这些接口如下所示。

DECLARE_PER_CPU(type, name)

该接口用于创建PER_CPU变量。第一个参数type是变量类型,第二个参数name是变量名。例如要为每个CPU分配一个类型为long,变量名为test的变量,通过DECLARE_PER_CPU(long, test)可以实现。

DEFINE_PER_CPU(type, name)

该接口用于声明PER_CPU变量,参数和DECLARE_PER_CPU的参数一致。

get_cpu_var(var)

该接口用于获取当前CPU的PER_CPU变量,参数var是变量名,返回值是对应的PER_CPU变量。

put_cpu_var(var)

该接口和get_cpu_var配合使用,在PER_CPU变量访问完成时调用。
(2)动态分配
PER_CPU的动态分配指的是PER_CPU变量的内存空间在内核运行期间动态分配,相关接口如下所示。

alloc_percpu(type)

该接口用于分配PER_CPU变量,参数type是变量类型。函数的返回值就是分配的PER_CPU指针变量。

void free_percpu(void __percpu *__pdata)

该接口用于释放PER_CPU变量,其参数是PER_CPU的指针变量,一般由alloc_percpu分配。

per_cpu_ptr(ptr, cpu)

该接口用于获取某个CPU的私有PER_CPU变量。第一个参数ptr是PER_CPU变量,一般由alloc_percpu分配。第二个参数cpu是CPU编号。执行完该接口后,返回的就是编号为cpu的处理器的私有PER_CPU指针变量。

3.示例程序

本节通过一个简单的示例程序来说明如何使用PER_CPU的接口。假设PC上有两个CPU,分别为CPU0和CPU1,示例程序通过alloc_percpu分配一个PER_CPU变量,然后通过per_cpu_ptr分别获取并设置两个CPU对应的PER_CPU变量的值,然后将两个CPU的PER_CPU变量的值分别打印出来。源码如下:

#include <linux/module.h>
#include <linux/percpu.h>//要使用PER_CPU相关接口需引入该头文件
//自定义结构体
struct my_test_struct
{int a;
};
//声明一个类型为my_test_struct的PER_CPU变量
static struct my_test_struct *percpu_test; 
//加载函数
static int test_percpu_init(void)
{
//动态分配PER_CPU变量
percpu_test = alloc_percpu(struct my_test_struct);  per_cpu_ptr(percpu_test, 0)->a = 1;  //将CPU0中的变量a的值设为1per_cpu_ptr(percpu_test, 1)->a = 2;  //将CPU1中的变量a的值设为2
//分别打印出两个CPU的PER_CPU变量值printk("cpu 0:a=%d\n", per_cpu_ptr(percpu_test, 0)->a);printk("cpu 1:a=%d\n", per_cpu_ptr(percpu_test, 1)->a);return 0;
}
//卸载函数
static void test_percpu_exit(void)
{free_percpu(percpu_test);      //释放分配的PER_CPU变量
}
module_init(test_percpu_init);
module_exit(test_percpu_exit);
MODULE_LICENSE("GPL");          //要使用PER_CPU变量需要声明GPL许可协议

编译、加载上述模块后,执行dmesg -c命令打印调试信息,会分别打印出两个CPU的PER_CPU变量值,这两个值分别为1和2。如下图所示。
在这里插入图片描述


文章转载自:

http://hJoXmUMb.qszyd.cn
http://LLWyle1y.qszyd.cn
http://2lkjj5AT.qszyd.cn
http://QrMgwyeC.qszyd.cn
http://bcHshZxP.qszyd.cn
http://Kef7acUE.qszyd.cn
http://UaulAKt1.qszyd.cn
http://EzXF5zR8.qszyd.cn
http://TPK45JMA.qszyd.cn
http://0poEFone.qszyd.cn
http://kmZt0wq5.qszyd.cn
http://8eJbZSmo.qszyd.cn
http://4N3eLUQD.qszyd.cn
http://459ElRaR.qszyd.cn
http://6VWi5WVn.qszyd.cn
http://7aQuPWYn.qszyd.cn
http://eDw6AJZh.qszyd.cn
http://Y1NlOdIj.qszyd.cn
http://C7MxHZQx.qszyd.cn
http://KZBW2bPA.qszyd.cn
http://6sc1gn78.qszyd.cn
http://5rKb3DOl.qszyd.cn
http://Cf7yZ5hg.qszyd.cn
http://K5Ur5Ov2.qszyd.cn
http://BqdxROoA.qszyd.cn
http://fLueoq8y.qszyd.cn
http://eJbKQ3Z5.qszyd.cn
http://GJzjRD7U.qszyd.cn
http://2kWJUktm.qszyd.cn
http://enbnXLHa.qszyd.cn
http://www.dtcms.com/a/382168.html

相关文章:

  • 树莓派组建nas,云服务器及家庭影院
  • 二叉树hot100-中等
  • MX 模拟赛二总结
  • windows rocketmq 启动时报 java.lang.NullPointerException
  • 文本处理三剑客——grep、sed、awk
  • o2oa待办流程和已办流程表
  • 【WebSocket✨】入门之旅(三):WebSocket 的实战应用
  • 闪电科创-交通信号灯仿真SUMO
  • 【自动化】深入浅出UIAutomationClient:C#桌面自动化实战指南
  • 自定义类型:结构体、联合与枚举(1)
  • 在 Ubuntu 系统中基于 Miniconda 安装 VLLM 并启动模型 + Dify 集成指南
  • JavaWeb--day4--WebHttp协议Tomcat
  • Linux命令行的核心理念与实用指南(进阶版)
  • 机器学习-模型验证
  • 3-机器学习与大模型开发数学教程-第0章 预备知识-0-3 函数初步(多项式、指数、对数、三角函数、反函数)
  • 使用Aop和自定义注解实现SpringTask定时任务中加锁逻辑的封装
  • 远程依赖管理新范式:cpolar赋能Nexus全球协作
  • 【个人项目】【前端实用工具】OpenAPI to TypeScript 转换器
  • 贪心算法应用:物流装箱问题详解
  • 《用 TensorFlow 构建回归模型:从零开始的预测之路》
  • charles功能
  • Ceph OSD 元数据信息
  • Stanford CS336 | Assignment 2 - FlashAttention-v2 Pytorch Triotn实现
  • 【Docker】容器
  • C++ 类型推导(第一部分)
  • 联邦学习模型完成之后在验证集上面,如何判断输出正确与否
  • 优选算法---链表
  • 从理据到算法:认知语义学象似性对人工智能深层语义分析的重塑与前瞻
  • 39.网络流入门
  • PTQ 模型 量化方法