Linux pid_max设置及内核源码处理分析
2017-05-12 09:44
567 查看
pid_max 内核源码处理分析
以linux-3.2.6为例子分析 init/main.c: asmlinkage void __init start_kernel(void) -> kernel/pid.c: void __init pidmap_init(void) void __init pidmap_init(void) { /* bump default and minimum pid_max based on number of cpus */ pid_max = min(pid_max_max, max_t(int, pid_max, PIDS_PER_CPU_DEFAULT * num_possible_cpus())); pid_max_min = max_t(int, pid_max_min, PIDS_PER_CPU_MIN * num_possible_cpus()); pr_info("pid_max: default: %u minimum: %u\n", pid_max, pid_max_min); init_pid_ns.pidmap[0].page = kzalloc(PAGE_SIZE, GFP_KERNEL); /* Reserve PID 0. We never call free_pidmap(0) */ set_bit(0, init_pid_ns.pidmap[0].page); atomic_dec(&init_pid_ns.pidmap[0].nr_free); init_pid_ns.pid_cachep = KMEM_CACHE(pid, SLAB_HWCACHE_ALIGN | SLAB_PANIC); } 1、选出最大的pid_max max_t(int, pid_max, PIDS_PER_CPU_DEFAULT * num_possible_cpus()) 1.1、默认的pid_max int pid_max = PID_MAX_DEFAULT; #define PID_MAX_DEFAULT (CONFIG_BASE_SMALL ? 0x1000 : 0x8000) 也就是说如果没有配置base_small,则pid_max是0x8000,即32768。 1.2、计算cpu默认分配的pid总数 #define PIDS_PER_CPU_DEFAULT 1024 //每个cpu默认是1024个pid。 #define num_possible_cpus() cpumask_weight(cpu_possible_mask) //cpu总数 因此总的pid数就是 PIDS_PER_CPU_DEFAULT * num_possible_cpus() 因此第一步是先从这两个里面选出最大的那个,只有超过(32768/1024=32)32个cpu,才会用到cpu算出的pid总数,否则就是默认的。 2、系统总pid限制,即pid_max_max int pid_max_max = PID_MAX_LIMIT; #define PID_MAX_LIMIT (CONFIG_BASE_SMALL ? PAGE_SIZE * 8 : \ (sizeof(long) > 4 ? 4 * 1024 * 1024 : PID_MAX_DEFAULT)) 也既是最终的pid_max是不能超过pid_max_max,即不能超过limit(如果配置了base_small,则为page_size*8个pid。没配置的情况下,如果是64位的,则为4*1024*1024=4194304个pid。否则就是默认的PID_MAX_DEFAULT,即(0x100或0x800)
总结:
在不开启小内核的情况下,32为系统最大的pid个数是32768,实际的pid个数会根据cpu个数来调节,如果cpu个数小于32个,则实际的pid个数为32768,如果超过32个,则实际的pid个数为1024*cpus。
如何调节pid_max
前面已经说到pid_max的来源,唯一可以调节pid_max的途径就是改变cpus,那么cpus是如何确定的呢?cpus个数并非实际的cpu个数,而是possible cpus,即可用的最高cpu总数(有些热插拔的cpu还没有插进来,预留用的)
以x86为例子,查看possible cpus的来源
init/main.c start_kernel -> arch/x86/kernel/setup.c: void __init setup_arch -> arch/x86/kernel/smpboot.c __init void prefill_possible_map: ... if (setup_possible_cpus == -1) { possible = num_processors; #ifdef CONFIG_HOTPLUG_CPU if (setup_max_cpus) possible += disabled_cpus; #else if (possible > i) possible = i; #endif } else possible = setup_possible_cpus; total_cpus = max_t(int, possible, num_processors + disabled_cpus); 可用看到possible可以直接来源于setup_possible_cpus static int __initdata setup_possible_cpus = -1; static int __init _setup_possible_cpus(char *str) { get_option(&str, &setup_possible_cpus); return 0; } early_param("possible_cpus", _setup_possible_cpus); 可以看到它是可以通过内核参数传递进来的。最终能够手动修改pid个数的地方就是通过修改possible cpus,也就是通过内核参数来修改setup_possible_cpus。 具体的内核参数就是early_param定义的possible_cpus。 如何知道具体有多少个possible cpus?如下 printk(KERN_INFO "SMP: Allowing %d CPUs, %d hotplug CPUs\n", possible, max_t(int, possible - num_processors, 0)); 因此可以通过dmesg | grep Allowing来查看
# 关于CONFIG_BASE_SMALL
如果关闭这个选项,则会减少一部分内核数据结构。但是会减少性能。
相关文章推荐
- 变态的libDispatch源码分析-全局队列异步延时任务处理过程-设置计时器与插入ds
- FreeBSD 内核网络处理流程分析
- nhibernate源码分析之九: 事务处理
- .NET / Rotor源码分析5 - 开始使用WinDbg+SOS调试,sscoree.dll,加载SOS并设置JIT断点
- .NET / Rotor源码分析5 - 开始使用WinDbg+SOS调试,sscoree.dll,加载SOS并设置JIT断点
- .NET / Rotor源码分析5 - 开始使用WinDbg+SOS调试,sscoree.dll,加载SOS并设置JIT断点
- TOMCAT源码分析(消息处理)
- 第二人生的源码分析(三十七)消息处理的完整流程
- Linux内核2.6.14源码分析-双向循环链表代码分析
- 第二人生的源码分析(二十四)人物向前走的键盘消息处理
- .NET / Rotor源码分析5 - 开始使用WinDbg+SOS调试,sscoree.dll,加载SOS并设置JIT断点
- TOMCAT源码分析(消息处理)
- 传奇源码分析-客户端(游戏逻辑处理源分析三)
- 传奇源码分析-客户端(游戏逻辑处理源分析二)
- TOMCAT源码分析(消息处理)
- Linux内核2.6.14源码分析-双向循环链表代码分析(巨详细)
- 传奇源码分析-服务器端(LoginGate服务器处理)
- TOMCAT源码分析(消息处理)
- 传奇源码分析-客户端(游戏逻辑处理源分析四)
- 第二人生的源码分析(三十七)消息处理的完整流程