So, after some modifications and guidance from rwatson, alc and others, I've modified this patch a bit. The end result is that a sleep on slab alloc counter is displayed with a "vmstat -z". This can be used for diagnostics of low memory situations and has been VERY handy at Yahoo.
I've removed the sysctl to eliminate some heartache, moved the sleep count into a proper place in the data structure, properly instrumented the debugger function and returned the #ifdef. Patch provided against -current. Tested on amd64 and x86 Sean
Index: usr.bin/vmstat/vmstat.c =================================================================== --- usr.bin/vmstat/vmstat.c (revision 209161) +++ usr.bin/vmstat/vmstat.c (working copy) @@ -1294,16 +1294,17 @@ memstat_strerror(error)); } } - printf("%-20s %8s %8s %8s %8s %8s %8s\n\n", "ITEM", "SIZE", - "LIMIT", "USED", "FREE", "REQUESTS", "FAILURES"); + printf("%-20s %6s %6s %8s %8s %8s %4s %4s\n\n", "ITEM", "SIZE", + "LIMIT", "USED", "FREE", "REQ", "FAIL", "SLEEP"); for (mtp = memstat_mtl_first(mtlp); mtp != NULL; mtp = memstat_mtl_next(mtp)) { strlcpy(name, memstat_get_name(mtp), MEMTYPE_MAXNAME); strcat(name, ":"); - printf("%-20s %8llu, %8llu, %8llu, %8llu, %8llu, %8llu\n", name, + printf("%-20s %6llu, %6llu,%8llu,%8llu,%8llu,%4llu,%4llu\n",name, memstat_get_size(mtp), memstat_get_countlimit(mtp), memstat_get_count(mtp), memstat_get_free(mtp), - memstat_get_numallocs(mtp), memstat_get_failures(mtp)); + memstat_get_numallocs(mtp), memstat_get_failures(mtp), + memstat_get_sleeps(mtp)); } memstat_mtl_free(mtlp); printf("\n"); Index: lib/libmemstat/memstat.h =================================================================== --- lib/libmemstat/memstat.h (revision 209161) +++ lib/libmemstat/memstat.h (working copy) @@ -139,6 +139,7 @@ uint64_t memstat_get_count(const struct memory_type *mtp); uint64_t memstat_get_free(const struct memory_type *mtp); uint64_t memstat_get_failures(const struct memory_type *mtp); +uint64_t memstat_get_sleeps(const struct memory_type *mtp); void *memstat_get_caller_pointer(const struct memory_type *mtp, int index); void memstat_set_caller_pointer(struct memory_type *mtp, Index: lib/libmemstat/memstat.c =================================================================== --- lib/libmemstat/memstat.c (revision 209161) +++ lib/libmemstat/memstat.c (working copy) @@ -188,6 +188,7 @@ mtp->mt_count = 0; mtp->mt_free = 0; mtp->mt_failures = 0; + mtp->mt_sleeps = 0; mtp->mt_zonefree = 0; mtp->mt_kegfree = 0; @@ -304,6 +305,13 @@ return (mtp->mt_failures); } +uint64_t +memstat_get_sleeps(const struct memory_type *mtp) +{ + + return (mtp->mt_sleeps); +} + void * memstat_get_caller_pointer(const struct memory_type *mtp, int index) { Index: lib/libmemstat/memstat_internal.h =================================================================== --- lib/libmemstat/memstat_internal.h (revision 209161) +++ lib/libmemstat/memstat_internal.h (working copy) @@ -65,6 +65,7 @@ uint64_t mt_count; /* Number of current allocations. */ uint64_t mt_free; /* Number of cached free items. */ uint64_t mt_failures; /* Number of allocation failures. */ + uint64_t mt_sleeps; /* Number of allocation sleeps. */ /* * Caller-owned memory. Index: lib/libmemstat/memstat_uma.c =================================================================== --- lib/libmemstat/memstat_uma.c (revision 209161) +++ lib/libmemstat/memstat_uma.c (working copy) @@ -208,6 +208,7 @@ mtp->mt_numallocs = uthp->uth_allocs; mtp->mt_numfrees = uthp->uth_frees; mtp->mt_failures = uthp->uth_fails; + mtp->mt_sleeps = uthp->uth_sleeps; for (j = 0; j < maxcpus; j++) { upsp = (struct uma_percpu_stat *)p; @@ -402,6 +403,7 @@ mtp->mt_numallocs = uz.uz_allocs; mtp->mt_numfrees = uz.uz_frees; mtp->mt_failures = uz.uz_fails; + mtp->mt_sleeps = uz.uz_sleeps; if (kz.uk_flags & UMA_ZFLAG_INTERNAL) goto skip_percpu; for (i = 0; i < mp_maxid + 1; i++) { Index: sys/vm/uma_int.h =================================================================== --- sys/vm/uma_int.h (revision 209161) +++ sys/vm/uma_int.h (working copy) @@ -327,6 +327,7 @@ u_int64_t uz_allocs UMA_ALIGN; /* Total number of allocations */ u_int64_t uz_frees; /* Total number of frees */ u_int64_t uz_fails; /* Total number of alloc failures */ + u_int64_t uz_sleeps; /* Total number of alloc sleeps */ uint16_t uz_fills; /* Outstanding bucket fills */ uint16_t uz_count; /* Highest value ub_ptr can have */ Index: sys/vm/uma.h =================================================================== --- sys/vm/uma.h (revision 209161) +++ sys/vm/uma.h (working copy) @@ -600,7 +600,8 @@ u_int64_t uth_allocs; /* Zone: number of allocations. */ u_int64_t uth_frees; /* Zone: number of frees. */ u_int64_t uth_fails; /* Zone: number of alloc failures. */ - u_int64_t _uth_reserved1[3]; /* Reserved. */ + u_int64_t uth_sleeps; /* Zone: number of alloc sleeps. */ + u_int64_t _uth_reserved1[2]; /* Reserved. */ }; struct uma_percpu_stat { Index: sys/vm/uma_core.c =================================================================== --- sys/vm/uma_core.c (revision 209161) +++ sys/vm/uma_core.c (working copy) @@ -1396,6 +1396,7 @@ zone->uz_allocs = 0; zone->uz_frees = 0; zone->uz_fails = 0; + zone->uz_sleeps = 0; zone->uz_fills = zone->uz_count = 0; zone->uz_flags = 0; keg = arg->keg; @@ -2283,6 +2284,7 @@ */ if (full && !empty) { zone->uz_flags |= UMA_ZFLAG_FULL; + zone->uz_sleeps++; msleep(zone, zone->uz_lock, PVM, "zonelimit", hz/100); zone->uz_flags &= ~UMA_ZFLAG_FULL; continue; @@ -3094,13 +3096,13 @@ */ static void uma_zone_sumstat(uma_zone_t z, int *cachefreep, u_int64_t *allocsp, - u_int64_t *freesp) + u_int64_t *freesp, u_int64_t *sleepsp) { uma_cache_t cache; - u_int64_t allocs, frees; + u_int64_t allocs, frees, sleeps; int cachefree, cpu; - allocs = frees = 0; + allocs = frees = sleeps = 0; cachefree = 0; CPU_FOREACH(cpu) { cache = &z->uz_cpu[cpu]; @@ -3113,12 +3115,15 @@ } allocs += z->uz_allocs; frees += z->uz_frees; + sleeps += z->uz_sleeps; if (cachefreep != NULL) *cachefreep = cachefree; if (allocsp != NULL) *allocsp = allocs; if (freesp != NULL) *freesp = frees; + if (sleepsp != NULL) + *sleepsp = sleeps; } #endif /* DDB */ @@ -3226,6 +3231,7 @@ uth.uth_allocs = z->uz_allocs; uth.uth_frees = z->uz_frees; uth.uth_fails = z->uz_fails; + uth.uth_sleeps = z->uz_sleeps; if (sbuf_bcat(&sbuf, &uth, sizeof(uth)) < 0) { ZONE_UNLOCK(z); mtx_unlock(&uma_mtx); @@ -3277,32 +3283,33 @@ #ifdef DDB DB_SHOW_COMMAND(uma, db_show_uma) { - u_int64_t allocs, frees; + u_int64_t allocs, frees, sleeps; uma_bucket_t bucket; uma_keg_t kz; uma_zone_t z; int cachefree; - db_printf("%18s %8s %8s %8s %12s\n", "Zone", "Size", "Used", "Free", - "Requests"); + db_printf("%18s %8s %8s %8s %12s %8s\n", "Zone", "Size", "Used", "Free", + "Requests", "Sleeps"); LIST_FOREACH(kz, &uma_kegs, uk_link) { LIST_FOREACH(z, &kz->uk_zones, uz_link) { if (kz->uk_flags & UMA_ZFLAG_INTERNAL) { allocs = z->uz_allocs; frees = z->uz_frees; + sleeps = z->uz_sleeps; cachefree = 0; } else uma_zone_sumstat(z, &cachefree, &allocs, - &frees); + &frees, &sleeps); if (!((z->uz_flags & UMA_ZONE_SECONDARY) && (LIST_FIRST(&kz->uk_zones) != z))) cachefree += kz->uk_free; LIST_FOREACH(bucket, &z->uz_full_bucket, ub_link) cachefree += bucket->ub_cnt; - db_printf("%18s %8ju %8jd %8d %12ju\n", z->uz_name, + db_printf("%18s %8ju %8jd %8d %12ju %8ju\n", z->uz_name, (uintmax_t)kz->uk_size, (intmax_t)(allocs - frees), cachefree, - (uintmax_t)allocs); + (uintmax_t)allocs, sleeps); } } }
_______________________________________________ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"