diff --git a/sys/vm/vm_phys.c b/sys/vm/vm_phys.c --- a/sys/vm/vm_phys.c +++ b/sys/vm/vm_phys.c @@ -107,6 +107,11 @@ static struct rwlock_padalign vm_phys_fictitious_reg_lock; MALLOC_DEFINE(M_FICT_PAGES, "vm_fictitious", "Fictitious VM pages"); +struct vm_phys_info { + uint64_t free_pages; + uint64_t free_blocks; +}; + static struct vm_freelist __aligned(CACHE_LINE_SIZE) vm_phys_free_queues[MAXMEMDOM][VM_NFREELIST][VM_NFREEPOOL] [VM_NFREEORDER_MAX]; @@ -156,6 +161,11 @@ sysctl_vm_phys_free, "A", "Phys Free Info"); +static int sysctl_vm_phys_frag_idx(SYSCTL_HANDLER_ARGS); +SYSCTL_OID(_vm, OID_AUTO, phys_frag_idx, + CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, + sysctl_vm_phys_frag_idx, "A", "Phys Frag Info"); + static int sysctl_vm_phys_segs(SYSCTL_HANDLER_ARGS); SYSCTL_OID(_vm, OID_AUTO, phys_segs, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, @@ -291,6 +301,78 @@ return (error); } +static void +vm_phys_get_info(struct vm_phys_info *info, int domain) +{ + struct vm_freelist *fl; + int pind, oind, flind; + + /* Calculate total number of free pages and blocks */ + info->free_pages = info->free_blocks = 0; + for (flind = 0; flind < vm_nfreelists; flind++) { + for (oind = VM_NFREEORDER - 1; oind >= 0; oind--) { + for (pind = 0; pind < VM_NFREEPOOL; pind++) { + fl = vm_phys_free_queues[domain][flind][pind]; + info->free_pages += fl[oind].lcnt << oind; + info->free_blocks += fl[oind].lcnt; + } + } + } +} + +static int +vm_phys_fragmentation_index(int order, int domain) +{ + struct vm_phys_info info; + + vm_domain_free_assert_locked(VM_DOMAIN(domain)); + vm_phys_get_info(&info, domain); + + if (info.free_blocks == 0) { + return (0); + } + + return (1000 - + ((info.free_pages * 1000) / (1 << order) / info.free_blocks)); +} + +/* + * Outputs the value of the Free Memory Fragmentation Index (FMFI) for each + * domain. + */ +static int +sysctl_vm_phys_frag_idx(SYSCTL_HANDLER_ARGS) +{ + struct sbuf sbuf; + int64_t idx; + int oind, dom, error; + + error = sysctl_wire_old_buffer(req, 0); + if (error != 0) + return (error); + sbuf_new_for_sysctl(&sbuf, NULL, 128 * vm_ndomains, req); + + for (dom = 0; dom < vm_ndomains; dom++) { + + sbuf_printf(&sbuf, "\nDOMAIN %d\n", dom); + sbuf_printf(&sbuf, "\n ORDER (SIZE) | FMFI\n"); + sbuf_printf(&sbuf, "--\n"); + + vm_domain_free_lock(VM_DOMAIN(dom)); + for (oind = VM_NFREEORDER - 1; oind >= 0; oind--) { + idx = vm_phys_fragmentation_index(oind, dom); + sbuf_printf(&sbuf, " %2d (%6dK) ", oind, + 1 << (PAGE_SHIFT - 10 + oind)); + sbuf_printf(&sbuf, "| %ld \n", idx); + } + vm_domain_free_unlock(VM_DOMAIN(dom)); + } + + error = sbuf_finish(&sbuf); + sbuf_delete(&sbuf); + return (error); +} + /* * Outputs the set of physical memory segments. */