Linuxカーネルのfork.cにあるcopy_process()を見ててkmalloc()を使っている箇所をkmem_cache_alloc()を使うようにしたらどうなんだろ?とふと思ったので試してみました。試したのはauditsc.cにあるaudit_alloc_context()です。この関数はcopy_process()から呼ばれるのでfork(2)、clone(2)が呼ばれると実行されるやつです。
カーネルはgitのv3.8タグのやつをチェックアウトして弄りました。
実行環境は仮想マシンでメモリが4GiB、cpuは以下のとおりです。
[masami@kerntest:~]$ cat /proc/cpuinfo processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 2 model name : QEMU Virtual CPU version 1.2.2 stepping : 3 microcode : 0x1 cpu MHz : 3103.054 cache size : 4096 KB fpu : yes fpu_exception : yes cpuid level : 4 wp : yes flags : fpu de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pse3 6 clflush mmx fxsr sse sse2 syscall nx lm rep_good nopl pni cx16 popcnt hypervis or lahf_lm bogomips : 6206.10 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: processor : 1 vendor_id : GenuineIntel cpu family : 6 model : 2 model name : QEMU Virtual CPU version 1.2.2 stepping : 3 microcode : 0x1 cpu MHz : 3103.054 cache size : 4096 KB fpu : yes fpu_exception : yes cpuid level : 4 wp : yes flags : fpu de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pse3 6 clflush mmx fxsr sse sse2 syscall nx lm rep_good nopl pni cx16 popcnt hypervis or lahf_lm bogomips : 6206.10 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management:
カーネルはこのように変更しました。
diff --git a/include/linux/audit.h b/include/linux/audit.h index 5a6d718..b90bf0b 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -89,6 +89,7 @@ struct filename; #ifdef CONFIG_AUDITSYSCALL /* These are defined in auditsc.c */ /* Public API */ +extern int __init audit_cache_init(void); extern int audit_alloc(struct task_struct *task); extern void __audit_free(struct task_struct *task); extern void __audit_syscall_entry(int arch, @@ -281,6 +282,10 @@ static inline void audit_mmap_fd(int fd, int flags) extern int audit_n_rules; extern int audit_signals; #else /* CONFIG_AUDITSYSCALL */ +static inline int __init audit_cache_init(void) +{ + return 0; +} static inline int audit_alloc(struct task_struct *task) { return 0; diff --git a/kernel/auditsc.c b/kernel/auditsc.c index a371f85..7f51229 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -275,6 +275,8 @@ struct audit_context { #endif }; +static struct kmem_cache *audit_cachep; + static inline int open_arg(int flags, int mask) { int n = ACC_MODE(flags); @@ -1046,8 +1048,9 @@ static inline struct audit_context *audit_alloc_context(enum audit_state state) { struct audit_context *context; - if (!(context = kmalloc(sizeof(*context), GFP_KERNEL))) + if (!(context = kmem_cache_alloc(audit_cachep, GFP_KERNEL))) return NULL; + audit_zero_context(context, state); INIT_LIST_HEAD(&context->killed_trees); INIT_LIST_HEAD(&context->names_list); @@ -1096,7 +1099,7 @@ static inline void audit_free_context(struct audit_context *context) audit_free_aux(context); kfree(context->filterkey); kfree(context->sockaddr); - kfree(context); + kmem_cache_free(audit_cachep, context); } void audit_log_task_context(struct audit_buffer *ab) @@ -2749,3 +2752,11 @@ struct list_head *audit_killed_trees(void) return NULL; return &ctx->killed_trees; } + +int __init audit_cache_init(void) +{ + printk(KERN_INFO"use slab cache instead of kmalloc in audit_alloc_context()\n"); + audit_cachep = KMEM_CACHE(audit_context, SLAB_PANIC); + return 0; +} + diff --git a/kernel/fork.c b/kernel/fork.c index c535f33..f631aa4 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1715,6 +1715,7 @@ void __init proc_caches_init(void) vm_area_cachep = KMEM_CACHE(vm_area_struct, SLAB_PANIC); mmap_init(); nsproxy_cache_init(); + audit_cache_init(); } /*
次にhackbenchをダウンロードしてコンパイルします。
$ gcc hackbench.c -o hackbench -lpthread
そうしましたら、以下のようなシェルを走らせてログをとります。hackbenchは改造前のv3.8でも実行してます。
#!/bin/bash for i in {0..30}; do echo "Test $i" ./hackbench -pipe 20 process 40 done
これが結果です。
No. | kmallo() | kmem_cache_alloc() |
1 | 0.141 | 0.151 |
2 | 0.128 | 0.121 |
3 | 0.156 | 0.14 |
4 | 0.142 | 0.12 |
5 | 0.138 | 0.147 |
6 | 0.123 | 0.128 |
7 | 0.146 | 0.129 |
8 | 0.122 | 0.126 |
9 | 0.128 | 0.138 |
10 | 0.124 | 0.141 |
11 | 0.12 | 0.139 |
12 | 0.122 | 0.156 |
13 | 0.113 | 0.137 |
14 | 0.129 | 0.132 |
15 | 0.176 | 0.135 |
16 | 0.122 | 0.163 |
17 | 0.148 | 0.129 |
18 | 0.133 | 0.136 |
19 | 0.125 | 0.128 |
20 | 0.143 | 0.147 |
21 | 0.129 | 0.149 |
22 | 0.123 | 0.13 |
23 | 0.148 | 0.128 |
24 | 0.12 | 0.133 |
25 | 0.126 | 0.122 |
26 | 0.141 | 0.124 |
27 | 0.133 | 0.125 |
28 | 0.134 | 0.141 |
29 | 0.136 | 0.162 |
30 | 0.135 | 0.128 |
31 | 0.126 | 0.127 |
平均 | 0.133225806451613 | 0.135870967741935 |
グラフだとこのように。
(´-`).。oO(一回くらい実機で試してみるかなぁ。