[PATCH V2] selfttest/powerpc: Add memory page migration tests
Denis Kirjanov
kda at linux-powerpc.org
Tue Nov 24 19:12:32 AEDT 2015
On 11/24/15, Anshuman Khandual <khandual at linux.vnet.ibm.com> wrote:
> This adds two tests for memory page migration. One for normal page
> migration which works for both 4K or 64K base page size kernel and
> the other one is for 16MB huge page migration which will work both
> 4K or 64K base page sized 16MB huge pages as and when we support
> huge page migration.
>
> Signed-off-by: Anshuman Khandual <khandual at linux.vnet.ibm.com>
> ---
> Changes in V2:
> - Changed the script to accommodate review comments from Michael
> - Disabled huge page migration test till it is supported on POWER
>
> tools/testing/selftests/powerpc/mm/Makefile | 14 +-
> .../selftests/powerpc/mm/hugepage-migration.c | 30 ++++
> tools/testing/selftests/powerpc/mm/migration.h | 196
> +++++++++++++++++++++
> .../testing/selftests/powerpc/mm/page-migration.c | 33 ++++
> tools/testing/selftests/powerpc/mm/run_mmtests | 104 +++++++++++
> 5 files changed, 372 insertions(+), 5 deletions(-)
> create mode 100644 tools/testing/selftests/powerpc/mm/hugepage-migration.c
> create mode 100644 tools/testing/selftests/powerpc/mm/migration.h
> create mode 100644 tools/testing/selftests/powerpc/mm/page-migration.c
> create mode 100755 tools/testing/selftests/powerpc/mm/run_mmtests
>
> diff --git a/tools/testing/selftests/powerpc/mm/Makefile
> b/tools/testing/selftests/powerpc/mm/Makefile
> index ee179e2..c482614 100644
> --- a/tools/testing/selftests/powerpc/mm/Makefile
> +++ b/tools/testing/selftests/powerpc/mm/Makefile
> @@ -1,12 +1,16 @@
> noarg:
> $(MAKE) -C ../
>
> -TEST_PROGS := hugetlb_vs_thp_test subpage_prot
> -TEST_FILES := tempfile
> +TEST_PROGS := run_mmtests
> +TEST_FILES := hugetlb_vs_thp_test
> +TEST_FILES += subpage_prot
> +TEST_FILES += tempfile
> +TEST_FILES += hugepage-migration
> +TEST_FILES += page-migration
>
> -all: $(TEST_PROGS) $(TEST_FILES)
> +all: $(TEST_FILES)
>
> -$(TEST_PROGS): ../harness.c
> +$(TEST_FILES): ../harness.c
>
> include ../../lib.mk
>
> @@ -14,4 +18,4 @@ tempfile:
> dd if=/dev/zero of=tempfile bs=64k count=1
>
> clean:
> - rm -f $(TEST_PROGS) tempfile
> + rm -f $(TEST_FILES)
> diff --git a/tools/testing/selftests/powerpc/mm/hugepage-migration.c
> b/tools/testing/selftests/powerpc/mm/hugepage-migration.c
> new file mode 100644
> index 0000000..b60bc10
> --- /dev/null
> +++ b/tools/testing/selftests/powerpc/mm/hugepage-migration.c
> @@ -0,0 +1,30 @@
> +/*
> + * Copyright (C) 2015, Anshuman Khandual, IBM Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published
> + * by the Free Software Foundation.
> + */
> +#include "migration.h"
> +
> +static int hugepage_migration(void)
> +{
> + int ret = 0;
> +
> + if ((unsigned long)getpagesize() == 0x1000)
> + printf("Running on base page size 4K\n");
> +
> + if ((unsigned long)getpagesize() == 0x10000)
> + printf("Running on base page size 64K\n");
> +
> + ret = test_huge_migration(16 * MEM_MB);
> + ret = test_huge_migration(256 * MEM_MB);
> + ret = test_huge_migration(512 * MEM_MB);
> +
> + return ret;
> +}
> +
> +int main(void)
> +{
> + return test_harness(hugepage_migration, "hugepage_migration");
> +}
> diff --git a/tools/testing/selftests/powerpc/mm/migration.h
> b/tools/testing/selftests/powerpc/mm/migration.h
> new file mode 100644
> index 0000000..2f9e3f9
> --- /dev/null
> +++ b/tools/testing/selftests/powerpc/mm/migration.h
> @@ -0,0 +1,196 @@
> +/*
> + * Copyright (C) 2015, Anshuman Khandual, IBM Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published
> + * by the Free Software Foundation.
> + */
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <sys/mman.h>
> +#include <fcntl.h>
> +
> +#include "utils.h"
> +
> +#define HPAGE_OFF 0
> +#define HPAGE_ON 1
> +
> +#define PAGE_SHIFT_4K 12
> +#define PAGE_SHIFT_64K 16
> +#define PAGE_SIZE_4K 0x1000
> +#define PAGE_SIZE_64K 0x10000
> +#define PAGE_SIZE_HUGE 16UL * 1024 * 1024
> +
> +#define MEM_GB 1024UL * 1024 * 1024
> +#define MEM_MB 1024UL * 1024
> +#define MME_KB 1024UL
> +
> +#define PMAP_FILE "/proc/self/pagemap"
> +#define PMAP_PFN 0x007FFFFFFFFFFFFFUL
> +#define PMAP_SIZE 8
> +
> +#define SOFT_OFFLINE "/sys/devices/system/memory/soft_offline_page"
> +#define HARD_OFFLINE "/sys/devices/system/memory/hard_offline_page"
> +
> +#define MMAP_LENGTH (256 * MEM_MB)
> +#define MMAP_ADDR (void *)(0x0UL)
> +#define MMAP_PROT (PROT_READ | PROT_WRITE)
> +#define MMAP_FLAGS (MAP_PRIVATE | MAP_ANONYMOUS)
> +#define MMAP_FLAGS_HUGE (MAP_SHARED)
> +
> +#define FILE_NAME "huge/hugepagefile"
> +
> +static void write_buffer(char *addr, unsigned long length)
> +{
> + unsigned long i;
> +
> + for (i = 0; i < length; i++)
> + *(addr + i) = (char)i;
> +}
> +
> +static int read_buffer(char *addr, unsigned long length)
> +{
> + unsigned long i;
> +
> + for (i = 0; i < length; i++) {
> + if (*(addr + i) != (char)i) {
> + printf("Data miscompare at addr[%lu]\n", i);
> + return 1;
> + }
> + }
> + return 0;
> +}
> +
> +static unsigned long get_npages(unsigned long length, unsigned long size)
> +{
> + unsigned int tmp1 = length, tmp2 = size;
I think we want unsigned long here but this is very minor nit
> +
> + return tmp1/tmp2;
> +}
> +
> +static void soft_offline_pages(int hugepage, void *addr,
> + unsigned long npages, unsigned long *failed)
> +{
> + unsigned long psize, offset, pfn, pa, count;
> + void *tmp;
> + int i, fd1, fd2;
> + char buf[20];
> +
> + fd1 = open(PMAP_FILE, O_RDONLY);
> + if (fd1 == -1) {
> + perror("open() failed");
> + exit(-1);
> + }
> +
> + fd2 = open(SOFT_OFFLINE, O_WRONLY);
> + if (fd2 == -1) {
> + perror("open() failed");
> + exit(-1);
> + }
> +
> + count = 0;
> + psize = getpagesize();
> + for (i = 0; i < npages; i++) {
> + if (hugepage)
> + tmp = addr + i * PAGE_SIZE_HUGE;
> + else
> + tmp = addr + i * psize;
> +
> + offset = ((unsigned long) tmp / psize) * PMAP_SIZE;
> +
> + if (lseek(fd1, offset, SEEK_SET) == -1) {
> + perror("lseek() failed");
> + exit(-1);
> + }
> +
> + if (read(fd1, &pfn, sizeof(pfn)) == -1) {
> + perror("read() failed");
> + exit(-1);
> + }
> +
> + pfn = pfn & PMAP_PFN;
> + if (psize == PAGE_SIZE_4K)
> + pa = pfn << PAGE_SHIFT_4K;
> +
> + if (psize == PAGE_SIZE_64K)
> + pa = pfn << PAGE_SHIFT_64K;
> +
> + sprintf(buf, "0x%lx\n", pa);
> +
> + if (write(fd2, buf, strlen(buf)) == -1) {
> + perror("write() failed");
> + printf("%d PFN: %lx BUF: %s\n",i, pfn, buf);
> + count++;
> + exit(-1);
> + }
> +
> + }
> +
> + if (failed)
> + *failed = count;
> +
> + close(fd1);
> + close(fd2);
> +}
> +
> +int test_migration(unsigned long length)
> +{
> + unsigned long failed;
> + void *addr;
> + int ret;
> +
> + addr = mmap(MMAP_ADDR, length, MMAP_PROT, MMAP_FLAGS, -1, 0);
> + if (addr == MAP_FAILED) {
> + perror("mmap() failed");
> + exit(-1);
> + }
> +
> + write_buffer(addr, length);
> + soft_offline_pages(HPAGE_OFF, addr, length/getpagesize(), &failed);
You've defined get_npages() so I assume it has to be used or not used at all
> + ret = read_buffer(addr, length);
> +
> + printf("%ld pages moved, %ld pages failed\n", (length/getpagesize() -
> failed), failed);
> +
> + munmap(addr, length);
> + return ret;
> +}
> +
> +int test_huge_migration(unsigned long length)
> +{
> + unsigned long failed, npages;
> + void *addr;
> + int fd, ret;
> +
> + fd = open(FILE_NAME, O_CREAT | O_RDWR, 0755);
> + if (fd < 0) {
> + perror("open() failed");
> + exit(-1);
> + }
> +
> + addr = mmap(MMAP_ADDR, length, MMAP_PROT, MMAP_FLAGS_HUGE, fd, 0);
> + if (addr == MAP_FAILED) {
> + perror("mmap() failed");
> + unlink(FILE_NAME);
> + exit(-1);
> + }
> +
> + if (mlock(addr, length) == -1) {
> + perror("mlock() failed");
> + munmap(addr, length);
> + unlink(FILE_NAME);
> + exit(-1);
> + }
> +
> + write_buffer(addr, length);
> + npages = get_npages(length, PAGE_SIZE_HUGE);
> + soft_offline_pages(HPAGE_ON, addr, npages, &failed);
> + ret = read_buffer(addr, length);
> +
> + printf("%ld pages moved, %ld pages failed\n", (npages - failed), failed);
> +
> + munmap(addr, length);
> + unlink(FILE_NAME);
> + return ret;
> +}
> diff --git a/tools/testing/selftests/powerpc/mm/page-migration.c
> b/tools/testing/selftests/powerpc/mm/page-migration.c
> new file mode 100644
> index 0000000..fc6e472
> --- /dev/null
> +++ b/tools/testing/selftests/powerpc/mm/page-migration.c
> @@ -0,0 +1,33 @@
> +/*
> + * Copyright (C) 2015, Anshuman Khandual, IBM Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published
> + * by the Free Software Foundation.
> + */
> +#include "migration.h"
> +
> +static int page_migration(void)
> +{
> + int ret = 0;
> +
> + if ((unsigned long)getpagesize() == 0x1000)
> + printf("Running on base page size 4K\n");
> +
> + if ((unsigned long)getpagesize() == 0x10000)
> + printf("Running on base page size 64K\n");
> +
> + ret = test_migration(4 * MEM_MB);
> + ret = test_migration(64 * MEM_MB);
> + ret = test_migration(256 * MEM_MB);
> + ret = test_migration(512 * MEM_MB);
> + ret = test_migration(1 * MEM_GB);
> + ret = test_migration(2 * MEM_GB);
> +
> + return ret;
> +}
> +
> +int main(void)
> +{
> + return test_harness(page_migration, "page_migration");
> +}
> diff --git a/tools/testing/selftests/powerpc/mm/run_mmtests
> b/tools/testing/selftests/powerpc/mm/run_mmtests
> new file mode 100755
> index 0000000..89a7ed5
> --- /dev/null
> +++ b/tools/testing/selftests/powerpc/mm/run_mmtests
> @@ -0,0 +1,104 @@
> +#!/bin/bash
> +
> +# Mostly borrowed from tools/testing/selftests/vm/run_vmtests
> +
> +# Please run this as root
> +# Try allocating 2GB of 16MB huge pages, below is the size in kB.
> +# Please change this needed memory if the test program changes
> +needmem=2097152
> +mnt=./huge
> +exitcode=0
> +
> +# Get huge pagesize and freepages from /proc/meminfo
> +while read name size unit; do
> + if [ "$name" = "HugePages_Free:" ]; then
> + freepgs=$size
> + fi
> + if [ "$name" = "Hugepagesize:" ]; then
> + pgsize=$size
> + fi
> +done < /proc/meminfo
> +
> +# Set required nr_hugepages
> +if [ -n "$freepgs" ] && [ -n "$pgsize" ]; then
> + nr_hugepgs=`cat /proc/sys/vm/nr_hugepages`
> + needpgs=`expr $needmem / $pgsize`
> + tries=2
> + while [ $tries -gt 0 ] && [ $freepgs -lt $needpgs ]; do
> + lackpgs=$(( $needpgs - $freepgs ))
> + echo 3 > /proc/sys/vm/drop_caches
> + echo $(( $lackpgs + $nr_hugepgs )) > /proc/sys/vm/nr_hugepages
> + if [ $? -ne 0 ]; then
> + echo "Please run this test as root"
> + fi
> + while read name size unit; do
> + if [ "$name" = "HugePages_Free:" ]; then
> + freepgs=$size
> + fi
> + done < /proc/meminfo
> + tries=$((tries - 1))
> + done
> + if [ $freepgs -lt $needpgs ]; then
> + printf "Not enough huge pages available (%d < %d)\n" \
> + $freepgs $needpgs
> + fi
> +else
> + echo "No hugetlbfs support in kernel ? check dmesg"
> +fi
> +
> +mkdir $mnt
> +mount -t hugetlbfs none $mnt
> +
> +# Run the test programs
> +echo "...................."
> +echo "Test HugeTLB vs THP"
> +echo "...................."
> +./hugetlb_vs_thp_test
> +if [ $? -ne 0 ]; then
> + echo "[FAIL]"
> + exitcode=1
> +else
> + echo "[PASS]"
> +fi
> +
> +echo "........................."
> +echo "Test subpage protection"
> +echo "........................."
> +./subpage_prot
> +if [ $? -ne 0 ]; then
> + echo "[FAIL]"
> + exitcode=1
> +else
> + echo "[PASS]"
> +fi
> +
> +echo "..........................."
> +echo "Test normal page migration"
> +echo "..........................."
> +./page-migration
> +if [ $? -ne 0 ]; then
> + echo "[FAIL]"
> + exitcode=1
> +else
> + echo "[PASS]"
> +fi
> +
> +# Enable this after huge page migration is supported on POWER
> +
> +#echo "........................."
> +#echo "Test huge page migration"
> +#echo "........................."
> +#./hugepage-migration
> +#if [ $? -ne 0 ]; then
> +# echo "[FAIL]"
> +# exitcode=1
> +#else
> +# echo "[PASS]"
> +#fi
> +
> +# Huge pages cleanup
> +umount $mnt
> +rm -rf $mnt
> +echo $nr_hugepgs > /proc/sys/vm/nr_hugepages
> +
> +exit $exitcode
> --
> 2.1.0
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev at lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
More information about the Linuxppc-dev
mailing list