Skip to content

Commit 391e869

Browse files
alexlzhuakpm00
authored andcommitted
mm: selftest to verify zero-filled pages are mapped to zeropage
When a THP is split, any subpage that is zero-filled will be mapped to the shared zeropage, hence saving memory. Add selftest to verify this by allocating zero-filled THP and comparing RssAnon before and after split. Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Alexander Zhu <[email protected]> Signed-off-by: Usama Arif <[email protected]> Acked-by: Rik van Riel <[email protected]> Cc: Barry Song <[email protected]> Cc: David Hildenbrand <[email protected]> Cc: Domenico Cerasuolo <[email protected]> Cc: Johannes Weiner <[email protected]> Cc: Jonathan Corbet <[email protected]> Cc: Kairui Song <[email protected]> Cc: Matthew Wilcox <[email protected]> Cc: Mike Rapoport <[email protected]> Cc: Nico Pache <[email protected]> Cc: Roman Gushchin <[email protected]> Cc: Ryan Roberts <[email protected]> Cc: Shakeel Butt <[email protected]> Cc: Shuang Zhai <[email protected]> Cc: Yu Zhao <[email protected]> Cc: Shuang Zhai <[email protected]> Cc: Hugh Dickins <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent b1f2020 commit 391e869

File tree

3 files changed

+94
-0
lines changed

3 files changed

+94
-0
lines changed

tools/testing/selftests/mm/split_huge_page_test.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,76 @@ static void write_debugfs(const char *fmt, ...)
8484
write_file(SPLIT_DEBUGFS, input, ret + 1);
8585
}
8686

87+
static char *allocate_zero_filled_hugepage(size_t len)
88+
{
89+
char *result;
90+
size_t i;
91+
92+
result = memalign(pmd_pagesize, len);
93+
if (!result) {
94+
printf("Fail to allocate memory\n");
95+
exit(EXIT_FAILURE);
96+
}
97+
98+
madvise(result, len, MADV_HUGEPAGE);
99+
100+
for (i = 0; i < len; i++)
101+
result[i] = (char)0;
102+
103+
return result;
104+
}
105+
106+
static void verify_rss_anon_split_huge_page_all_zeroes(char *one_page, int nr_hpages, size_t len)
107+
{
108+
unsigned long rss_anon_before, rss_anon_after;
109+
size_t i;
110+
111+
if (!check_huge_anon(one_page, 4, pmd_pagesize)) {
112+
printf("No THP is allocated\n");
113+
exit(EXIT_FAILURE);
114+
}
115+
116+
rss_anon_before = rss_anon();
117+
if (!rss_anon_before) {
118+
printf("No RssAnon is allocated before split\n");
119+
exit(EXIT_FAILURE);
120+
}
121+
122+
/* split all THPs */
123+
write_debugfs(PID_FMT, getpid(), (uint64_t)one_page,
124+
(uint64_t)one_page + len, 0);
125+
126+
for (i = 0; i < len; i++)
127+
if (one_page[i] != (char)0) {
128+
printf("%ld byte corrupted\n", i);
129+
exit(EXIT_FAILURE);
130+
}
131+
132+
if (!check_huge_anon(one_page, 0, pmd_pagesize)) {
133+
printf("Still AnonHugePages not split\n");
134+
exit(EXIT_FAILURE);
135+
}
136+
137+
rss_anon_after = rss_anon();
138+
if (rss_anon_after >= rss_anon_before) {
139+
printf("Incorrect RssAnon value. Before: %ld After: %ld\n",
140+
rss_anon_before, rss_anon_after);
141+
exit(EXIT_FAILURE);
142+
}
143+
}
144+
145+
void split_pmd_zero_pages(void)
146+
{
147+
char *one_page;
148+
int nr_hpages = 4;
149+
size_t len = nr_hpages * pmd_pagesize;
150+
151+
one_page = allocate_zero_filled_hugepage(len);
152+
verify_rss_anon_split_huge_page_all_zeroes(one_page, nr_hpages, len);
153+
printf("Split zero filled huge pages successful\n");
154+
free(one_page);
155+
}
156+
87157
void split_pmd_thp(void)
88158
{
89159
char *one_page;
@@ -431,6 +501,7 @@ int main(int argc, char **argv)
431501

432502
fd_size = 2 * pmd_pagesize;
433503

504+
split_pmd_zero_pages();
434505
split_pmd_thp();
435506
split_pte_mapped_thp();
436507
split_file_backed_thp();

tools/testing/selftests/mm/vm_util.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#define PMD_SIZE_FILE_PATH "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size"
1414
#define SMAP_FILE_PATH "/proc/self/smaps"
15+
#define STATUS_FILE_PATH "/proc/self/status"
1516
#define MAX_LINE_LENGTH 500
1617

1718
unsigned int __page_size;
@@ -171,6 +172,27 @@ uint64_t read_pmd_pagesize(void)
171172
return strtoul(buf, NULL, 10);
172173
}
173174

175+
unsigned long rss_anon(void)
176+
{
177+
unsigned long rss_anon = 0;
178+
FILE *fp;
179+
char buffer[MAX_LINE_LENGTH];
180+
181+
fp = fopen(STATUS_FILE_PATH, "r");
182+
if (!fp)
183+
ksft_exit_fail_msg("%s: Failed to open file %s\n", __func__, STATUS_FILE_PATH);
184+
185+
if (!check_for_pattern(fp, "RssAnon:", buffer, sizeof(buffer)))
186+
goto err_out;
187+
188+
if (sscanf(buffer, "RssAnon:%10lu kB", &rss_anon) != 1)
189+
ksft_exit_fail_msg("Reading status error\n");
190+
191+
err_out:
192+
fclose(fp);
193+
return rss_anon;
194+
}
195+
174196
bool __check_huge(void *addr, char *pattern, int nr_hpages,
175197
uint64_t hpage_size)
176198
{

tools/testing/selftests/mm/vm_util.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ unsigned long pagemap_get_pfn(int fd, char *start);
3939
void clear_softdirty(void);
4040
bool check_for_pattern(FILE *fp, const char *pattern, char *buf, size_t len);
4141
uint64_t read_pmd_pagesize(void);
42+
unsigned long rss_anon(void);
4243
bool check_huge_anon(void *addr, int nr_hpages, uint64_t hpage_size);
4344
bool check_huge_file(void *addr, int nr_hpages, uint64_t hpage_size);
4445
bool check_huge_shmem(void *addr, int nr_hpages, uint64_t hpage_size);

0 commit comments

Comments
 (0)