X86 has information in /proc/meminfo showing the use of large mappings for the kernel direct map. This has now also become important for ARM since the kernel default CONFIG_RODATA_FULL_DEFAULT_ENABLED forces 4K PTE use for the direct map and users may not be aware of the performance impact of the increased TLB use etc. The output of /proc/meminfo on ARM64 is then after this patch: 4K page size: Hugepagesize: 2048 kB Hugetlb: 0 kB DirectMap4k: 155912 kB CONT DMap4k: 1176 kB DirectMap2M: 722944 kB CONT DMap2M: 28672 kB DirectMap1G: 534773760 kB 64K page size: Hugepagesize: 524288 kB Hugetlb: 0 kB DirectMap64k: 882624 kB CONT DMap64k: 19904 kB DirectMap512M: 534773760 kB CONT DMap512M: 0 kB DirectMap4096G: 0 kB Signed-off-by: Christoph Lameter <cl@xxxxxxxxx> Index: linux/arch/arm64/mm/mmu.c =================================================================== --- linux.orig/arch/arm64/mm/mmu.c +++ linux/arch/arm64/mm/mmu.c @@ -66,6 +66,12 @@ u32 __boot_cpu_mode[] = { BOOT_CPU_MODE_ */ long __section(".mmuoff.data.write") __early_cpu_boot_status; +static atomic_t nr_pte; +static atomic_t nr_pmd; +static atomic_t nr_pud; +static atomic_t nr_pte_cont; +static atomic_t nr_pmd_cont; + /* * Empty_zero_page is a special page that is used for zero-initialized data * and COW. @@ -179,6 +185,7 @@ static void init_pte(pmd_t *pmdp, unsign pte_t old_pte = READ_ONCE(*ptep); set_pte(ptep, pfn_pte(__phys_to_pfn(phys), prot)); + atomic_inc(&nr_pte); /* * After the PTE entry has been populated once, we @@ -223,8 +230,10 @@ static void alloc_init_cont_pte(pmd_t *p /* use a contiguous mapping if the range is suitably aligned */ if ((((addr | next | phys) & ~CONT_PTE_MASK) == 0) && - (flags & NO_CONT_MAPPINGS) == 0) + (flags & NO_CONT_MAPPINGS) == 0) { __prot = __pgprot(pgprot_val(prot) | PTE_CONT); + atomic_inc(&nr_pte_cont); + } init_pte(pmdp, addr, next, phys, __prot); @@ -249,6 +258,7 @@ static void init_pmd(pud_t *pudp, unsign if (((addr | next | phys) & ~PMD_MASK) == 0 && (flags & NO_BLOCK_MAPPINGS) == 0) { pmd_set_huge(pmdp, phys, prot); + atomic_inc(&nr_pmd); /* * After the PMD entry has been populated once, we @@ -301,8 +311,10 @@ static void alloc_init_cont_pmd(pud_t *p /* use a contiguous mapping if the range is suitably aligned */ if ((((addr | next | phys) & ~CONT_PMD_MASK) == 0) && - (flags & NO_CONT_MAPPINGS) == 0) + (flags & NO_CONT_MAPPINGS) == 0) { __prot = __pgprot(pgprot_val(prot) | PTE_CONT); + atomic_inc(&nr_pmd_cont); + } init_pmd(pudp, addr, next, phys, __prot, pgtable_alloc, flags); @@ -346,7 +358,7 @@ static void alloc_init_pud(pgd_t *pgdp, ((addr | next | phys) & ~PUD_MASK) == 0 && (flags & NO_BLOCK_MAPPINGS) == 0) { pud_set_huge(pudp, phys, prot); - + atomic_inc(&nr_pud); /* * After the PUD entry has been populated once, we * only allow updates to the permission attributes. @@ -1486,3 +1498,35 @@ void ptep_modify_prot_commit(struct vm_a { set_pte_at(vma->vm_mm, addr, ptep, pte); } + +#ifdef CONFIG_PROC_FS +void arch_report_meminfo(struct seq_file *m) +{ + unsigned long pagesize_in_kb = PAGE_SIZE / 1024; + + seq_printf(m, "DirectMap%luk: %8lu kB\n", + pagesize_in_kb, + (unsigned long)atomic_read(&nr_pte) * pagesize_in_kb); + + seq_printf(m, "CONT DMap%luk: %8lu kB\n", + pagesize_in_kb, + (unsigned long)atomic_read(&nr_pte_cont) * pagesize_in_kb); + + pagesize_in_kb = PMD_SIZE / 1024; + + seq_printf(m, "DirectMap%luM: %8lu kB\n", + pagesize_in_kb / 1024, + (unsigned long)atomic_read(&nr_pmd) * pagesize_in_kb); + + seq_printf(m, "CONT DMap%luM: %8lu kB\n", + pagesize_in_kb / 1024, + (unsigned long)atomic_read(&nr_pmd_cont) * pagesize_in_kb); + + pagesize_in_kb = PUD_SIZE / 1024; + + seq_printf(m, "DirectMap%luG: %10lu kB\n", + pagesize_in_kb >> 20, + (unsigned long)atomic_read(&nr_pud) * pagesize_in_kb); +} +#endif +