On 11/24/15, Anshuman Khandual <khand...@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 <khand...@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@lists.ozlabs.org > https://lists.ozlabs.org/listinfo/linuxppc-dev _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev