Linux per-CPU实现分析

Linux内核同步机制之:Per-CPU变量 具体底层的硬件是如何做的呢?此外,静态定义的数据在内存中连续,对于UMA系统而言是OK的,对于NUMA系统,每个CPU上的Per-CPU变量的副本应该位于它访问最快的那段memory上,也就是说Per-CPU变量的各个CPU副本可能是散布在整个内存地址空间的,而这些空间之间是有空洞的。无论静态还是动态per cpu变量的分配,其机制都是一样的,只不过,对于静态per cpu变量,需要在系统初始化的时候,对应per cpu section,预先动态分配一个同样size的per cpu chunk。 阅读详情

217 static DEFINE_PER_CPU(struct runqueue, runqueues);
11 #define DEFINE_PER_CPU(type, name) 
12 __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
13 

 

 

首先,在arch/i386/kernel/vmlinux.lds中有

  /* will be freed after init */

  . = ALIGN(4096);		/* Init code and data */

  __init_begin = .;



  /* 此处省略若干行:) */

  

  . = ALIGN(32);

  __per_cpu_start = .;

  .data.percpu  : { *(.data.percpu) }

  __per_cpu_end = .;

  . = ALIGN(4096);

  __init_end = .;

  /* freed after init ends here */




这说明__per_cpu_start和__per_cpu_end标识.data.percpu这个section的开头和结尾
并且,整个.data.percpu这个section都在__init_begin和__init_end之间,
也就是说,该section所占内存会在系统启动后释放(free)掉

因为有
#define DEFINE_PER_CPU(type, name) 
__attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name

所以
static DEFINE_PER_CPU(struct runqueue, runqueues); 
会扩展成
__attribute__((__section__(".data.percpu"))) __typeof__(struct runqueue)
per_cpu__runqueues;
也就是在.data.percpu这个section中定义了一个变量per_cpu__runqueues,
其类型是struct runqueue。事实上,这里所谓的变量per_cpu__runqueues,
其实就是一个偏移量,标识该变量的地址。

--------------------
其次,系统启动后,在start_kernel()中会调用如下函数

unsigned long __per_cpu_offset[NR_CPUS];



static void __init setup_per_cpu_areas(void)

{

	unsigned long size, i;

	char *ptr;

	/* Created by linker magic */

	extern char __per_cpu_start[], __per_cpu_end[];



	/* Copy section for each CPU (we discard the original) */

	size = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES);

#ifdef CONFIG_MODULES

	if (size < PERCPU_ENOUGH_ROOM)

		size = PERCPU_ENOUGH_ROOM;

#endif



	ptr = alloc_bootmem(size * NR_CPUS);



	for (i = 0; i < NR_CPUS; i++, ptr += size) {

		__per_cpu_offset[i] = ptr - __per_cpu_start;

		memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);

	}

}




在该函数中,为每个CPU分配一段专有数据区,并将.data.percpu中的数据拷贝到其中,
每个CPU各有一份。由于数据从__per_cpu_start处转移到各CPU自己的专有数据区中了,
因此存取其中的变量就不能再用原先的值了,比如存取per_cpu__runqueues
就不能再用per_cpu__runqueues了,需要做一个偏移量的调整,
即需要加上各CPU自己的专有数据区首地址相对于__per_cpu_start的偏移量。
在这里也就是__per_cpu_offset[i],其中CPU i的专有数据区相对于
__per_cpu_start的偏移量为__per_cpu_offset[i]。
这样,就可以方便地计算专有数据区中各变量的新地址,比如对于per_cpu_runqueues,
其新地址即变成per_cpu_runqueues+__per_cpu_offset[i]。

经过这样的处理,.data.percpu这个section在系统初始化后就可以释放了。

--------------------
再看如何存取per cpu的变量

/* This macro obfuscates arithmetic on a variable address so that gcc

   shouldn't recognize the original var, and make assumptions about it */

#define RELOC_HIDE(ptr, off)					

  ({ unsigned long __ptr;					

    __asm__ ("" : "=g"(__ptr) : "0"(ptr));		

    (typeof(ptr)) (__ptr + (off)); })



