Changeset View
Standalone View
sys/vm/uma_core.c
Show First 20 Lines • Show All 450 Lines • ▼ Show 20 Lines | |||||
bucket_zone_drain(void) | bucket_zone_drain(void) | ||||
{ | { | ||||
struct uma_bucket_zone *ubz; | struct uma_bucket_zone *ubz; | ||||
for (ubz = &bucket_zones[0]; ubz->ubz_entries != 0; ubz++) | for (ubz = &bucket_zones[0]; ubz->ubz_entries != 0; ubz++) | ||||
zone_drain(ubz->ubz_zone); | zone_drain(ubz->ubz_zone); | ||||
} | } | ||||
static uma_bucket_t | |||||
zone_try_fetch_bucket(uma_zone_t zone, uma_zone_domain_t zdom, const bool ws) | |||||
{ | |||||
uma_bucket_t bucket; | |||||
jeff: lock asserts please | |||||
if ((bucket = LIST_FIRST(&zdom->uzd_buckets)) != NULL) { | |||||
MPASS(zdom->uzd_nitems >= bucket->ub_cnt); | |||||
LIST_REMOVE(bucket, ub_link); | |||||
zdom->uzd_nitems -= bucket->ub_cnt; | |||||
if (ws && zdom->uzd_imin > zdom->uzd_nitems) | |||||
zdom->uzd_imin = zdom->uzd_nitems; | |||||
} else if (ws) | |||||
zdom->uzd_imax += zone->uz_count; | |||||
jeffUnsubmitted Done Inline ActionsShouldn't this be done where we actually allocate the bucket? jeff: Shouldn't this be done where we actually allocate the bucket? | |||||
return (bucket); | |||||
} | |||||
static void | static void | ||||
zone_put_bucket(uma_zone_domain_t zdom, uma_bucket_t bucket, const bool ws) | |||||
{ | |||||
LIST_INSERT_HEAD(&zdom->uzd_buckets, bucket, ub_link); | |||||
zdom->uzd_nitems += bucket->ub_cnt; | |||||
if (ws && zdom->uzd_imax < zdom->uzd_nitems) | |||||
zdom->uzd_imax = zdom->uzd_nitems; | |||||
} | |||||
static void | |||||
zone_log_warning(uma_zone_t zone) | zone_log_warning(uma_zone_t zone) | ||||
{ | { | ||||
static const struct timeval warninterval = { 300, 0 }; | static const struct timeval warninterval = { 300, 0 }; | ||||
if (!zone_warnings || zone->uz_warning == NULL) | if (!zone_warnings || zone->uz_warning == NULL) | ||||
return; | return; | ||||
if (ratecheck(&zone->uz_ratecheck, &warninterval)) | if (ratecheck(&zone->uz_ratecheck, &warninterval)) | ||||
Show All 32 Lines | |||||
{ | { | ||||
bucket_enable(); | bucket_enable(); | ||||
zone_foreach(zone_timeout); | zone_foreach(zone_timeout); | ||||
/* Reschedule this event */ | /* Reschedule this event */ | ||||
callout_reset(&uma_callout, UMA_TIMEOUT * hz, uma_timeout, NULL); | callout_reset(&uma_callout, UMA_TIMEOUT * hz, uma_timeout, NULL); | ||||
} | } | ||||
/* XXX */ | |||||
static void | |||||
zone_domain_update_wss(uma_zone_domain_t zdom) | |||||
{ | |||||
long wss; | |||||
MPASS(zdom->uzd_imax >= zdom->uzd_imin); | |||||
wss = zdom->uzd_imax - zdom->uzd_imin; | |||||
zdom->uzd_imax = zdom->uzd_imin = zdom->uzd_nitems; | |||||
zdom->uzd_wss = (3 * wss + 2 * zdom->uzd_wss) / 5; | |||||
Done Inline ActionsUnless you think overflow is likely, it would be better to write this as: = (4 * wss + zdom->uzd_wss) / 5; alc: Unless you think overflow is likely, it would be better to write this as:
```
= (4 * wss + zdom… | |||||
Not Done Inline ActionsP.S. I'm also surprised by the extremely rapid decay. Was there a rationale? alc: P.S. I'm also surprised by the extremely rapid decay. Was there a rationale? | |||||
Not Done Inline ActionsThere isn't much of a rationale for the specific weights here. I was thinking about the long (20s) update period relative to the lowmem period of 10s. I do agree that the estimate decays perhaps too quickly, and would consider giving more weight to the tail. I haven't been able to come up with workloads where the difference is measurable, though. markj: There isn't much of a rationale for the specific weights here. I was thinking about the long… | |||||
Not Done Inline ActionsBonwick observed in his paper that flushing everything gave similar performance in his tests to flushing less. So it seems that he didn't spend a lot of effort tuning it. I think a minute or so is probably reasonable for decay. We could import and use an actual EMA algorithm although the scheduler doesn't use anything more complicated than this either. jeff: Bonwick observed in his paper that flushing everything gave similar performance in his tests to… | |||||
Done Inline Actions
I would suggest saying these things explicitly in the comment at the head of the function. alc: > .There isn't much of a rationale for the specific weights here. I was thinking about the long… | |||||
} | |||||
/* | /* | ||||
* Routine to perform timeout driven calculations. This expands the | * Routine to perform timeout driven calculations. This expands the | ||||
* hashes and does per cpu statistics aggregation. | * hashes and does per cpu statistics aggregation. | ||||
* | * | ||||
* Returns nothing. | * Returns nothing. | ||||
*/ | */ | ||||
static void | static void | ||||
keg_timeout(uma_keg_t keg) | keg_timeout(uma_keg_t keg) | ||||
Show All 36 Lines | if (keg->uk_flags & UMA_ZONE_HASH && | ||||
} | } | ||||
} | } | ||||
KEG_UNLOCK(keg); | KEG_UNLOCK(keg); | ||||
} | } | ||||
static void | static void | ||||
zone_timeout(uma_zone_t zone) | zone_timeout(uma_zone_t zone) | ||||
{ | { | ||||
int i; | |||||
zone_foreach_keg(zone, &keg_timeout); | zone_foreach_keg(zone, &keg_timeout); | ||||
ZONE_LOCK(zone); | |||||
for (i = 0; i < vm_ndomains; i++) | |||||
zone_domain_update_wss(&zone->uz_domain[i]); | |||||
ZONE_UNLOCK(zone); | |||||
} | } | ||||
/* | /* | ||||
* Allocate and zero fill the next sized hash table from the appropriate | * Allocate and zero fill the next sized hash table from the appropriate | ||||
* backing store. | * backing store. | ||||
* | * | ||||
* Arguments: | * Arguments: | ||||
* hash A new hash structure with the old hash size in uh_hashsize | * hash A new hash structure with the old hash size in uh_hashsize | ||||
▲ Show 20 Lines • Show All 194 Lines • ▼ Show 20 Lines | cache_drain_safe_cpu(uma_zone_t zone) | ||||
critical_enter(); | critical_enter(); | ||||
if (zone->uz_flags & UMA_ZONE_NUMA) | if (zone->uz_flags & UMA_ZONE_NUMA) | ||||
domain = PCPU_GET(domain); | domain = PCPU_GET(domain); | ||||
else | else | ||||
domain = 0; | domain = 0; | ||||
cache = &zone->uz_cpu[curcpu]; | cache = &zone->uz_cpu[curcpu]; | ||||
if (cache->uc_allocbucket) { | if (cache->uc_allocbucket) { | ||||
if (cache->uc_allocbucket->ub_cnt != 0) | if (cache->uc_allocbucket->ub_cnt != 0) | ||||
LIST_INSERT_HEAD(&zone->uz_domain[domain].uzd_buckets, | zone_put_bucket(&zone->uz_domain[domain], | ||||
cache->uc_allocbucket, ub_link); | cache->uc_allocbucket, false); | ||||
else | else | ||||
b1 = cache->uc_allocbucket; | b1 = cache->uc_allocbucket; | ||||
cache->uc_allocbucket = NULL; | cache->uc_allocbucket = NULL; | ||||
} | } | ||||
if (cache->uc_freebucket) { | if (cache->uc_freebucket) { | ||||
if (cache->uc_freebucket->ub_cnt != 0) | if (cache->uc_freebucket->ub_cnt != 0) | ||||
LIST_INSERT_HEAD(&zone->uz_domain[domain].uzd_buckets, | zone_put_bucket(&zone->uz_domain[domain], | ||||
cache->uc_freebucket, ub_link); | cache->uc_freebucket, false); | ||||
else | else | ||||
b2 = cache->uc_freebucket; | b2 = cache->uc_freebucket; | ||||
cache->uc_freebucket = NULL; | cache->uc_freebucket = NULL; | ||||
} | } | ||||
critical_exit(); | critical_exit(); | ||||
ZONE_UNLOCK(zone); | ZONE_UNLOCK(zone); | ||||
if (b1) | if (b1) | ||||
bucket_free(zone, b1, NULL); | bucket_free(zone, b1, NULL); | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | bucket_cache_drain(uma_zone_t zone) | ||||
uma_zone_domain_t zdom; | uma_zone_domain_t zdom; | ||||
uma_bucket_t bucket; | uma_bucket_t bucket; | ||||
int i; | int i; | ||||
/* | /* | ||||
* Drain the bucket queues and free the buckets. | * Drain the bucket queues and free the buckets. | ||||
*/ | */ | ||||
for (i = 0; i < vm_ndomains; i++) { | for (i = 0; i < vm_ndomains; i++) { | ||||
zdom = &zone->uz_domain[i]; | zdom = &zone->uz_domain[i]; | ||||
while ((bucket = LIST_FIRST(&zdom->uzd_buckets)) != NULL) { | while ((bucket = zone_try_fetch_bucket(zone, zdom, false)) != | ||||
LIST_REMOVE(bucket, ub_link); | NULL) { | ||||
ZONE_UNLOCK(zone); | ZONE_UNLOCK(zone); | ||||
bucket_drain(zone, bucket); | bucket_drain(zone, bucket); | ||||
bucket_free(zone, bucket, NULL); | bucket_free(zone, bucket, NULL); | ||||
ZONE_LOCK(zone); | ZONE_LOCK(zone); | ||||
} | } | ||||
Not Done Inline ActionsShould you reset the imin and imax counts here? After this drain operation, for a time, every "try fetch" is going to add to an imax value that is still based on the pre-drain state. And, when you eventually recycle a bucket, the imin value will get updated to something close to zero. So, there will be an exaggerated difference between imin and imax, which will inflate the moving average. alc: Should you reset the imin and imax counts here? After this drain operation, for a time, every… | |||||
Not Done Inline ActionsWouldn't resetting imin = imax = nitems effectively just throw away the history accumulated since the last update to wss? That could deflate the moving average. Could we, instead of freeing nitems - wss items when trimming, free MIN(imin, nitems - wss) items, and subtract the number of reclaimed items from both imin and imax so that all three of imin, imax and nitems are shifted by the same amount? Suppose imax - imin < wss. Then nitems - imin < wss, so nitems - wss < imin and we'll get the same reclamation target as before. Now suppose imax - imin >= wss, i.e., the WSS estimate for the cache will grow upon its next update. If we free only imin items in this case, we're ignoring the history of the WSS estimate before the most recent update, but I don't think that that's unreasonable: with the current patch we're ignoring the WSS estimate for the current interval, which is undesirable if the average of the estimate is growing. Moreover, if imax - imin is close to wss, then nitems - wss will be close to imin, so the WSS estimate would have to be growing by a large amount for the proposed change to have a significant effect. markj: Wouldn't resetting imin = imax = nitems effectively just throw away the history accumulated… | |||||
Not Done Inline Actions
Briefly, yes. However, given the long time period between wss updates, I would expect them to reconverge before the next wss update. Essentially, my earlier comment pointed out a calculation error that can arise in one direction, resulting in a too large wss estimate. And, your followup points out an error that can arise in the other direction, leading to a too small wss estimate, if we reset the counts. I think that the difference between these two calculation errors is that the first will persist until the end of the time period and the second will likely disappear before the end of the time period.
Yes, I like this much better. Do it. In particular, when the wss is growing, I think that ignoring the historical average is sound practice. Once you've done this, I would probably change the moving average calculation to be a more conventional (wss + 4 * zdom->uzd_wss) / 5. alc: > Wouldn't resetting imin = imax = nitems effectively just throw away the history accumulated… | |||||
Done Inline Actions(This discussion really applies to D16667 and will be handled there.) markj: (This discussion really applies to D16667 and will be handled there.) | |||||
} | } | ||||
/* | /* | ||||
* Shrink further bucket sizes. Price of single zone lock collision | * Shrink further bucket sizes. Price of single zone lock collision | ||||
* is probably lower then price of global cache drain. | * is probably lower then price of global cache drain. | ||||
*/ | */ | ||||
if (zone->uz_count > zone->uz_count_min) | if (zone->uz_count > zone->uz_count_min) | ||||
zone->uz_count--; | zone->uz_count--; | ||||
▲ Show 20 Lines • Show All 1,649 Lines • ▼ Show 20 Lines | #endif | ||||
/* | /* | ||||
* Check the zone's cache of buckets. | * Check the zone's cache of buckets. | ||||
*/ | */ | ||||
if (domain == UMA_ANYDOMAIN) | if (domain == UMA_ANYDOMAIN) | ||||
zdom = &zone->uz_domain[0]; | zdom = &zone->uz_domain[0]; | ||||
else | else | ||||
zdom = &zone->uz_domain[domain]; | zdom = &zone->uz_domain[domain]; | ||||
if ((bucket = LIST_FIRST(&zdom->uzd_buckets)) != NULL) { | if ((bucket = zone_try_fetch_bucket(zone, zdom, true)) != NULL) { | ||||
Done Inline ActionsSuppose two processors fail at this one after the other, specifically, where the second fails before the first has succeeded in allocating a fresh, filled bucket. Won't this inflate the difference between uzd_imax and uzd_imin? If a processor gets to the comment "See if we lost the race or were migrated. ...", and it lost the race, should it increase uzd_imin to reflect the unneeded/unused bucket? alc: Suppose two processors fail at this one after the other, specifically, where the second fails… | |||||
Done Inline ActionsDid you mean to write "threads" instead of "processors"? If so, I agree. markj: Did you mean to write "threads" instead of "processors"? If so, I agree. | |||||
Done Inline ActionsYes. alc: Yes. | |||||
KASSERT(bucket->ub_cnt != 0, | KASSERT(bucket->ub_cnt != 0, | ||||
("uma_zalloc_arg: Returning an empty bucket.")); | ("uma_zalloc_arg: Returning an empty bucket.")); | ||||
LIST_REMOVE(bucket, ub_link); | |||||
cache->uc_allocbucket = bucket; | cache->uc_allocbucket = bucket; | ||||
ZONE_UNLOCK(zone); | ZONE_UNLOCK(zone); | ||||
goto zalloc_start; | goto zalloc_start; | ||||
} | } | ||||
/* We are no longer associated with this CPU. */ | /* We are no longer associated with this CPU. */ | ||||
critical_exit(); | critical_exit(); | ||||
/* | /* | ||||
Show All 15 Lines | #endif | ||||
if (bucket != NULL) { | if (bucket != NULL) { | ||||
ZONE_LOCK(zone); | ZONE_LOCK(zone); | ||||
critical_enter(); | critical_enter(); | ||||
cpu = curcpu; | cpu = curcpu; | ||||
cache = &zone->uz_cpu[cpu]; | cache = &zone->uz_cpu[cpu]; | ||||
/* | /* | ||||
* See if we lost the race or were migrated. Cache the | * See if we lost the race or were migrated. Cache the | ||||
* initialized bucket to make this less likely or claim | * initialized bucket to make this less likely or claim | ||||
* the memory directly. | * the memory directly. We have already accounted for | ||||
* this bucket in the working set. | |||||
*/ | */ | ||||
if (cache->uc_allocbucket != NULL || | if (cache->uc_allocbucket != NULL || | ||||
(zone->uz_flags & UMA_ZONE_NUMA && | (zone->uz_flags & UMA_ZONE_NUMA && | ||||
Done Inline ActionsTesting domain != UMA_ANYDOMAIN here would avoid a memory dereference and be no less clear. alc: Testing `domain != UMA_ANYDOMAIN` here would avoid a memory dereference and be no less clear. | |||||
domain != PCPU_GET(domain))) | domain != PCPU_GET(domain))) | ||||
LIST_INSERT_HEAD(&zdom->uzd_buckets, bucket, ub_link); | zone_put_bucket(zdom, bucket, false); | ||||
else | else | ||||
cache->uc_allocbucket = bucket; | cache->uc_allocbucket = bucket; | ||||
ZONE_UNLOCK(zone); | ZONE_UNLOCK(zone); | ||||
goto zalloc_start; | goto zalloc_start; | ||||
} | } | ||||
/* | /* | ||||
* We may not be able to get a bucket so return an actual item. | * We may not be able to get a bucket so return an actual item. | ||||
▲ Show 20 Lines • Show All 593 Lines • ▼ Show 20 Lines | if (bucket != NULL) { | ||||
KASSERT(bucket->ub_cnt != 0, | KASSERT(bucket->ub_cnt != 0, | ||||
("uma_zfree: Attempting to insert an empty bucket onto the full list.\n")); | ("uma_zfree: Attempting to insert an empty bucket onto the full list.\n")); | ||||
if ((zone->uz_flags & UMA_ZONE_NOBUCKETCACHE) != 0) { | if ((zone->uz_flags & UMA_ZONE_NOBUCKETCACHE) != 0) { | ||||
ZONE_UNLOCK(zone); | ZONE_UNLOCK(zone); | ||||
bucket_drain(zone, bucket); | bucket_drain(zone, bucket); | ||||
bucket_free(zone, bucket, udata); | bucket_free(zone, bucket, udata); | ||||
goto zfree_restart; | goto zfree_restart; | ||||
} else | } else | ||||
LIST_INSERT_HEAD(&zdom->uzd_buckets, bucket, ub_link); | zone_put_bucket(zdom, bucket, true); | ||||
} | } | ||||
/* | /* | ||||
* We bump the uz count when the cache size is insufficient to | * We bump the uz count when the cache size is insufficient to | ||||
* handle the working set. | * handle the working set. | ||||
*/ | */ | ||||
if (lockfail && zone->uz_count < BUCKET_MAX) | if (lockfail && zone->uz_count < BUCKET_MAX) | ||||
zone->uz_count++; | zone->uz_count++; | ||||
▲ Show 20 Lines • Show All 430 Lines • ▼ Show 20 Lines | uma_reclaim_locked(bool kmem_danger) | ||||
CTR0(KTR_UMA, "UMA: vm asked us to release pages!"); | CTR0(KTR_UMA, "UMA: vm asked us to release pages!"); | ||||
sx_assert(&uma_drain_lock, SA_XLOCKED); | sx_assert(&uma_drain_lock, SA_XLOCKED); | ||||
bucket_enable(); | bucket_enable(); | ||||
zone_foreach(zone_drain); | zone_foreach(zone_drain); | ||||
if (vm_page_count_min() || kmem_danger) { | if (vm_page_count_min() || kmem_danger) { | ||||
cache_drain_safe(NULL); | cache_drain_safe(NULL); | ||||
zone_foreach(zone_drain); | zone_foreach(zone_drain); | ||||
} | } | ||||
/* | /* | ||||
* Some slabs may have been freed but this zone will be visited early | * Some slabs may have been freed but this zone will be visited early | ||||
* we visit again so that we can free pages that are empty once other | * we visit again so that we can free pages that are empty once other | ||||
* zones are drained. We have to do the same for buckets. | * zones are drained. We have to do the same for buckets. | ||||
*/ | */ | ||||
zone_drain(slabzone); | zone_drain(slabzone); | ||||
bucket_zone_drain(); | bucket_zone_drain(); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 235 Lines • ▼ Show 20 Lines | |||||
* Note: does not update the zone statistics, as it can't safely clear the | * Note: does not update the zone statistics, as it can't safely clear the | ||||
* per-CPU cache statistic. | * per-CPU cache statistic. | ||||
* | * | ||||
* XXXRW: Following the uc_allocbucket and uc_freebucket pointers here isn't | * XXXRW: Following the uc_allocbucket and uc_freebucket pointers here isn't | ||||
* safe from off-CPU; we should modify the caches to track this information | * safe from off-CPU; we should modify the caches to track this information | ||||
* directly so that we don't have to. | * directly so that we don't have to. | ||||
*/ | */ | ||||
static void | static void | ||||
uma_zone_sumstat(uma_zone_t z, int *cachefreep, uint64_t *allocsp, | uma_zone_sumstat(uma_zone_t z, long *cachefreep, uint64_t *allocsp, | ||||
uint64_t *freesp, uint64_t *sleepsp) | uint64_t *freesp, uint64_t *sleepsp) | ||||
{ | { | ||||
uma_cache_t cache; | uma_cache_t cache; | ||||
uint64_t allocs, frees, sleeps; | uint64_t allocs, frees, sleeps; | ||||
int cachefree, cpu; | int cachefree, cpu; | ||||
allocs = frees = sleeps = 0; | allocs = frees = sleeps = 0; | ||||
cachefree = 0; | cachefree = 0; | ||||
Show All 38 Lines | |||||
} | } | ||||
static int | static int | ||||
sysctl_vm_zone_stats(SYSCTL_HANDLER_ARGS) | sysctl_vm_zone_stats(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct uma_stream_header ush; | struct uma_stream_header ush; | ||||
struct uma_type_header uth; | struct uma_type_header uth; | ||||
struct uma_percpu_stat *ups; | struct uma_percpu_stat *ups; | ||||
uma_bucket_t bucket; | |||||
uma_zone_domain_t zdom; | uma_zone_domain_t zdom; | ||||
struct sbuf sbuf; | struct sbuf sbuf; | ||||
uma_cache_t cache; | uma_cache_t cache; | ||||
uma_klink_t kl; | uma_klink_t kl; | ||||
uma_keg_t kz; | uma_keg_t kz; | ||||
uma_zone_t z; | uma_zone_t z; | ||||
uma_keg_t k; | uma_keg_t k; | ||||
int count, error, i; | int count, error, i; | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | LIST_FOREACH(z, &kz->uk_zones, uz_link) { | ||||
* on the keg's zone list. | * on the keg's zone list. | ||||
*/ | */ | ||||
if ((z->uz_flags & UMA_ZONE_SECONDARY) && | if ((z->uz_flags & UMA_ZONE_SECONDARY) && | ||||
(LIST_FIRST(&kz->uk_zones) != z)) | (LIST_FIRST(&kz->uk_zones) != z)) | ||||
uth.uth_zone_flags = UTH_ZONE_SECONDARY; | uth.uth_zone_flags = UTH_ZONE_SECONDARY; | ||||
for (i = 0; i < vm_ndomains; i++) { | for (i = 0; i < vm_ndomains; i++) { | ||||
zdom = &z->uz_domain[i]; | zdom = &z->uz_domain[i]; | ||||
LIST_FOREACH(bucket, &zdom->uzd_buckets, | uth.uth_zone_free += zdom->uzd_nitems; | ||||
ub_link) | |||||
uth.uth_zone_free += bucket->ub_cnt; | |||||
} | } | ||||
uth.uth_allocs = z->uz_allocs; | uth.uth_allocs = z->uz_allocs; | ||||
uth.uth_frees = z->uz_frees; | uth.uth_frees = z->uz_frees; | ||||
uth.uth_fails = z->uz_fails; | uth.uth_fails = z->uz_fails; | ||||
uth.uth_sleeps = z->uz_sleeps; | uth.uth_sleeps = z->uz_sleeps; | ||||
/* | /* | ||||
* While it is not normally safe to access the cache | * While it is not normally safe to access the cache | ||||
* bucket pointers while not on the CPU that owns the | * bucket pointers while not on the CPU that owns the | ||||
▲ Show 20 Lines • Show All 183 Lines • ▼ Show 20 Lines | uma_dbg_free(uma_zone_t zone, uma_slab_t slab, void *item) | ||||
BIT_CLR_ATOMIC(SLAB_SETSIZE, freei, &slab->us_debugfree); | BIT_CLR_ATOMIC(SLAB_SETSIZE, freei, &slab->us_debugfree); | ||||
} | } | ||||
#endif /* INVARIANTS */ | #endif /* INVARIANTS */ | ||||
#ifdef DDB | #ifdef DDB | ||||
DB_SHOW_COMMAND(uma, db_show_uma) | DB_SHOW_COMMAND(uma, db_show_uma) | ||||
{ | { | ||||
uma_bucket_t bucket; | |||||
uma_keg_t kz; | uma_keg_t kz; | ||||
uma_zone_t z; | uma_zone_t z; | ||||
uma_zone_domain_t zdom; | |||||
uint64_t allocs, frees, sleeps; | uint64_t allocs, frees, sleeps; | ||||
int cachefree, i; | long cachefree; | ||||
int i; | |||||
db_printf("%18s %8s %8s %8s %12s %8s %8s\n", "Zone", "Size", "Used", | db_printf("%18s %8s %8s %8s %12s %8s %8s\n", "Zone", "Size", "Used", | ||||
"Free", "Requests", "Sleeps", "Bucket"); | "Free", "Requests", "Sleeps", "Bucket"); | ||||
LIST_FOREACH(kz, &uma_kegs, uk_link) { | LIST_FOREACH(kz, &uma_kegs, uk_link) { | ||||
LIST_FOREACH(z, &kz->uk_zones, uz_link) { | LIST_FOREACH(z, &kz->uk_zones, uz_link) { | ||||
if (kz->uk_flags & UMA_ZFLAG_INTERNAL) { | if (kz->uk_flags & UMA_ZFLAG_INTERNAL) { | ||||
allocs = z->uz_allocs; | allocs = z->uz_allocs; | ||||
frees = z->uz_frees; | frees = z->uz_frees; | ||||
sleeps = z->uz_sleeps; | sleeps = z->uz_sleeps; | ||||
cachefree = 0; | cachefree = 0; | ||||
} else | } else | ||||
uma_zone_sumstat(z, &cachefree, &allocs, | uma_zone_sumstat(z, &cachefree, &allocs, | ||||
&frees, &sleeps); | &frees, &sleeps); | ||||
if (!((z->uz_flags & UMA_ZONE_SECONDARY) && | if (!((z->uz_flags & UMA_ZONE_SECONDARY) && | ||||
(LIST_FIRST(&kz->uk_zones) != z))) | (LIST_FIRST(&kz->uk_zones) != z))) | ||||
cachefree += kz->uk_free; | cachefree += kz->uk_free; | ||||
for (i = 0; i < vm_ndomains; i++) { | for (i = 0; i < vm_ndomains; i++) | ||||
zdom = &z->uz_domain[i]; | cachefree += z->uz_domain[i].uzd_nitems; | ||||
LIST_FOREACH(bucket, &zdom->uzd_buckets, | |||||
ub_link) | db_printf("%18s %8ju %8jd %8ld %12ju %8ju %8u\n", | ||||
cachefree += bucket->ub_cnt; | |||||
} | |||||
db_printf("%18s %8ju %8jd %8d %12ju %8ju %8u\n", | |||||
z->uz_name, (uintmax_t)kz->uk_size, | z->uz_name, (uintmax_t)kz->uk_size, | ||||
(intmax_t)(allocs - frees), cachefree, | (intmax_t)(allocs - frees), cachefree, | ||||
(uintmax_t)allocs, sleeps, z->uz_count); | (uintmax_t)allocs, sleeps, z->uz_count); | ||||
if (db_pager_quit) | if (db_pager_quit) | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
DB_SHOW_COMMAND(umacache, db_show_umacache) | DB_SHOW_COMMAND(umacache, db_show_umacache) | ||||
{ | { | ||||
uma_bucket_t bucket; | |||||
uma_zone_t z; | uma_zone_t z; | ||||
uma_zone_domain_t zdom; | |||||
uint64_t allocs, frees; | uint64_t allocs, frees; | ||||
int cachefree, i; | long cachefree; | ||||
int i; | |||||
db_printf("%18s %8s %8s %8s %12s %8s\n", "Zone", "Size", "Used", "Free", | db_printf("%18s %8s %8s %8s %12s %8s\n", "Zone", "Size", "Used", "Free", | ||||
"Requests", "Bucket"); | "Requests", "Bucket"); | ||||
LIST_FOREACH(z, &uma_cachezones, uz_link) { | LIST_FOREACH(z, &uma_cachezones, uz_link) { | ||||
uma_zone_sumstat(z, &cachefree, &allocs, &frees, NULL); | uma_zone_sumstat(z, &cachefree, &allocs, &frees, NULL); | ||||
for (i = 0; i < vm_ndomains; i++) { | for (i = 0; i < vm_ndomains; i++) | ||||
zdom = &z->uz_domain[i]; | cachefree += z->uz_domain[i].uzd_nitems; | ||||
LIST_FOREACH(bucket, &zdom->uzd_buckets, ub_link) | db_printf("%18s %8ju %8jd %8ld %12ju %8u\n", | ||||
cachefree += bucket->ub_cnt; | |||||
} | |||||
db_printf("%18s %8ju %8jd %8d %12ju %8u\n", | |||||
z->uz_name, (uintmax_t)z->uz_size, | z->uz_name, (uintmax_t)z->uz_size, | ||||
(intmax_t)(allocs - frees), cachefree, | (intmax_t)(allocs - frees), cachefree, | ||||
(uintmax_t)allocs, z->uz_count); | (uintmax_t)allocs, z->uz_count); | ||||
if (db_pager_quit) | if (db_pager_quit) | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
#endif /* DDB */ | #endif /* DDB */ |
lock asserts please