Linux内核变量中per-CPU的使用
目录
一、锁的使用
1、使用锁的缺点
2、解决方法
二、per-CPU使用
1)动态
2)静态
3)注意事项
4)引用使用
三、per-CPU在内核中的使用
四、实例
程序输出
一、锁的使用
当操作共享可写数据时,需要加锁进行保护。
1、使用锁的缺点
- 性能会受到影响,更糟糕的是,这些不利影响可能会在数百核的高端多核系统上成倍增加。现实生活中的一种场景,是繁忙高速公路上的单一收费站或繁忙十字路口的红绿灯,严重影响通行性能。
- 锁的竞争:增加系统内锁的数量,有利于降低两个或多个进程/线程之间对特定锁的争用。
但出现死锁的机会大增。 - 一些列问题:性能问题,死锁,优先级转换风险、优先级高的需要等到优先级低的进程等。
2、解决方法
lock-free技术:per-CPU与lock-free数据结构RCU
原理:通过拷贝一份变量
二、per-CPU使用
头文件 #include <linux/percpu.h>
有两种申请方式:动态申请和静态申请
1)动态
申请
- alloc_percpu()
- alloc_percpu_gfp()
- devm_alloc_percpu(),第一个参数dev
释放
- void free_percpu(void __percpu *__pdata)
2)静态
- DEFINE_PER_CPU(int, pcpa);
3)注意事项
void *p;
val = get_cpu_var(pcpa);
p = vmalloc(20000);
pr_info("cpu1: pcpa = %+d\n", val);
put_cpu_var(pcpa);
vfree(p);
- get_cpu_var()/put_cpu_var() 之间的数据必须是原子的并且不能阻塞
- 所以禁用内核抢占,不允许任何类型的阻塞(或休眠)
- vmalloc、printk() 或者pr_foo<>是 可能会睡眠
4)引用使用
get_cpu_var()会引用preempt_disable(),禁止内核竞争
put_cpu_var()会引用preempt_enable()
增加per-CPU的变量
get_cpu_var(pcpa) ++;
put_cpu_var(pcpa);
或者per_cpu(var,cpu) 如遍历每个CPU核的pcpa的变量
for_each_online_cpu(i) {val = per_cpu(pcpa, i);pr_info(" cpu %2d: pcpa = %+d\n", i, val);
}
通过指针指向变量
{get,put}_cpu_ptr()
三、per-CPU在内核中的使用
current 变量
// arch/x86/include/asm/current.h
struct task_struct;DECLARE_PER_CPU(struct task_struct *, current_task);static __always_inline struct task_struct *get_current(void)
{return this_cpu_read_stable(current_task);
}#define current get_current()
current_task的变量什么时候更新? 上下文切换的时候
//源码文件arch/x86/kernel/process_64.c
__visible __notrace_funcgraph struct task_struct *
__switch_to(struct task_struct *prev_p, struct task_struct *next_p)
{[ ... ]this_cpu_write(current_task, next_p);[ ... ]
}
四、实例
两个线程使用共享变量,使用per-CPU,最后各自的输出是正确的
#define THRD0_ITERS 3static int thrd_work(void *arg)
{int i, val;long thrd = (long)arg;struct drv_ctx *ctx;if (set_cpuaffinity(thrd) < 0) {pr_err("setting cpu affinity mask for our kthread %ld failed\n", thrd);return -ENOSYS;}SHOW_CPU_CTX();if (thrd == 0) { /* kthread #0 runs on CPU 0 */for (i=0; i<THRD0_ITERS; i++) {/* Operate on our perpcu integer */val = ++ get_cpu_var(pcpa);pr_info(" thrd_0/cpu0: pcpa = %+d\n", val);put_cpu_var(pcpa);ctx = get_cpu_ptr(pcp_ctx);ctx->tx += 100;pr_info(" thrd_0/cpu0: pcp ctx: tx = %5d, rx = %5d\n",ctx->tx, ctx->rx);put_cpu_ptr(pcp_ctx);}} else if (thrd == 1) { /*kthread #1 runs on CPU 1 */for (i=0; i<THRD1_ITERS; i++) {val = -- get_cpu_var(pcpa);pr_info(" thrd_1/cpu1: pcpa = %+d\n", val);ctx = get_cpu_ptr(pcp_ctx);ctx->rx += 200;pr_info(" thrd_1/cpu1: pcp ctx: tx = %5d, rx = %5d\n",ctx->tx, ctx->rx);put_cpu_ptr(pcp_ctx);}}
程序输出
benshushu:2_percpu# insmod percpu_var.ko
[ 3180.878394] percpu_var: loading out-of-tree module taints kernel.
[ 3180.888442] percpu_var: module verification failed: signature and/or required key missing - tainting kernel
[ 3180.912374] percpu_var:init_percpu_var(): inserted
[ 3180.928186] percpu_var:thrd_work(): *** kthread PID 837 on cpu 1 now ***
[ 3180.928853] percpu_var:thrd_work(): thrd_1/cpu1: pcpa = -1
[ 3180.933631] percpu_var:thrd_work(): *** kthread PID 836 on cpu 0 now ***
[ 3180.939866] percpu_var:thrd_work(): thrd_0/cpu0: pcpa = +1
[ 3180.939947] percpu_var:thrd_work(): thrd_0/cpu0: pcp ctx: tx = 100, rx = 0
[ 3180.939968] percpu_var:thrd_work(): thrd_0/cpu0: pcpa = +2
[ 3180.939977] percpu_var:thrd_work(): thrd_0/cpu0: pcp ctx: tx = 200, rx = 0
[ 3180.939984] percpu_var:thrd_work(): thrd_0/cpu0: pcpa = +3
[ 3180.939992] percpu_var:thrd_work(): thrd_0/cpu0: pcp ctx: tx = 300, rx = 0
[ 3180.940691] percpu_var:disp_vars(): 000) [thrd_0/0]:836 | ...0 /* disp_vars() */
[ 3180.940786] percpu_var:disp_vars(): cpu 0: pcpa = +3, rx = 0, tx = 300
[ 3180.940801] percpu_var:disp_vars(): cpu 1: pcpa = -1, rx = 0, tx = 0
[ 3180.940811] percpu_var:disp_vars(): cpu 2: pcpa = +0, rx = 0, tx = 0
[ 3180.940822] percpu_var:disp_vars(): cpu 3: pcpa = +0, rx = 0, tx = 0
[ 3180.940838] percpu_var:thrd_work(): Our kernel thread #0 exiting now...
[ 3180.956032] percpu_var:thrd_work(): thrd_1/cpu1: pcp ctx: tx = 0, rx = 200
[ 3180.956454] percpu_var:thrd_work(): thrd_1/cpu1: pcpa = -2
[ 3180.956821] percpu_var:thrd_work(): thrd_1/cpu1: pcp ctx: tx = 0, rx = 400
[ 3180.959607] percpu_var:thrd_work(): thrd_1/cpu1: pcpa = -3
[ 3180.960655] percpu_var:thrd_work(): thrd_1/cpu1: pcp ctx: tx = 0, rx = 600
[ 3180.963535] percpu_var:disp_vars(): 001) [thrd_1/1]:837 | .N.0 /* disp_vars() */
[ 3180.965357] percpu_var:disp_vars(): cpu 0: pcpa = +3, rx = 0, tx = 300
[ 3180.969093] percpu_var:disp_vars(): cpu 1: pcpa = -3, rx = 600, tx = 0
[ 3180.970835] percpu_var:disp_vars(): cpu 2: pcpa = +0, rx = 0, tx = 0
[ 3180.971269] percpu_var:disp_vars(): cpu 3: pcpa = +0, rx = 0, tx = 0
[ 3180.971561] percpu_var:thrd_work(): Our kernel thread #1 exiting now...
解析
- 两个线程共享的数据 val与ctx,互不干扰
- 线程0执行后,val=3; ctx->tx += 100, 最后结果 300
- 线程1执行后,val=-3;ctx->rx += 200; 最后结果 600
Linux内核变量中per-CPU的使用相关推荐
- Linux环境变量中PS1
Linux环境变量中PS1是很重要的环境变量: PS(Prompt Sign): 是指命令提示符,例如在Fedora 12的终端下:[liutao@liutao ~]$ ,在设定PS1环境变量时,我们 ...
- c++ map 初始化_如何调整Linux内核启动中的驱动初始化顺序?
如何调整Linux内核启动中的驱动初始化顺序?[问题] 此处我要实现的是将芯片的ID用于网卡MAC地址,网卡驱动是enc28j60_init. 但是,读取芯片ID的函数,在as352x_afe_ini ...
- Linux内核配置(二) :CPU类型配置
5. Processor type and features 处理器类型及特性 5.1. Symmetric multi-processing support (SMP) 对称多处理器支持. 这将支持 ...
- Linux内核网络中数据报在协议层的处理
1. 前言 本文主要分析数据报从 IP 协议层进入协议栈,通过udp协议层,到达 socket,最终被用户程序读取的过程.在此过程中,介绍了 IP 协议层和 UDP 协议层中监测数据和网络调优的方法. ...
- linux内核编译如何选择cpu类型,Ubuntu内核编译和CPU Hot-Plug特性配置全过程及遇到问题记录...
最近编译Palacios需要linux的内核支持cpu Hot-Plug(内存热插拔)特性,无奈我机器上安装的Ubuntu10.04系统默认不支持内存热插拔特性,所以需要修改配置文件并重新编译linu ...
- Linux下编译build的命令,Linux内核编译中build目录设置
配置参数 最近在分析yocto中名为poky的嵌入式自动构建系统.在对内核进行定制的时候,看到了一个在进行内核编译时挺有用的特性,之前(作为野生程序员的我)一直没有发现. 该特性就是将源码与编译工作目 ...
- Linux内核网络中的软中断ksoftirqd
1. 前言 之前分享过Linux内核网络数据包的接收过程,当执行到网卡通过硬件中断(IRQ)通知CPU,告诉它有数据来了,CPU会根据中断表,调用已经注册的中断函数,这个中断函数会调到驱动程序(NIC ...
- Linux内核学习:EXT4 文件系统在 Linux 内核系统中的读写过程
目录 1 概述 2 虚拟文件系统 与 Ext4 文件系统 2.1 sys_write( ) 代码跟踪 2.2 sys_write( ) 过程分析 2.3 sys_write( ) 的核心部分 vfs_ ...
- Linux内核defconfig在哪,Linux内核根目录中的配置文件.config中包含了许多宏定义,...
满意答案 大大bigone 推荐于 2017.11.22 采纳率:52% 等级:9 已帮助:813人 一.Linux内核的配置系统由三个部分组成,分别是: 1.Makefile:分布在 Linu ...
最新文章
- View绘制流程的入口
- 十进制 转换为 二进制
- python学了可以干什么-学了Python都能干什么,哪个最赚钱?
- 数据结构简介以及抽象数据类型的实现
- ubuntu18.04安装openresty
- micropython会商用吗_NSF商用食品设备认证解析
- linux切换默认编辑器
- sklearn之逻辑回归和岭回归
- (转)J2EE十三个技术规范
- Julia: 由0.3 升级到0.4 版本的变化
- DELPHI利用WMI获取主板参数
- 一个权限管理系统如何设计
- OVS使用VLAN隔离VM流量
- HTML超大图片加载显示解决方案--图片切割转换成瓦片地图(BaiduMapTileCutter)
- H指数(h-index)的Python实现
- Html编码(#数字型)与解码小结 - 针对Puny Code(中文域名)的解码处理
- 第一天 :二分查找+移除元素
- 数据表中常见的数据类型
- 安徽大学在校生如何校外访问图书馆资源
- C语言练习-day29
热门文章
- python库大全(转)
- 极海APM微控制器基于IAR开发环境搭建与工程调试配置方法
- 007-安装百度云,搜狗输入法,播放器
- 基于JAVA跨境电商网站计算机毕业设计源码+数据库+lw文档+系统+部署
- 通过FFMpeg将MOV视频转为黑白通道的mp4(可设置上下/左右)
- ThreadPoolExecutor最佳实践--如何选择线程数
- css设置了超出隐藏省略号无效解决
- 2021年高考防骗预警,6大骗局,防骗指南,考生、家长请注意
- 男女比例失调,农村“光棍危机”有多严重?
- Qt编写安防视频监控系统17-在线地图