/* var is in discarded region: offset to particular copy we want */

#define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]))

#define __get_cpu_var(var) per_cpu(var, smp_processor_id())



#define get_cpu_var(var) (*({ preempt_disable(); &__get_cpu_var(var); }))




对于__get_cpu_var(runqueues),将等效地扩展为
__per_cpu_offset[smp_processor_id()] + per_cpu__runqueues
并且是一个lvalue,也就是说可以进行赋值操作。
这正好是上述per_cpu__runqueues变量在对应CPU的专有数据区中的新地址。

由于不同的per cpu变量有不同的偏移量,并且不同的CPU其专有数据区首地址不同,
因此,通过__get_cpu_var()便访问到了不同的变量。

静态PCPU变量 阅读详情

相关推荐

VS2019集成AddressSanitizer:C++内存错误检测实战指南

在C++开发中,内存管理是核心挑战之一,涉及堆、栈和全局变量的分配与释放。其原理在于程序运行时对内存地址的访问必须严格遵循分配边界和生命周期规则,否则会导致缓冲区溢出、释放后使用等严重错误。这类问题的技术价值在于直接影响程序的稳定性、安全性和性能,是高质量软件必须攻克的基础难题。应用场景广泛,从嵌入式系统到大型服务器软件,都需要可靠的内存错误检测机制。AddressSanitizer(ASan)作为一种编译时插桩技术,通过影子内存和运行时检查,能精准定位堆缓冲区溢出、释放后使用等隐蔽错误。本文以Visual

weixin_34356310的博客 279

Linux内核同步机制之Per-CPU变量

本文转自http://www.wowotech.net/kernel_synchronization/per-cpu.html。蜗窝出品,必属精品。 一、源由:为何引入 Per-CPU 变量? 1、lock bus 带来的性能问题 在 ARM 平台上,ARMv6 之前,SWP 和 SWPB 指令被用来支持对 shared memory 的访问: SWP <Rt>, <Rt2>, [<Rn>] Rn 中保存了 SWP 指令要操作的内存地址,通过...

不捡风筝的玖伍贰柒 1296

大华事件检测智能服务器,大华股份:高速公路智能事件检测 解决方案

1方案背景随着我国基础设施建设的飞速发展,公路尤其是高速公路的总里程数年年攀升。交通运输部统计数据显示,截止2017年底全国公路总里程477.35万公里,其中高速公路13.65万公里,位居世界第一。高速公路的运营和管理作为全国交通管理的重要组成部分日益受到严峻挑战,交通拥堵和事故频发已成为高速公路上非常突出的问题。抛洒物、行人、车辆不规则行驶等事件是导致以上结果的重要原因。基于视频分析的高速公路智...

weixin_39523887的博客 1822

解释DEFINE_PER_CPU(struct runqueue, runqueues);宏

首先,在arch/i386/kernel/vmlinux.lds中有 /* will be freed after init */ . = ALIGN(4096); /* Init code and data */ __init_begin = .;

yarsen的专栏 1534

机器人强化学习入门学习笔记

如果你追求高精度动力学仿真、用于强化学习或机器人研究,MuJoCo 是一个非常优秀的选择。如果需要快速实验、使用真实机器人模型,PyBullet 或 Gazebo可能更合适;如果你追求大规模并行训练,Isaac Gym 或 BraX会更高效。legged gym底层是​编辑isaacgym,基于gpu训练可以多环境并行训练,收敛到一个稳定行走的策略快。本视频MuJoCo基于cpu训练很慢。

xiaomu_347的博客 1462

XTDrone——无人机基于2D激光Lidar进行二维运动规划(细节提醒以及相关报错解决)

本文介绍了在Ubuntu 20.04系统无人机基于ROS Noetic实现HectorSLAM二维激光建图与运动规划的完整流程。主要内容包括:安装必要ROS依赖库;修改HectorSLAM的launch文件,解决坐标系转换问题;配置地图发布参数以避免覆盖已建地图;启动PX4仿真环境与XTDrone通信模块;最后通过2D导航目标点实现无人机运动规划。文中详细说明了各步骤的关键配置修改,并提供了处理常见错误(如TF转换超时)的解决方案。实现了从激光SLAM建图到路径规划的过程。

