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.com Signed-off-by: Zach O'Keefe <zokeefe@google.com> Reviewed-by: Zi 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: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
d41fd2016e
commit
c07c343cda
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user