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

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: 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
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+7 −57
Original line number Diff line number Diff line
@@ -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);
	return check_huge_anon(addr, nr_hpages, hpage_pmd_size);
}


	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;
}


#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;
+1 −1
Original line number Diff line number Diff line
@@ -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();
+4 −8
Original line number Diff line number Diff line
@@ -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);
	}
+17 −9
Original line number Diff line number Diff line
@@ -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);
}
Loading