Home | History | Annotate | Download | only in swapping
      1 /*
      2  * Copyright (C) 2012-2017  Red Hat, Inc.
      3  *
      4  * This program is free software;  you can redistribute it and/or modify
      5  * it under the terms of the GNU General Public License as published by
      6  * the Free Software Foundation; either version 2 of the License, or
      7  * (at your option) any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
     12  * the GNU General Public License for more details.
     13  */
     14 /*
     15  * swapping01 - first time swap use results in heavy swapping
     16  *
     17  * This case is used for testing upstream commit: 50a1598
     18  *
     19  * The upstream commit fixed a issue on s390/x platform that heavy
     20  * swapping might occur in some condition, however since the patch
     21  * was quite general, this testcase will be run on all supported
     22  * platforms to ensure no regression been introduced.
     23  *
     24  * Details of the upstream fix:
     25  * On x86 a page without a mapper is by definition not referenced / old.
     26  * The s390 architecture keeps the reference bit in the storage key and
     27  * the current code will check the storage key for page without a mapper.
     28  * This leads to an interesting effect: the first time an s390 system
     29  * needs to write pages to swap it only finds referenced pages. This
     30  * causes a lot of pages to get added and written to the swap device.
     31  * To avoid this behaviour change page_referenced to query the storage
     32  * key only if there is a mapper of the page.
     33  *
     34  * Test Strategy:
     35  * Try to allocate memory which size is slightly larger than current
     36  * available memory. After allocation done, continue loop for a while
     37  * and calculate the used swap size. The used swap size should be small
     38  * enough, else it indicates that heavy swapping is occured unexpectedly.
     39  */
     40 
     41 #include <sys/types.h>
     42 #include <sys/wait.h>
     43 #include <stdio.h>
     44 #include <stdlib.h>
     45 #include <string.h>
     46 #include <unistd.h>
     47 #include "mem.h"
     48 
     49 /* allow swapping 1 * phy_mem in maximum */
     50 #define COE_DELTA       1
     51 /* will try to alloc 1.3 * phy_mem */
     52 #define COE_SLIGHT_OVER 0.3
     53 
     54 static void init_meminfo(void);
     55 static void do_alloc(void);
     56 static void check_swapping(void);
     57 
     58 static long mem_available_init;
     59 static long swap_free_init;
     60 static long mem_over;
     61 static long mem_over_max;
     62 static pid_t pid;
     63 
     64 static void test_swapping(void)
     65 {
     66 #if __WORDSIZE == 32
     67 	tst_brk(TCONF, "test is not designed for 32-bit system.");
     68 #endif
     69 
     70 	init_meminfo();
     71 
     72 	switch (pid = SAFE_FORK()) {
     73 		case 0:
     74 			do_alloc();
     75 			exit(0);
     76 		default:
     77 			check_swapping();
     78 	}
     79 }
     80 
     81 static void init_meminfo(void)
     82 {
     83 	swap_free_init = SAFE_READ_MEMINFO("SwapFree:");
     84 	if (FILE_LINES_SCANF("/proc/meminfo", "MemAvailable: %ld",
     85 		&mem_available_init)) {
     86 		mem_available_init = SAFE_READ_MEMINFO("MemFree:")
     87 			+ SAFE_READ_MEMINFO("Cached:");
     88 	}
     89 	mem_over = mem_available_init * COE_SLIGHT_OVER;
     90 	mem_over_max = mem_available_init * COE_DELTA;
     91 
     92 	/* at least 10MB available physical memory needed */
     93 	if (mem_available_init < 10240)
     94 		tst_brk(TCONF, "Not enough available mem to test.");
     95 
     96 	if (swap_free_init < mem_over_max)
     97 		tst_brk(TCONF, "Not enough swap space to test.");
     98 }
     99 
    100 static void do_alloc(void)
    101 {
    102 	long mem_count;
    103 	void *s;
    104 
    105 	tst_res(TINFO, "available physical memory: %ld MB",
    106 		mem_available_init / 1024);
    107 	mem_count = mem_available_init + mem_over;
    108 	tst_res(TINFO, "try to allocate: %ld MB", mem_count / 1024);
    109 	s = SAFE_MALLOC(mem_count * 1024);
    110 	memset(s, 1, mem_count * 1024);
    111 	tst_res(TINFO, "memory allocated: %ld MB", mem_count / 1024);
    112 	if (raise(SIGSTOP) == -1)
    113 		tst_brk(TBROK | TERRNO, "kill");
    114 	free(s);
    115 }
    116 
    117 static void check_swapping(void)
    118 {
    119 	int status, i;
    120 	long swap_free_now, swapped;
    121 
    122 	/* wait child stop */
    123 	SAFE_WAITPID(pid, &status, WUNTRACED);
    124 	if (!WIFSTOPPED(status))
    125 		tst_brk(TBROK, "child was not stopped.");
    126 
    127 	/* Still occupying memory, loop for a while */
    128 	i = 0;
    129 	while (i < 10) {
    130 		swap_free_now = SAFE_READ_MEMINFO("SwapFree:");
    131 		sleep(1);
    132 		if (abs(swap_free_now - SAFE_READ_MEMINFO("SwapFree:")) < 512)
    133 			break;
    134 
    135 		i++;
    136 	}
    137 
    138 	swap_free_now = SAFE_READ_MEMINFO("SwapFree:");
    139 	swapped = swap_free_init - swap_free_now;
    140 	if (swapped > mem_over_max) {
    141 		kill(pid, SIGCONT);
    142 		tst_brk(TFAIL, "heavy swapping detected: "
    143 				"%ld MB swapped.", swapped / 1024);
    144 	}
    145 
    146 	tst_res(TPASS, "no heavy swapping detected, %ld MB swapped.",
    147 		 swapped / 1024);
    148 	kill(pid, SIGCONT);
    149 	/* wait child exit */
    150 	SAFE_WAITPID(pid, &status, 0);
    151 }
    152 
    153 static struct tst_test test = {
    154 	.needs_root = 1,
    155 	.forks_child = 1,
    156 	.test_all = test_swapping,
    157 };
    158