Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

s390/mm: Add memory allocation profiling hooks

Similar to common code changes [1] add alloc_hook() wrappers to page table
allocation functions to allow for memory allocation profiling.

If CONFIG_MEM_ALLOC_PROFILING is enabled call sites of page table
allocations are accounted, instead of e.g. only crst_table_alloc() and
page_table_alloc(). This allows for slightly better profiling data, and the
output of /proc/allocinfo is similar to other architectures.

Without alloc_hook() wrappers the output of /proc/allocinfo looks like
this:

17096704 4174 mm/memory.c:1061 func:folio_prealloc
17809408 4348 mm/memory.c:1063 func:folio_prealloc
0 0 mm/memory.c:4422 func:alloc_swap_folio
0 0 mm/memory.c:4286 func:__alloc_swap_folio
0 0 mm/memory.c:4971 func:alloc_anon_folio
...
1589248 97 arch/s390/mm/pgalloc.c:25 func:crst_table_alloc
0 0 arch/s390/mm/pgalloc.c:124 func:page_table_alloc_pgste
4280320 1045 arch/s390/mm/pgalloc.c:149 func:page_table_alloc

With alloc_hook() wrappers:

1097728 268 mm/memory.c:5147 func:__do_fault
20119552 4912 mm/memory.c:1061 func:folio_prealloc
17534976 4281 mm/memory.c:1063 func:folio_prealloc
0 0 mm/memory.c:4422 func:alloc_swap_folio
0 0 mm/memory.c:4286 func:__alloc_swap_folio
786432 192 mm/memory.c:452 func:__pte_alloc
405504 99 mm/memory.c:464 func:__pte_alloc_kernel
1880064 459 mm/memory.c:5525 func:do_fault_around
0 0 mm/memory.c:6403 func:__p4d_alloc
0 0 mm/memory.c:6426 func:__pud_alloc
1064960 65 mm/memory.c:6450 func:__pmd_alloc
0 0 mm/memory.c:4971 func:alloc_anon_folio
0 0 mm/memory.c:5233 func:do_set_pmd

[1] commit 2c321f3f70bc ("mm: change inlined allocation helpers to account at the call site")

Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Acked-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>

authored by

Heiko Carstens and committed by
Alexander Gordeev
088bb10e 72105fc1

