aboutsummaryrefslogtreecommitdiffstats
path: root/mm/slub.c
diff options
context:
space:
mode:
authorChristoph Lameter <clameter@sgi.com>2007-05-09 05:32:45 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-09 15:30:46 -0400
commit45edfa580b8e638c44ec26872bfe75b307ba12d1 (patch)
tree1143a378c5a8b6dcf6bfb1cb7c0cfd42df725417 /mm/slub.c
parent41ecc55b8a8ca618e6d490982c7ce45d230d4399 (diff)
SLUB: include lifetime stats and sets of cpus / nodes in tracking output
We have information about how long an object existed and about the nodes and cpus where the allocations and frees took place. Add that information to the tracking output in /sys/slab/xx/alloc_calls and /sys/slab/free_calls This will then enable slabinfo to output nice reports like this: christoph@qirst:~/slub$ ./slabinfo kmalloc-128 Slabcache: kmalloc-128 Aliases: 0 Order : 0 Sizes (bytes) Slabs Debug Memory ------------------------------------------------------------------------ Object : 128 Total : 12 Sanity Checks : On Total: 49152 SlabObj: 200 Full : 7 Redzoning : On Used : 24832 SlabSiz: 4096 Partial: 4 Poisoning : On Loss : 24320 Loss : 72 CpuSlab: 1 Tracking : On Lalig: 13968 Align : 8 Objects: 20 Tracing : Off Lpadd: 1152 kmalloc-128 has no kmem_cache operations kmalloc-128: Kernel object allocation ----------------------------------------------------------------------- 6 param_sysfs_setup+0x71/0x130 age=284512/284512/284512 pid=1 nodes=0-1,3 11 percpu_populate+0x39/0x80 age=283914/284428/284512 pid=1 nodes=0 21 __register_chrdev_region+0x31/0x170 age=282896/284347/284473 pid=1-1705 nodes=0-2 1 sys_inotify_init+0x76/0x1c0 age=283423 pid=1004 nodes=0 19 as_get_io_context+0x32/0xd0 age=6/247567/283988 pid=1-11782 nodes=0,2 10 ida_pre_get+0x4a/0x80 age=277666/283773/284526 pid=0-2177 nodes=0,2 24 kobject_kset_add_dir+0x37/0xb0 age=282727/283860/284472 pid=1-1723 nodes=0-2 1 acpi_ds_build_internal_buffer_obj+0xd3/0x11d age=284508 pid=1 nodes=0 24 con_insert_unipair+0xd7/0x110 age=284438/284438/284438 pid=1 nodes=0,2 1 uart_open+0x2d2/0x4b0 age=283896 pid=1 nodes=0 26 dma_pool_create+0x73/0x1a0 age=282762/282833/282916 pid=1705-1723 nodes=0 1 neigh_table_init_no_netlink+0xd2/0x210 age=284461 pid=1 nodes=0 2 neigh_parms_alloc+0x2b/0xe0 age=284410/284411/284412 pid=1 nodes=2 2 neigh_resolve_output+0x1e1/0x280 age=276289/276291/276293 pid=0-2443 nodes=0 1 netlink_kernel_create+0x90/0x170 age=284472 pid=1 nodes=0 4 xt_alloc_table_info+0x39/0xf0 age=283958/283958/283959 pid=1 nodes=1 3 fn_hash_insert+0x473/0x720 age=277653/277661/277666 pid=2177-2185 nodes=0 1 get_mtrr_state+0x285/0x2a0 age=284526 pid=0 nodes=0 1 cacheinfo_cpu_callback+0x26d/0x3e0 age=284458 pid=1 nodes=0 29 kernel_param_sysfs_setup+0x25/0x90 age=284511/284511/284512 pid=1 nodes=0-1,3 5 process_zones+0x5e/0x170 age=284546/284546/284546 pid=0 nodes=0 1 drm_core_init+0x48/0x160 age=284421 pid=1 nodes=2 kmalloc-128: Kernel object freeing ------------------------------------------------------------------------ 163 <not-available> age=4295176847 pid=0 nodes=0-3 1 __vunmap+0x6e/0xf0 age=282907 pid=1723 nodes=0 28 free_as_io_context+0x12/0x90 age=9243/262197/283474 pid=42-11754 nodes=0 1 acpi_get_object_info+0x1b7/0x1d4 age=284475 pid=1 nodes=0 1 do_acpi_find_child+0x45/0x4e age=284475 pid=1 nodes=0 NUMA nodes : 0 1 2 3 ------------------------------------------ All slabs 7 2 2 1 Partial slabs 2 2 0 0 Signed-off-by: Christoph Lameter <clameter@sgi.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/slub.c')
-rw-r--r--mm/slub.c96
1 files changed, 81 insertions, 15 deletions
diff --git a/mm/slub.c b/mm/slub.c
index 3e614c1901b7..ae2831027802 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1586,13 +1586,16 @@ static int calculate_order(int size)
1586 order < MAX_ORDER; order++) { 1586 order < MAX_ORDER; order++) {
1587 unsigned long slab_size = PAGE_SIZE << order; 1587 unsigned long slab_size = PAGE_SIZE << order;
1588 1588
1589 if (slub_max_order > order && 1589 if (order < slub_max_order &&
1590 slab_size < slub_min_objects * size) 1590 slab_size < slub_min_objects * size)
1591 continue; 1591 continue;
1592 1592
1593 if (slab_size < size) 1593 if (slab_size < size)
1594 continue; 1594 continue;
1595 1595
1596 if (order >= slub_max_order)
1597 break;
1598
1596 rem = slab_size % size; 1599 rem = slab_size % size;
1597 1600
1598 if (rem <= slab_size / 8) 1601 if (rem <= slab_size / 8)
@@ -2751,6 +2754,13 @@ static void resiliency_test(void) {};
2751struct location { 2754struct location {
2752 unsigned long count; 2755 unsigned long count;
2753 void *addr; 2756 void *addr;
2757 long long sum_time;
2758 long min_time;
2759 long max_time;
2760 long min_pid;
2761 long max_pid;
2762 cpumask_t cpus;
2763 nodemask_t nodes;
2754}; 2764};
2755 2765
2756struct loc_track { 2766struct loc_track {
@@ -2791,11 +2801,12 @@ static int alloc_loc_track(struct loc_track *t, unsigned long max)
2791} 2801}
2792 2802
2793static int add_location(struct loc_track *t, struct kmem_cache *s, 2803static int add_location(struct loc_track *t, struct kmem_cache *s,
2794 void *addr) 2804 const struct track *track)
2795{ 2805{
2796 long start, end, pos; 2806 long start, end, pos;
2797 struct location *l; 2807 struct location *l;
2798 void *caddr; 2808 void *caddr;
2809 unsigned long age = jiffies - track->when;
2799 2810
2800 start = -1; 2811 start = -1;
2801 end = t->count; 2812 end = t->count;
@@ -2811,12 +2822,29 @@ static int add_location(struct loc_track *t, struct kmem_cache *s,
2811 break; 2822 break;
2812 2823
2813 caddr = t->loc[pos].addr; 2824 caddr = t->loc[pos].addr;
2814 if (addr == caddr) { 2825 if (track->addr == caddr) {
2815 t->loc[pos].count++; 2826
2827 l = &t->loc[pos];
2828 l->count++;
2829 if (track->when) {
2830 l->sum_time += age;
2831 if (age < l->min_time)
2832 l->min_time = age;
2833 if (age > l->max_time)
2834 l->max_time = age;
2835
2836 if (track->pid < l->min_pid)
2837 l->min_pid = track->pid;
2838 if (track->pid > l->max_pid)
2839 l->max_pid = track->pid;
2840
2841 cpu_set(track->cpu, l->cpus);
2842 }
2843 node_set(page_to_nid(virt_to_page(track)), l->nodes);
2816 return 1; 2844 return 1;
2817 } 2845 }
2818 2846
2819 if (addr < caddr) 2847 if (track->addr < caddr)
2820 end = pos; 2848 end = pos;
2821 else 2849 else
2822 start = pos; 2850 start = pos;
@@ -2834,7 +2862,16 @@ static int add_location(struct loc_track *t, struct kmem_cache *s,
2834 (t->count - pos) * sizeof(struct location)); 2862 (t->count - pos) * sizeof(struct location));
2835 t->count++; 2863 t->count++;
2836 l->count = 1; 2864 l->count = 1;
2837 l->addr = addr; 2865 l->addr = track->addr;
2866 l->sum_time = age;
2867 l->min_time = age;
2868 l->max_time = age;
2869 l->min_pid = track->pid;
2870 l->max_pid = track->pid;
2871 cpus_clear(l->cpus);
2872 cpu_set(track->cpu, l->cpus);
2873 nodes_clear(l->nodes);
2874 node_set(page_to_nid(virt_to_page(track)), l->nodes);
2838 return 1; 2875 return 1;
2839} 2876}
2840 2877
@@ -2850,11 +2887,8 @@ static void process_slab(struct loc_track *t, struct kmem_cache *s,
2850 set_bit(slab_index(p, s, addr), map); 2887 set_bit(slab_index(p, s, addr), map);
2851 2888
2852 for_each_object(p, s, addr) 2889 for_each_object(p, s, addr)
2853 if (!test_bit(slab_index(p, s, addr), map)) { 2890 if (!test_bit(slab_index(p, s, addr), map))
2854 void *addr = get_track(s, p, alloc)->addr; 2891 add_location(t, s, get_track(s, p, alloc));
2855
2856 add_location(t, s, addr);
2857 }
2858} 2892}
2859 2893
2860static int list_locations(struct kmem_cache *s, char *buf, 2894static int list_locations(struct kmem_cache *s, char *buf,
@@ -2888,15 +2922,47 @@ static int list_locations(struct kmem_cache *s, char *buf,
2888 } 2922 }
2889 2923
2890 for (i = 0; i < t.count; i++) { 2924 for (i = 0; i < t.count; i++) {
2891 void *addr = t.loc[i].addr; 2925 struct location *l = &t.loc[i];
2892 2926
2893 if (n > PAGE_SIZE - 100) 2927 if (n > PAGE_SIZE - 100)
2894 break; 2928 break;
2895 n += sprintf(buf + n, "%7ld ", t.loc[i].count); 2929 n += sprintf(buf + n, "%7ld ", l->count);
2896 if (addr) 2930
2897 n += sprint_symbol(buf + n, (unsigned long)t.loc[i].addr); 2931 if (l->addr)
2932 n += sprint_symbol(buf + n, (unsigned long)l->addr);
2898 else 2933 else
2899 n += sprintf(buf + n, "<not-available>"); 2934 n += sprintf(buf + n, "<not-available>");
2935
2936 if (l->sum_time != l->min_time) {
2937 unsigned long remainder;
2938
2939 n += sprintf(buf + n, " age=%ld/%ld/%ld",
2940 l->min_time,
2941 div_long_long_rem(l->sum_time, l->count, &remainder),
2942 l->max_time);
2943 } else
2944 n += sprintf(buf + n, " age=%ld",
2945 l->min_time);
2946
2947 if (l->min_pid != l->max_pid)
2948 n += sprintf(buf + n, " pid=%ld-%ld",
2949 l->min_pid, l->max_pid);
2950 else
2951 n += sprintf(buf + n, " pid=%ld",
2952 l->min_pid);
2953
2954 if (num_online_cpus() > 1 && !cpus_empty(l->cpus)) {
2955 n += sprintf(buf + n, " cpus=");
2956 n += cpulist_scnprintf(buf + n, PAGE_SIZE - n - 50,
2957 l->cpus);
2958 }
2959
2960 if (num_online_nodes() > 1 && !nodes_empty(l->nodes)) {
2961 n += sprintf(buf + n, " nodes=");
2962 n += nodelist_scnprintf(buf + n, PAGE_SIZE - n - 50,
2963 l->nodes);
2964 }
2965
2900 n += sprintf(buf + n, "\n"); 2966 n += sprintf(buf + n, "\n");
2901 } 2967 }
2902 2968