Commit c07c343c authored by Zach O'Keefe's avatar Zach O'Keefe Committed by Andrew Morton

selftests/vm: dedup THP helpers

These files:

tools/testing/selftests/vm/vm_util.c
tools/testing/selftests/vm/khugepaged.c

Both contain logic to:

1) Determine hugepage size on current system
2) Read /proc/self/smaps to determine number of THPs at an address

Refactor selftests/vm/khugepaged.c to use the vm_util common helpers and
add it as a build dependency.

Since selftests/vm/khugepaged.c is the largest user of check_huge(),
change the signature of check_huge() to match selftests/vm/khugepaged.c's
useage: take an expected number of hugepages, and return a bool indicating
if the correct number of hugepages were found.  Add a wrapper,
check_huge_anon(), in anticipation of checking smaps for file and shmem
hugepages.

Update existing callsites to use the new pattern / function.

Likewise, check_for_pattern() was duplicated, and it's a general enough
helper to include in vm_util helpers as well.

Link: https://lkml.kernel.org/r/20220907144521.3115321-6-zokeefe@google.com
Link: https://lkml.kernel.org/r/20220922224046.1143204-6-zokeefe@google.comSigned-off-by: default avatarZach O'Keefe <zokeefe@google.com>
Reviewed-by: default avatarZi Yan <ziy@nvidia.com>
Cc: Axel Rasmussen <axelrasmussen@google.com>
Cc: Chris Kennelly <ckennelly@google.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: James Houghton <jthoughton@google.com>
Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Miaohe Lin <linmiaohe@huawei.com>
Cc: Minchan Kim <minchan@kernel.org>
Cc: Pasha Tatashin <pasha.tatashin@soleen.com>
Cc: Peter Xu <peterx@redhat.com>
Cc: Rongwei Wang <rongwei.wang@linux.alibaba.com>
Cc: SeongJae Park <sj@kernel.org>
Cc: Song Liu <songliubraving@fb.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Yang Shi <shy828301@gmail.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent d41fd201
......@@ -95,6 +95,7 @@ TEST_FILES += va_128TBswitch.sh
include ../lib.mk
$(OUTPUT)/khugepaged: vm_util.c
$(OUTPUT)/madv_populate: vm_util.c
$(OUTPUT)/soft-dirty: vm_util.c
$(OUTPUT)/split_huge_page_test: vm_util.c
......
......@@ -12,6 +12,8 @@
#include <sys/mman.h>
#include <sys/wait.h>
#include "vm_util.h"
#ifndef MADV_PAGEOUT
#define MADV_PAGEOUT 21
#endif
......@@ -352,64 +354,12 @@ static void save_settings(void)
signal(SIGQUIT, restore_settings);
}
#define MAX_LINE_LENGTH 500
static bool check_for_pattern(FILE *fp, char *pattern, char *buf)
{
while (fgets(buf, MAX_LINE_LENGTH, fp) != NULL) {
if (!strncmp(buf, pattern, strlen(pattern)))
return true;
}
return false;
}
static bool check_huge(void *addr, int nr_hpages)
{
bool thp = false;
int ret;
FILE *fp;
char buffer[MAX_LINE_LENGTH];
char addr_pattern[MAX_LINE_LENGTH];
ret = snprintf(addr_pattern, MAX_LINE_LENGTH, "%08lx-",
(unsigned long) addr);
if (ret >= MAX_LINE_LENGTH) {
printf("%s: Pattern is too long\n", __func__);
exit(EXIT_FAILURE);
}
fp = fopen(PID_SMAPS, "r");
if (!fp) {
printf("%s: Failed to open file %s\n", __func__, PID_SMAPS);
exit(EXIT_FAILURE);
}
if (!check_for_pattern(fp, addr_pattern, buffer))
goto err_out;
ret = snprintf(addr_pattern, MAX_LINE_LENGTH, "AnonHugePages:%10ld kB",
nr_hpages * (hpage_pmd_size >> 10));
if (ret >= MAX_LINE_LENGTH) {
printf("%s: Pattern is too long\n", __func__);
exit(EXIT_FAILURE);
}
/*
* Fetch the AnonHugePages: in the same block and check whether it got
* the expected number of hugeepages next.
*/
if (!check_for_pattern(fp, "AnonHugePages:", buffer))
goto err_out;
if (strncmp(buffer, addr_pattern, strlen(addr_pattern)))
goto err_out;
thp = true;
err_out:
fclose(fp);
return thp;
return check_huge_anon(addr, nr_hpages, hpage_pmd_size);
}
#define MAX_LINE_LENGTH 500
static bool check_swap(void *addr, unsigned long size)
{
bool swap = false;
......@@ -431,7 +381,7 @@ static bool check_swap(void *addr, unsigned long size)
printf("%s: Failed to open file %s\n", __func__, PID_SMAPS);
exit(EXIT_FAILURE);
}
if (!check_for_pattern(fp, addr_pattern, buffer))
if (!check_for_pattern(fp, addr_pattern, buffer, sizeof(buffer)))
goto err_out;
ret = snprintf(addr_pattern, MAX_LINE_LENGTH, "Swap:%19ld kB",
......@@ -444,7 +394,7 @@ static bool check_swap(void *addr, unsigned long size)
* Fetch the Swap: in the same block and check whether it got
* the expected number of hugeepages next.
*/
if (!check_for_pattern(fp, "Swap:", buffer))
if (!check_for_pattern(fp, "Swap:", buffer, sizeof(buffer)))
goto err_out;
if (strncmp(buffer, addr_pattern, strlen(addr_pattern)))
......@@ -1066,7 +1016,7 @@ int main(int argc, const char **argv)
setbuf(stdout, NULL);
page_size = getpagesize();
hpage_pmd_size = read_num("hpage_pmd_size");
hpage_pmd_size = read_pmd_pagesize();
hpage_pmd_nr = hpage_pmd_size / page_size;
default_settings.khugepaged.max_ptes_none = hpage_pmd_nr - 1;
......
......@@ -91,7 +91,7 @@ static void test_hugepage(int pagemap_fd, int pagesize)
for (i = 0; i < hpage_len; i++)
map[i] = (char)i;
if (check_huge(map)) {
if (check_huge_anon(map, 1, hpage_len)) {
ksft_test_result_pass("Test %s huge page allocation\n", __func__);
clear_softdirty();
......
......@@ -92,7 +92,6 @@ void split_pmd_thp(void)
{
char *one_page;
size_t len = 4 * pmd_pagesize;
uint64_t thp_size;
size_t i;
one_page = memalign(pmd_pagesize, len);
......@@ -107,8 +106,7 @@ void split_pmd_thp(void)
for (i = 0; i < len; i++)
one_page[i] = (char)i;
thp_size = check_huge(one_page);
if (!thp_size) {
if (!check_huge_anon(one_page, 1, pmd_pagesize)) {
printf("No THP is allocated\n");
exit(EXIT_FAILURE);
}
......@@ -124,9 +122,8 @@ void split_pmd_thp(void)
}
thp_size = check_huge(one_page);
if (thp_size) {
printf("Still %ld kB AnonHugePages not split\n", thp_size);
if (check_huge_anon(one_page, 0, pmd_pagesize)) {
printf("Still AnonHugePages not split\n");
exit(EXIT_FAILURE);
}
......@@ -172,8 +169,7 @@ void split_pte_mapped_thp(void)
for (i = 0; i < len; i++)
one_page[i] = (char)i;
thp_size = check_huge(one_page);
if (!thp_size) {
if (!check_huge_anon(one_page, 1, pmd_pagesize)) {
printf("No THP is allocated\n");
exit(EXIT_FAILURE);
}
......
......@@ -42,9 +42,9 @@ void clear_softdirty(void)
ksft_exit_fail_msg("writing clear_refs failed\n");
}
static bool check_for_pattern(FILE *fp, const char *pattern, char *buf)
bool check_for_pattern(FILE *fp, const char *pattern, char *buf, size_t len)
{
while (fgets(buf, MAX_LINE_LENGTH, fp) != NULL) {
while (fgets(buf, len, fp)) {
if (!strncmp(buf, pattern, strlen(pattern)))
return true;
}
......@@ -72,9 +72,10 @@ uint64_t read_pmd_pagesize(void)
return strtoul(buf, NULL, 10);
}
uint64_t check_huge(void *addr)
bool __check_huge(void *addr, char *pattern, int nr_hpages,
uint64_t hpage_size)
{
uint64_t thp = 0;
uint64_t thp = -1;
int ret;
FILE *fp;
char buffer[MAX_LINE_LENGTH];
......@@ -89,20 +90,27 @@ uint64_t check_huge(void *addr)
if (!fp)
ksft_exit_fail_msg("%s: Failed to open file %s\n", __func__, SMAP_FILE_PATH);
if (!check_for_pattern(fp, addr_pattern, buffer))
if (!check_for_pattern(fp, addr_pattern, buffer, sizeof(buffer)))
goto err_out;
/*
* Fetch the AnonHugePages: in the same block and check the number of
* Fetch the pattern in the same block and check the number of
* hugepages.
*/
if (!check_for_pattern(fp, "AnonHugePages:", buffer))
if (!check_for_pattern(fp, pattern, buffer, sizeof(buffer)))
goto err_out;
if (sscanf(buffer, "AnonHugePages:%10ld kB", &thp) != 1)
snprintf(addr_pattern, MAX_LINE_LENGTH, "%s%%9ld kB", pattern);
if (sscanf(buffer, addr_pattern, &thp) != 1)
ksft_exit_fail_msg("Reading smap error\n");
err_out:
fclose(fp);
return thp;
return thp == (nr_hpages * (hpage_size >> 10));
}
bool check_huge_anon(void *addr, int nr_hpages, uint64_t hpage_size)
{
return __check_huge(addr, "AnonHugePages: ", nr_hpages, hpage_size);
}
......@@ -5,5 +5,6 @@
uint64_t pagemap_get_entry(int fd, char *start);
bool pagemap_is_softdirty(int fd, char *start);
void clear_softdirty(void);
bool check_for_pattern(FILE *fp, const char *pattern, char *buf, size_t len);
uint64_t read_pmd_pagesize(void);
uint64_t check_huge(void *addr);
bool check_huge_anon(void *addr, int nr_hpages, uint64_t hpage_size);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment