From: Christoph Lameter --- Documentation/vm/slabinfo.c | 28 ++++++++++++++++++++++------ include/linux/slub_def.h | 6 ++++++ mm/slub.c | 29 +++++++++++++++++++++++++++-- 3 files changed, 55 insertions(+), 8 deletions(-) Index: linux-2.6/include/linux/slub_def.h =================================================================== --- linux-2.6.orig/include/linux/slub_def.h 2008-04-02 21:34:31.077507957 -0700 +++ linux-2.6/include/linux/slub_def.h 2008-04-02 21:42:33.206376109 -0700 @@ -30,6 +30,12 @@ enum stat_item { DEACTIVATE_TO_TAIL, /* Cpu slab was moved to the tail of partials */ DEACTIVATE_REMOTE_FREES,/* Slab contained remotely freed objects */ ORDER_FALLBACK, /* Number of times fallback was necessary */ + SHRINK_CALLS, /* Number of invocations of kmem_cache_shrink */ + SHRINK_ATTEMPT_DEFRAG, /* Slabs that were attempted to be reclaimed */ + SHRINK_EMPTY_SLAB, /* Shrink encountered and freed empty slab */ + SHRINK_SLAB_SKIPPED, /* Slab reclaim skipped an slab (busy etc) */ + SHRINK_SLAB_RECLAIMED, /* Successfully reclaimed slabs */ + SHRINK_OBJECT_RECLAIM_FAILED, /* Callbacks signaled busy objects */ NR_SLUB_STAT_ITEMS }; struct kmem_cache_cpu { Index: linux-2.6/mm/slub.c =================================================================== --- linux-2.6.orig/mm/slub.c 2008-04-02 21:34:31.087506587 -0700 +++ linux-2.6/mm/slub.c 2008-04-02 21:41:53.547467763 -0700 @@ -2820,6 +2820,7 @@ static int kmem_cache_vacate(struct page void *private; unsigned long flags; unsigned long objects; + struct kmem_cache_cpu *c; BUG_ON(!PageSlab(page)); local_irq_save(flags); @@ -2828,9 +2829,12 @@ static int kmem_cache_vacate(struct page s = page->slab; objects = page->objects; + c= get_cpu_slab(s, smp_processor_id()); map = scratch + max_defrag_slab_objects * sizeof(void **); - if (!page->inuse || !s->kick || !SlabKickable(page)) + if (!page->inuse || !s->kick || !SlabKickable(page)) { + stat(c, SHRINK_SLAB_SKIPPED); goto out; + } /* Determine used objects */ bitmap_fill(map, objects); @@ -2866,8 +2870,12 @@ out: * Check the result and unfreeze the slab */ leftover = page->inuse; - if (leftover) + if (leftover) { + stat(c, SHRINK_OBJECT_RECLAIM_FAILED); ClearSlabKickable(page); + } else + stat(c, SHRINK_SLAB_RECLAIMED); + unfreeze_slab(s, page, leftover > 0); local_irq_restore(flags); return leftover; @@ -2913,11 +2921,14 @@ static unsigned long __kmem_cache_shrink LIST_HEAD(zaplist); int freed = 0; struct kmem_cache_node *n = get_node(s, node); + struct kmem_cache_cpu *c; if (n->nr_partial <= limit) return 0; spin_lock_irqsave(&n->list_lock, flags); + c = get_cpu_slab(s, smp_processor_id()); + stat(c, SHRINK_CALLS); list_for_each_entry_safe(page, page2, &n->partial, lru) { if (page->inuse) { @@ -2933,12 +2944,14 @@ static unsigned long __kmem_cache_shrink list_move(&page->lru, &zaplist); if (s->kick) { + stat(c, SHRINK_ATTEMPT_DEFRAG); n->nr_partial--; SetSlabFrozen(page); } slab_unlock(page); } else { + stat(c, SHRINK_EMPTY_SLAB); list_del(&page->lru); n->nr_partial--; slab_unlock(page); @@ -4305,6 +4318,12 @@ STAT_ATTR(DEACTIVATE_TO_HEAD, deactivate STAT_ATTR(DEACTIVATE_TO_TAIL, deactivate_to_tail); STAT_ATTR(DEACTIVATE_REMOTE_FREES, deactivate_remote_frees); STAT_ATTR(ORDER_FALLBACK, order_fallback); +STAT_ATTR(SHRINK_CALLS, shrink_calls); +STAT_ATTR(SHRINK_ATTEMPT_DEFRAG, shrink_attempt_defrag); +STAT_ATTR(SHRINK_EMPTY_SLAB, shrink_empty_slab); +STAT_ATTR(SHRINK_SLAB_SKIPPED, shrink_slab_skipped); +STAT_ATTR(SHRINK_SLAB_RECLAIMED, shrink_slab_reclaimed); +STAT_ATTR(SHRINK_OBJECT_RECLAIM_FAILED, shrink_object_reclaim_failed); #endif static struct attribute *slab_attrs[] = { @@ -4359,6 +4378,12 @@ static struct attribute *slab_attrs[] = &deactivate_to_tail_attr.attr, &deactivate_remote_frees_attr.attr, &order_fallback_attr.attr, + &shrink_calls_attr.attr, + &shrink_attempt_defrag_attr.attr, + &shrink_empty_slab_attr.attr, + &shrink_slab_skipped_attr.attr, + &shrink_slab_reclaimed_attr.attr, + &shrink_object_reclaim_failed_attr.attr, #endif NULL }; Index: linux-2.6/Documentation/vm/slabinfo.c =================================================================== --- linux-2.6.orig/Documentation/vm/slabinfo.c 2008-04-02 21:34:31.107507370 -0700 +++ linux-2.6/Documentation/vm/slabinfo.c 2008-04-02 21:46:12.434529498 -0700 @@ -41,6 +41,9 @@ struct slabinfo { unsigned long cpuslab_flush, deactivate_full, deactivate_empty; unsigned long deactivate_to_head, deactivate_to_tail; unsigned long deactivate_remote_frees; + unsigned long shrink_calls, shrink_attempt_defrag, shrink_empty_slab; + unsigned long shrink_slab_skipped, shrink_slab_reclaimed; + unsigned long shrink_object_reclaim_failure; int numa[MAX_NODES]; int numa_partial[MAX_NODES]; } slabinfo[MAX_SLABS]; @@ -466,22 +469,28 @@ void slab_stats(struct slabinfo *s) printf("Total %8lu %8lu\n\n", total_alloc, total_free); - if (s->cpuslab_flush) - printf("Flushes %8lu\n", s->cpuslab_flush); - - if (s->alloc_refill) - printf("Refill %8lu\n", s->alloc_refill); + if (s->cpuslab_flush || s->alloc_refill) + printf("CPU Slab : Flushes=%lu Refills=%lu\n", + s->cpuslab_flush, s->alloc_refill); total = s->deactivate_full + s->deactivate_empty + s->deactivate_to_head + s->deactivate_to_tail; if (total) - printf("Deactivate Full=%lu(%lu%%) Empty=%lu(%lu%%) " + printf("Deactivate: Full=%lu(%lu%%) Empty=%lu(%lu%%) " "ToHead=%lu(%lu%%) ToTail=%lu(%lu%%)\n", s->deactivate_full, (s->deactivate_full * 100) / total, s->deactivate_empty, (s->deactivate_empty * 100) / total, s->deactivate_to_head, (s->deactivate_to_head * 100) / total, s->deactivate_to_tail, (s->deactivate_to_tail * 100) / total); + + if (s->shrink_calls) + printf("Shrink : Calls=%lu Attempts=%lu Empty=%lu Successful=%lu\n", + s->shrink_calls, s->shrink_attempt_defrag, + s->shrink_empty_slab, s->shrink_slab_reclaimed); + if (s->shrink_slab_skipped || s->shrink_object_reclaim_failure) + printf("Defrag : Slabs skipped=%lu Object reclaim failure=%lu\n", + s->shrink_slab_skipped, s->shrink_object_reclaim_failure); } void report(struct slabinfo *s) @@ -1208,6 +1217,13 @@ void read_slab_dir(void) slab->deactivate_to_head = get_obj("deactivate_to_head"); slab->deactivate_to_tail = get_obj("deactivate_to_tail"); slab->deactivate_remote_frees = get_obj("deactivate_remote_frees"); + slab->shrink_calls = get_obj("shrink_calls"); + slab->shrink_attempt_defrag = get_obj("shrink_attempt_defrag"); + slab->shrink_empty_slab = get_obj("shrink_empty_slab"); + slab->shrink_slab_skipped = get_obj("shrink_slab_skipped"); + slab->shrink_slab_reclaimed = get_obj("shrink_slab_reclaimed"); + slab->shrink_object_reclaim_failure = + get_obj("shrink_object_reclaim_failure"); slab->defrag_ratio = get_obj("defrag_ratio"); slab->remote_node_defrag_ratio = get_obj("remote_node_defrag_ratio");