网站设计报告模板及范文建设银行网站怎么登陆不了了
web/
2025/9/26 22:50:50/
文章来源:
网站设计报告模板及范文,建设银行网站怎么登陆不了了,类似千图网的素材网站,2023智慧树网络营销答案在多处理器系统中#xff0c;每处理器变量为每个处理器生成一个变量的副本#xff0c;每个处理器访问自己的副本#xff0c;从而避免了处理器之间的互斥和处理器缓存之间的同步#xff0c;提高了程序的执行速度。
每处理器变量分为静态和动态两种。
静态每处理器变量
使…在多处理器系统中每处理器变量为每个处理器生成一个变量的副本每个处理器访问自己的副本从而避免了处理器之间的互斥和处理器缓存之间的同步提高了程序的执行速度。
每处理器变量分为静态和动态两种。
静态每处理器变量
使用宏“DEFINE_PER_CPU(type, name)”定义普通的静态每处理器变量使用宏“ DECLARE_PER_CPU(type, name)”声明普通的静态每处理器变量。 把宏“DEFINE_PER_CPU(type, name)”展开以后是 __attribute__((section(.data..percpu))) __typeof__(type) name
可以看出普通的静态每处理器变量存放在“ .data..percpu”节中。
定义静态每处理器变量的其他变体如下。 1使用宏“DEFINE_PER_CPU_FIRST(type, name)”定义必须在每处理器变量集合中最先出现的每处理器变量。 2使用宏“DEFINE_PER_CPU_SHARED_ALIGNED(type, name)”定义和处理器缓存行对齐的每处理器变量仅仅在 SMP 系统中需要和处理器缓存行对齐。 3使用宏“DEFINE_PER_CPU_ALIGNED(type, name)”定义和处理器缓存行对齐的每处理器变量不管是不是 SMP 系统都需要和处理器缓存行对齐。 4使用宏“DEFINE_PER_CPU_PAGE_ALIGNED(type, name)”定义和页长度对齐的每处理器变量。 5使用宏“DEFINE_PER_CPU_READ_MOSTLY(type, name)”定义以读为主的每处理器变量。
如果想要静态每处理器变量可以被其他内核模块引用需要导出到符号表 1如果允许任何内核模块引用使用宏“EXPORT_PER_CPU_SYMBOL(var)”把静态每处理器变量导出到符号表。 2如果只允许使用 GPL 许可的内核模块引用使用宏“EXPORT_PER_CPU_SYMBOL_GPL(var)”把静态每处理器变量导出到符号表。 要在模块中访问这样的一个变量应该这样声明 DECLARE_PER_CPU(type,name); 静态每处理器变量的存储 以arch/i386/kernel/vmlinux.lds文件为例 …… /*will be free after init*/ .ALIGN(4096); __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在系统初始化后就可以释放了。 动态每处理器变量
为动态每处理器变量分配内存的函数如下。 1使用函数__alloc_percpu_gfp 为动态每处理器变量分配内存。 void __percpu *__alloc_percpu_gfp(size_t size, size_t align, gfp_t gfp); 参数 size 是长度参数 align 是对齐值参数 gfp 是传给页分配器的分配标志位。
2宏 alloc_percpu_gfp(type, gfp)是函数__alloc_percpu_gfp 的简化形式参数 size 取“sizeof(type)”参数 align 取“__alignof__(type)”即数据类型 type 的对齐值。
3函数__alloc_percpu 是函数__alloc_percpu_gfp 的简化形式参数 gfp 取 GFP_KERNEL。 void __percpu *__alloc_percpu(size_t size, size_t align);
4宏 alloc_percpu(type)是函数__alloc_percpu 的简化形式参数 size 取“sizeof(type)”参数 align 取“ __alignof__(type)”。
最常用的是宏 alloc_percpu(type)。 为每处理器变量分配内存时返回的虚拟地址是chunk-base_addr offset − delta其中chunk-base_addr是块的基准地址offset是单元内部的偏移delta是pcpu_base_addr − __per_cpu_start__per_cpu_start是每处理器数据段的起始地址内核把所有静态每处理器变量放在每处理器数据段pcpu_base_addr是第一块的基准地址每处理器内存分配器在初始化的时候把每处理器数据段复制到第一块的每个单元。 问为每处理器变量分配内存时返回的虚拟地址为什么要减去delta 答因为宏“this_cpu_ptr(ptr)”在计算变量副本的地址时加上了delta所以分配内存时返回的虚拟地址要提前减去delta。宏“this_cpu_ptr(ptr)”为什么要加上delta原因是要照顾内核的静态每处理器变量。 所以使用alloc_percpu接口返回的地址不能直接使用赋值需要使用per_cpu提供的接口。 使用函数 free_percpu 释放动态每处理器变量的内存。 void free_percpu(void __percpu *__pdata); 访问每处理器变量
宏“this_cpu_ptr(ptr)”用来得到当前处理器的变量副本的地址宏“get_cpu_var(var)”用来得到当前处理器的变量副本的值。宏“this_cpu_ptr(ptr)”展开以后是 unsigned long __ptr; __ptr (unsigned long) (ptr); (typeof(ptr)) (__ptr per_cpu_offset(raw_smp_processor_id()));
可以看出当前处理器的变量副本的地址等于基准地址加上当前处理器的偏移。 宏“per_cpu_ptr(ptr, cpu)”用来得到指定处理器的变量副本的地址宏“per_cpu(var, cpu)”用来得到指定处理器的变量副本的值。 宏“get_cpu_ptr(ptr)”禁止内核抢占并且返回当前处理器的变量副本的地址宏“put_cpu_ptr(ptr)”开启内核抢占这两个宏成对使用确保当前进程在内核模式下访问当前处理器的变量副本的时候不会被其他进程抢占。 宏“get_cpu_var(var)”禁止内核抢占并且返回当前处理器的变量副本的值宏“put_cpu_var(var)”开启内核抢占这两个宏成对使用确保当前进程在内核模式下访问当前处理器的变量副本的时候不会被其他进程抢占。
示例
#include linux/netdevice.h #include linux/etherdevice.h #include linux/module.h #include linux/init.h #include asm/atomic.h #include linux/list.h #include net/inet_hashtables.h #include net/protocol.h #include linux/cpumask.h
#define err(msg) printk(KERN_ALERT %s\n, msg)
static int *percpu;
static int main_init(void) { int *p; int i; percpu alloc_percpu(int); if (!percpu) { err(alloc_percpu); goto err; } for_each_possible_cpu(i) { p per_cpu_ptr(percpu, i); *p i; } for_each_possible_cpu(i) { p per_cpu_ptr(percpu, i); printk(KERN_INFO %d %d\n, i, *p); } return 0; err: return -1; }
static void main_exit(void) { free_percpu(percpu); }
module_init(main_init); module_exit(main_exit);
MODULE_LICENSE(GPL); 每处理器计数器 通常使用原子变量作为计数器在多处理器系统中如果处理器很多那么计数器可能成为瓶颈每次只能有一个处理器修改计数器其他处理器必须等待。如果访问计数器很频繁将会严重降低系统性能。 有些计数器我们不需要时刻知道它们的准确值计数器的近似值和准确值对我们没有差别。针对这种情况我们可以使用每处理器计数器加速多处理器系统中计数器的操作。每处理器计数器的设计思想是计数器有一个总的计数值每个处理器有一个临时计数值每个处理器先把计数累加到自己的临时计数值当临时计数值达到或超过阈值的时候把临时计数值累加到总的计数值。 每处理器计数器的定义如下 include/linux/percpu_counter.h struct percpu_counter { raw_spinlock_t lock; s64 count; #ifdef CONFIG_HOTPLUG_CPU struct list_head list; /* All percpu_counters are on a list */ #endif s32 __percpu *counters; }; 成员 count 是总的计数值成员 lock 用来保护总的计数值成员 counters 指向每处理器变量每个处理器对应一个临时计数值。 运行时动态初始化每处理器计数器的方法如下 percpu_counter_init(fbc, value, gfp) fbc 是每处理器计数器的地址 value 是初始值 gfp 是分配每处理器变量的标志位。 把计数累加到每处理器计数器的函数是 void percpu_counter_add(struct percpu_counter *fbc, s64 amount) 读取近似计数值的函数如下。 1 s64 percpu_counter_read(struct percpu_counter *fbc) 可能返回负数。 2 s64 percpu_counter_read_positive(struct percpu_counter *fbc) 返回值大于或等于 0如果是负数返回 0。如果计数值必须大于或等于 0那么应该使用这个函数。读取准确计数值的函数如下。 1 s64 percpu_counter_sum(struct percpu_counter *fbc) 可能返回负数。 2 s64 percpu_counter_sum_positive(struct percpu_counter *fbc) 返回值大于或等于 0如果是负数返回 0。如果计数值必须大于或等于 0那么应该使用这个函数。
销毁每处理器计数器的函数是 void percpu_counter_destroy(struct percpu_counter *fbc) 函数 percpu_counter_add 的功能是把计数累加到每处理器计数器其代码如下 lib/percpu_counter.c 1 static inline void percpu_counter_add(struct percpu_counter *fbc, s64 amount) 2 { 3 __percpu_counter_add(fbc, amount, percpu_counter_batch); 4 } 5 6 void __percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch) 7 { 8 s64 count; 9 10 preempt_disable(); 11 count __this_cpu_read(*fbc-counters) amount; 12 if (count batch || count -batch) { 13 unsigned long flags; 14 raw_spin_lock_irqsave(fbc-lock, flags); 15 fbc-count count; 16 __this_cpu_sub(*fbc-counters, count - amount); 17 raw_spin_unlock_irqrestore(fbc-lock, flags); 18 } else { 19 this_cpu_add(*fbc-counters, amount); 20 } 21 preempt_enable(); 22 } 第 10 行代码禁止内核抢占。 第 11 行代码 count 等于本处理器的临时计数值加上 amount。 第 12 行代码如果 count 大于或等于阈值或者小于或等于阈值的相反数处理如下。 1第 14 行代码申请自旋锁并且禁止本处理器的硬中断。 2第 15 行代码把 count 加到总的计数值。 3第 16 行代码从本处理器的临时计数值减去 count − amount。 4第 17 行代码释放自旋锁并且恢复本处理器的硬中断状态。 第 1820 行代码如果 count 大于阈值的相反数并且小于阈值那么把 amount 加到本处理器的临时计数值。 第 21 行代码开启内核抢占。 全局变量 percpu_counter_batch 是每处理器计数器的阈值取值是 32 和处理器数量× 2的最大值。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/81248.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!