weixin_45390670的博客 996

Linux PER_CPU变量的理解

x86架构,64位长模式下。 // <arch/x86/include/asm/percpu.h > #define __percpu_seg gs #define PER_CPU_VAR(var) %__percpu_seg:var 1、定义 静态per-cpu变量通过DEFINE_PER_CPU和DECLARE_PER_CPU宏在内核源码中定义和声明,详见如下。 // ...

一点点 1900

如何判断一个程序员的技术比你强?

技术大佬与普通程序员之间存在明显的认知差异:前者善于将复杂问题抽象为经典计算机科学问题,用声明式代码替代过程式逻辑;对异常和边界条件极度敏感,具备系统化的排查方法论;代码追求高可读性而非炫技,且执着于底层原理研究。这种技术压制体现在解决问题的确定性上——通过扎实的理论功底和工程直觉,快速定位问题本质,而非依赖试错或搜索。真正的技术实力源于对底层逻辑的深刻理解和对系统稳定性的敬畏。

wldtzzming的专栏 1088

linux内核percpu变量声明,每个 CPU 的变量

Per-cpu 变量Per-cpu 变量是一项内核特性。从它的名字你就可以理解这项特性的意义了。我们可以创建一个变量,然后每个 CPU 上都会有一个此变量的拷贝。本节我们来看下这个特性,并试着去理解它是如何实现以及工作的。内核提供了一个创建 per-cpu 变量的 API - DEFINE_PER_CPU 宏:#define DEFINE_PER_CPU(type, name) \DEFINE_P...

weixin_30821291的博客 459

Jetson Orin Nano - SONY imx415 camera驱动开发

基于英伟达 Jetson orin nano 平台 imx415 camera驱动开发

hinewcc的博客 3242

Python离线断网情况下安装numpy、pandas和matplotlib等常用第三方包

联网情况下在命令终端CMD中输入“pip install numpy”即可自动安装,pandas和matplotlib同理一样方法进行自动安装。 工作的电脑不能上外网,所以不能通过直接输入pip命令来安装。 环境:电脑上已经安装了Python(没有安装的请参考其他教程)。 Python离线断网情况下安装numpy、pandas和matplotlib等常用第三方包的步骤如下: ...

dayou7738的博客 4942

多CPU支持下的 percpu 变量分析

/* *使用一个数组,来记录对于每个特定的CPU的变量的地址偏移量。 *有些CPU有自己独特的技术来实现。 */#ifndef __per_cpu_offsetextern unsigned long __per_cpu_offset[NR_CPUS];#define per_cpu_offset(x) (__per_cpu_offset[x])#endif /* 

CharlesPrince的专栏 5420

黑猫带你学UFS协议第23篇:UFS固件升级操作详解(FFU)

摘要:本文介绍了UFS固件更新(FFU)的实现方法与注意事项。根据UFS3.1 JEDEC协议,FFU通过write buffer命令(MODE=0Eh)下载FW固件,随后必须进行power cycle或硬件复位生效。文章详细阐述了FFU操作的10条规则,包括数据分片传输要求、寄存器访问限制等,同时指出协议未明确的厂商实现差异。关键寄存器包括bFFUTimeout、bDeviceFFUStatus和fPermanentlyDisableFwUpdate。

黑猫奥利奥的博客 1万+

linux per_cpu内容,Linux per-CPU实现分析

217 static DEFINE_PER_CPU(struct runqueue, runqueues);11 #define DEFINE_PER_CPU(type, name)12 __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name13首先,在arch/i386/kernel/vmlinu...

weixin_39829307的博客 155

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

linux 内核Per-CPU变量实现代码分析

本文分析了Linux内核中Per-CPU变量的实现机制,重点探讨了setup_per_cpu_areas函数的执行流程。文章详细介绍了关键数据结构pcpu_alloc_info和pcpu_chunk,它们分别用于管理动态Per-CPU内存分配的元数据和内存块状态。通过pcpu_embed_first_chunk函数完成内存分配后,pcpu_setup_first_chunk函数建立初始内存布局,包括静态和动态Per-CPU区域的划分。整个初始化过程涉及CPU分组、内存对齐和偏移量计算等核心步骤,最终形成每个

