#include #include #include #include #include #include #include #include #include #include #include "inc/testsuite.h" struct swap_struct { int page_size; int fd; int flags; void *buf; unsigned long len; int key_break; }; #define SWAP_DEFAULT_SIZE 0x200000 /* 2MB */ #define SWAP_PAGE_TO_SPLIT 511 #define SWAP_PAGE_TO_SWAP 1 #define SWAP_PAGE_TO_SWAP_NUM 256 #ifndef MADV_PAGEOUT #define MADV_PAGEOUT 21 #endif static void usage(void) { fprintf(stdout, "testsuite mm swap -l -k\n"); fprintf(stdout, "\n"); fprintf(stdout, "-l: Length of memory to be mapped\n"); fprintf(stdout, "-w: Length of memory to be copied-on-write\n"); fprintf(stdout, "-k: Stop at various stages\n"); fprintf(stdout, "\n"); } static int swap_init_data(struct swap_struct *m) { m->page_size = getpagesize(); m->fd = -1; m->flags = (MAP_PRIVATE | MAP_ANONYMOUS); m->len = SWAP_DEFAULT_SIZE; m->key_break = 0; return 0; } static int swap_handler(int argc, char **argv) { struct swap_struct m; unsigned long *pval; int i, opt, ret; ret = swap_init_data(&m); if (ret) return ret; while ((opt = getopt(argc, argv, "l:w:kh")) != -1) { switch (opt) { case 'l': m.len = util_memory_parse_size(optarg); if (m.len <= SWAP_DEFAULT_SIZE) { fprintf(stderr, "%s: length 0x%lx less than 0x%x\n", __func__, m.len, SWAP_DEFAULT_SIZE); return -1; } break; case 'k': m.key_break = 1; break; case 'h': usage(); return 0; } } /* * Setup the area. The area should be backed up with huge pages * if it suits. Write to the area to ensure the area is populted * completely. */ m.buf = mmap(NULL, m.len, PROT_READ | PROT_WRITE, m.flags, m.fd, 0); if (m.buf == (void *)-1) { fprintf(stderr, "Unable do mmap()\n"); goto out; } memset(m.buf, 0xff, m.len); /* Force to split the huge page */ util_misc_key_press(m.key_break, " ", "Any key to split THP"); ret = madvise(m.buf + SWAP_PAGE_TO_SPLIT * m.page_size, m.page_size, MADV_FREE); if (ret) { fprintf(stderr, "Error %d to split THP\n", ret); goto out; } /* Swap one sub-page */ util_misc_key_press(m.key_break, " ", "Any key to swap sub-pages"); ret = madvise(m.buf + SWAP_PAGE_TO_SWAP * m.page_size, SWAP_PAGE_TO_SWAP_NUM * m.page_size, MADV_PAGEOUT); if (ret) { fprintf(stderr, "Error %d to swap one sub-page\n", ret); goto out; } /* Read the swapped sub-page */ util_misc_key_press(m.key_break, " ", "Any key to read the swapped sub-pages"); for (i = 0; i < SWAP_PAGE_TO_SWAP_NUM; i++) { pval = (unsigned long *)(m.buf + (SWAP_PAGE_TO_SWAP + i) * m.page_size); fprintf(stdout, " Page[%03d]: 0x%016lx\n", i, *pval); } /* Exit */ util_misc_key_press(m.key_break, " ", "Any key to exit"); out: if (m.buf != (void *)-1) munmap(m.buf, m.len); if (m.fd > 0) close(m.fd); return 0; } static struct command swap_command = { .name = "swap", .handler = swap_handler, .children = LIST_HEAD_INIT(swap_command.children), .link = LIST_HEAD_INIT(swap_command.link), }; int mm_swap_init(void) { return command_add(&mm_command, &swap_command); }