+25 -17
+19 -11
arch/s390/include/asm/pgalloc.h
··· 19 19 20 20 #define CRST_ALLOC_ORDER 2 21 21 22 - unsigned long *crst_table_alloc(struct mm_struct *); 22 + unsigned long *crst_table_alloc_noprof(struct mm_struct *); 23 + #define crst_table_alloc(...) alloc_hooks(crst_table_alloc_noprof(__VA_ARGS__)) 23 24 void crst_table_free(struct mm_struct *, unsigned long *); 24 25 25 - unsigned long *page_table_alloc(struct mm_struct *); 26 - struct ptdesc *page_table_alloc_pgste(struct mm_struct *mm); 26 + unsigned long *page_table_alloc_noprof(struct mm_struct *); 27 + #define page_table_alloc(...) alloc_hooks(page_table_alloc_noprof(__VA_ARGS__)) 27 28 void page_table_free(struct mm_struct *, unsigned long *); 29 + 30 + struct ptdesc *page_table_alloc_pgste_noprof(struct mm_struct *mm); 31 + #define page_table_alloc_pgste(...) alloc_hooks(page_table_alloc_pgste_noprof(__VA_ARGS__)) 28 32 void page_table_free_pgste(struct ptdesc *ptdesc); 29 33 30 34 static inline void crst_table_init(unsigned long *crst, unsigned long entry) ··· 52 48 return addr; 53 49 } 54 50 55 - static inline p4d_t *p4d_alloc_one(struct mm_struct *mm, unsigned long address) 51 + static inline p4d_t *p4d_alloc_one_noprof(struct mm_struct *mm, unsigned long address) 56 52 { 57 - unsigned long *table = crst_table_alloc(mm); 53 + unsigned long *table = crst_table_alloc_noprof(mm); 58 54 59 55 if (!table) 60 56 return NULL; ··· 63 59 64 60 return (p4d_t *) table; 65 61 } 62 + #define p4d_alloc_one(...) alloc_hooks(p4d_alloc_one_noprof(__VA_ARGS__)) 66 63 67 64 static inline void p4d_free(struct mm_struct *mm, p4d_t *p4d) 68 65 { ··· 74 69 crst_table_free(mm, (unsigned long *) p4d); 75 70 } 76 71 77 - static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address) 72 + static inline pud_t *pud_alloc_one_noprof(struct mm_struct *mm, unsigned long address) 78 73 { 79 - unsigned long *table = crst_table_alloc(mm); 74 + unsigned long *table = crst_table_alloc_noprof(mm); 80 75 81 76 if (!table) 82 77 return NULL; ··· 85 80 86 81 return (pud_t *) table; 87 82 } 83 + #define pud_alloc_one(...) alloc_hooks(pud_alloc_one_noprof(__VA_ARGS__)) 88 84 89 85 static inline void pud_free(struct mm_struct *mm, pud_t *pud) 90 86 { ··· 96 90 crst_table_free(mm, (unsigned long *) pud); 97 91 } 98 92 99 - static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr) 93 + static inline pmd_t *pmd_alloc_one_noprof(struct mm_struct *mm, unsigned long vmaddr) 100 94 { 101 - unsigned long *table = crst_table_alloc(mm); 95 + unsigned long *table = crst_table_alloc_noprof(mm); 102 96 103 97 if (!table) 104 98 return NULL; ··· 109 103 } 110 104 return (pmd_t *) table; 111 105 } 106 + #define pmd_alloc_one(...) alloc_hooks(pmd_alloc_one_noprof(__VA_ARGS__)) 112 107 113 108 static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) 114 109 { ··· 134 127 set_pud(pud, __pud(_REGION3_ENTRY | __pa(pmd))); 135 128 } 136 129 137 - static inline pgd_t *pgd_alloc(struct mm_struct *mm) 130 + static inline pgd_t *pgd_alloc_noprof(struct mm_struct *mm) 138 131 { 139 - unsigned long *table = crst_table_alloc(mm); 132 + unsigned long *table = crst_table_alloc_noprof(mm); 140 133 141 134 if (!table) 142 135 return NULL; ··· 144 137 145 138 return (pgd_t *) table; 146 139 } 140 + #define pgd_alloc(...) alloc_hooks(pgd_alloc_noprof(__VA_ARGS__)) 147 141 148 142 static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) 149 143 {
+6 -6
arch/s390/mm/pgalloc.c
··· 14 14 #include <asm/pgalloc.h> 15 15 #include <asm/tlbflush.h> 16 16 17 - unsigned long *crst_table_alloc(struct mm_struct *mm) 17 + unsigned long *crst_table_alloc_noprof(struct mm_struct *mm) 18 18 { 19 19 gfp_t gfp = GFP_KERNEL_ACCOUNT; 20 20 struct ptdesc *ptdesc; ··· 22 22 23 23 if (mm == &init_mm) 24 24 gfp &= ~__GFP_ACCOUNT; 25 - ptdesc = pagetable_alloc(gfp, CRST_ALLOC_ORDER); 25 + ptdesc = pagetable_alloc_noprof(gfp, CRST_ALLOC_ORDER); 26 26 if (!ptdesc) 27 27 return NULL; 28 28 table = ptdesc_to_virt(ptdesc); ··· 116 116 117 117 #ifdef CONFIG_PGSTE 118 118 119 - struct ptdesc *page_table_alloc_pgste(struct mm_struct *mm) 119 + struct ptdesc *page_table_alloc_pgste_noprof(struct mm_struct *mm) 120 120 { 121 121 struct ptdesc *ptdesc; 122 122 u64 *table; 123 123 124 - ptdesc = pagetable_alloc(GFP_KERNEL_ACCOUNT, 0); 124 + ptdesc = pagetable_alloc_noprof(GFP_KERNEL_ACCOUNT, 0); 125 125 if (ptdesc) { 126 126 table = (u64 *)ptdesc_to_virt(ptdesc); 127 127 __arch_set_page_dat(table, 1); ··· 138 138 139 139 #endif /* CONFIG_PGSTE */ 140 140 141 - unsigned long *page_table_alloc(struct mm_struct *mm) 141 + unsigned long *page_table_alloc_noprof(struct mm_struct *mm) 142 142 { 143 143 gfp_t gfp = GFP_KERNEL_ACCOUNT; 144 144 struct ptdesc *ptdesc; ··· 146 146 147 147 if (mm == &init_mm) 148 148 gfp &= ~__GFP_ACCOUNT; 149 - ptdesc = pagetable_alloc(gfp, 0); 149 + ptdesc = pagetable_alloc_noprof(gfp, 0); 150 150 if (!ptdesc) 151 151 return NULL; 152 152 if (!pagetable_pte_ctor(mm, ptdesc)) {