Amelio Ming 228

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

linux内核percpu变量声明,Linux内核对per-cpu变量的实现

(2012-04-10)摘自http://www.embexperts.com/viewthread.php?tid=131&extra=page%3D1在Linux中,per-cpu变量用在多处理器系统中,用来为系统中的每个cpu都生成一个变量的副本,以避开多处理器互斥中的加锁问题,另一个是cpu本地的变量可以充分利用cpu的硬件缓存,提高性能。本贴讨论一下Linux内核对per-cpu...

weixin_39603908的博客 161

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Linux kernel 中的per_cpu宏

本博文为原创,遵循CC3.0协议,转载请注明出处:http://blog.youkuaiyun.com/lux_veritas/article/details/8977510 -------------------------------------------------------------------------------------------------------------------

Lux_Veritas的专栏 5142

kernel中的per_cpu变量

per-cpu 变量的引入有效的解决了SMP系统中处理器对锁得竞争,每个cpu只需访问自己的本地变量。本文阐述了per-cpu变量在2.6内核上的实现和相关操作。 在系统编译阶段我们就手工的定义了一份所有的per-cpu变量,这些变量的定义是通过宏DEFINE_PER_CPU实现的: 11 #define DEFINE_PER_CPU(type, name) \

芋圆_钰源 1344

指针返回Linux kernel 中的per_cpu宏

时间紧张,先记一笔,后续优化与完善。     本博文为原创,遵守CC3.0协议,转载请注明出处:http://blog.youkuaiyun.com/lux_veritas/article/details/8977510     -----------------------------------------------------------------------------------------...

weixin_33725722的博客 121

[Linux]学习笔记系列 -- mm/percpu

本文介绍了Linux内核中Per-CPU变量的核心实现(mm/percpu.c),重点分析了其解决多核系统并发访问性能问题的技术原理。文章从历史背景出发,阐述了Per-CPU如何通过为每个CPU创建私有副本来避免锁争用和缓存一致性开销。详细解析了其核心工作原理,包括静态变量布局、动态分配机制和快速寻址技术,并对比了与自旋锁、原子变量等方案的性能差异。文章指出Per-CPU是统计计数器、调度队列等高频独立写场景的最佳选择,但也提示了其内存开销大、数据聚合成本高等局限性。最后通过对比表格,直观展示了Per-CP

wdfk-prog.space 1766

SMP/NUMA/PER_CPU

除了这种静态percpu变量,还有另外两种percpu变量, 其中一种是内核模块中的静态percpu变量,它虽然也是在编译期就能确定的,但由于内核模块动态加载的特性,它不是完全静态的,内核为这种percpu变量在percpu内存块中单独开辟了一个区域,叫reserved区,当内核模块被加载到内存时,其静态percpu变量就会在这个区域分配内存。当我们在访问percpu变量时,只需要将gs寄存器里的地址,加上我们想要访问的percpu变量的地址,就能得到在该cpu上,该percpu变量真实的内存地址。

Jun's blog 158

[Linux]学习笔记系列 -- [kernel]cpu

本文摘要主要分析了Linux内核中CPU相关的部分代码实现,包括CPU状态设置、热插拔初始化以及cpumask操作等关键功能。重点内容包括:1) cpumask相关工具宏的实现;2) CPU核心状态的设置接口(online/active/present/possible等);3) 引导CPU的初始化流程;4) CPU热插拔状态管理机制。这些代码为Linux内核提供了CPU资源的动态管理能力,支持SMP系统的核心功能实现。

wdfk-prog.space 876

【Linux内核十】进程管理模块,CPU在执行进程时的状态:current指针

【Linux内核十】进程管理模块,CPU在执行进程时的状态:current指针

新兴IT民工的专栏 972
上一篇: 从著名的list_head看linux内核中OO && 从Unix分层内核栈以及中断处理看Linux内核的另类
下一篇: (三)洞悉linux下的Netfilter&iptables:内核中的rule,match和target
废言Pro
博客等级 码龄16年 1093粉丝 142原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值