[Crash-utility] [PATCH] Speed up "kmem -[sS]" by optimizing is_page_ptr()

k-hagio at ab.jp.nec.com k-hagio at ab.jp.nec.com
Tue Feb 13 17:52:03 UTC 2018


Hi,

The "kmem -[sS]" commands can take several minutes to complete with
the following conditions:
  * The system has a lot of memory sections with CONFIG_SPARSEMEM.
  * The kernel uses SLUB and it has a very long partial slab list.

  crash> kmem -s dentry | awk '{print strftime("%T"), $0}'
  10:18:34 CACHE            NAME                 OBJSIZE  ALLOCATED     TOTAL  SLABS  SSIZE
  10:19:41 ffff88017fc78a00 dentry                   192    9038949  10045728  239184     8k
  crash> kmem -S dentry | bash -c 'cat >/dev/null ; echo $SECONDS'
  334

One of the causes is that is_page_ptr() in count_partial() checks if
a given slub page address is a page struct by searching all memory
sections linearly for the one which includes it.

        nr_mem_sections = NR_MEM_SECTIONS();
        for (nr = 0; nr < nr_mem_sections ; nr++) {
                if ((sec_addr = valid_section_nr(nr))) {
                        ...

With CONFIG_SPARSEMEM{_VMEMMAP}, we can calculate the memory section
which includes a page struct with its page.flags, or its address and
VMEMMAP_VADDR. With this patch doing so, the computation amount can be
significantly reduced in that case.

  crash> kmem -s dentry | awk '{print strftime("%T"), $0}'
  10:34:55 CACHE            NAME                 OBJSIZE  ALLOCATED     TOTAL  SLABS  SSIZE
  10:34:55 ffff88017fc78a00 dentry                   192    9038949  10045728  239184     8k
  crash> kmem -S dentry | bash -c 'cat >/dev/null ; echo $SECONDS'
  2

This patch uses VMEMMAP_VADDR. It is not defined on PPC64, but it looks
like PPC64 supports VMEMMAP flag and machdep->machspec->vmemmap_base is
it, so this patch also defines it for PPC64. This might need some help
from PPC folks.

Signed-off-by: Kazuhito Hagio <k-hagio at ab.jp.nec.com>
---
 defs.h   |  2 ++
 memory.c | 15 +++++++++++++++
 2 files changed, 17 insertions(+)

diff --git a/defs.h b/defs.h
index aa17792..84e68ca 100644
--- a/defs.h
+++ b/defs.h
@@ -3861,6 +3861,8 @@ struct efi_memory_desc_t {
 #define IS_VMALLOC_ADDR(X) machdep->machspec->is_vmaddr(X)
 #define KERNELBASE      machdep->pageoffset
 
+#define VMEMMAP_VADDR   (machdep->machspec->vmemmap_base)
+
 #define PGDIR_SHIFT     (machdep->pageshift + (machdep->pageshift -3) + (machdep->pageshift - 2))
 #define PMD_SHIFT       (machdep->pageshift + (machdep->pageshift - 3))
 
diff --git a/memory.c b/memory.c
index 0df8ecc..0696763 100644
--- a/memory.c
+++ b/memory.c
@@ -13348,10 +13348,25 @@ is_page_ptr(ulong addr, physaddr_t *phys)
 	ulong nr_mem_sections;
 	ulong coded_mem_map, mem_map, end_mem_map;
 	physaddr_t section_paddr;
+#ifdef VMEMMAP_VADDR
+	ulong flags;
+#endif
 
 	if (IS_SPARSEMEM()) {
 		nr_mem_sections = NR_MEM_SECTIONS();
+#ifdef VMEMMAP_VADDR
+		nr = nr_mem_sections;
+		if (machdep->flags & VMEMMAP)
+			nr = pfn_to_section_nr((addr - VMEMMAP_VADDR) / SIZE(page));
+		else if (readmem(addr + OFFSET(page_flags), KVADDR, &flags,
+			sizeof(ulong), "page.flags", RETURN_ON_ERROR|QUIET))
+			nr = (flags >> (SIZE(page_flags)*8 - SECTIONS_SHIFT())
+				& ((1UL << SECTIONS_SHIFT()) - 1));
+
+		if (nr < nr_mem_sections) {
+#else
 	        for (nr = 0; nr < nr_mem_sections ; nr++) {
+#endif
 	                if ((sec_addr = valid_section_nr(nr))) {
 	                        coded_mem_map = section_mem_map_addr(sec_addr);
 	                        mem_map = sparse_decode_mem_map(coded_mem_map, nr);
-- 
1.8.3.1




More information about the Crash-utility mailing list