Home | History | Annotate | Download | only in swapping
      1 /*
      2  * Copyright (C) 2012  Red Hat, Inc.
      3  * This program is free software; you can redistribute it and/or
      4  * modify it under the terms of version 2 of the GNU General Public
      5  * License as published by the Free Software Foundation.
      6  *
      7  * This program is distributed in the hope that it would be useful,
      8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     10  *
     11  * Further, this software is distributed without any warranty that it
     12  * is free of the rightful claim of any third person regarding
     13  * infringement or the like.  Any license provided herein, whether
     14  * implied or otherwise, applies only to this software file.  Patent
     15  * licenses, if any, provided herein do not apply to combinations of
     16  * this program with other software, or any other product whatsoever.
     17  *
     18  * You should have received a copy of the GNU General Public License
     19  * along with this program; if not, write the Free Software
     20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
     21  * 02110-1301, USA.
     22  */
     23 /*
     24  * swapping01 - first time swap use results in heavy swapping
     25  *
     26  * This case is used for testing upstream commit: 50a1598
     27  *
     28  * The upstream commit fixed a issue on s390/x platform that heavy
     29  * swapping might occur in some condition, however since the patch
     30  * was quite general, this testcase will be run on all supported
     31  * platforms to ensure no regression been introduced.
     32  *
     33  * Details of the upstream fix:
     34  * On x86 a page without a mapper is by definition not referenced / old.
     35  * The s390 architecture keeps the reference bit in the storage key and
     36  * the current code will check the storage key for page without a mapper.
     37  * This leads to an interesting effect: the first time an s390 system
     38  * needs to write pages to swap it only finds referenced pages. This
     39  * causes a lot of pages to get added and written to the swap device.
     40  * To avoid this behaviour change page_referenced to query the storage
     41  * key only if there is a mapper of the page.
     42  *
     43  * Test Strategy:
     44  * Try to allocate memory which size is slightly larger than current
     45  * available memory. After allocation done, continue loop for a while
     46  * and calculate the used swap size. The used swap size should be small
     47  * enough, else it indicates that heavy swapping is occured unexpectedly.
     48  */
     49 
     50 #include <sys/types.h>
     51 #include <sys/wait.h>
     52 #include <stdio.h>
     53 #include <stdlib.h>
     54 #include <string.h>
     55 #include <unistd.h>
     56 #include "test.h"
     57 #include "mem.h"
     58 
     59 char *TCID = "swapping01";
     60 int TST_TOTAL = 1;
     61 
     62 /* allow swapping 1 * phy_mem in maximum */
     63 #define COE_DELTA       1
     64 /* will try to alloc 1.3 * phy_mem */
     65 #define COE_SLIGHT_OVER 0.3
     66 
     67 static void init_meminfo(void);
     68 static void do_alloc(void);
     69 static void check_swapping(void);
     70 
     71 static long mem_available_init;
     72 static long swap_free_init;
     73 static long mem_over;
     74 static long mem_over_max;
     75 static pid_t pid;
     76 
     77 int main(int argc, char *argv[])
     78 {
     79 	int lc;
     80 
     81 	tst_parse_opts(argc, argv, NULL, NULL);
     82 
     83 #if __WORDSIZE == 32
     84 	tst_brkm(TCONF, NULL, "test is not designed for 32-bit system.");
     85 #endif
     86 
     87 	setup();
     88 
     89 	for (lc = 0; TEST_LOOPING(lc); lc++) {
     90 		tst_count = 0;
     91 
     92 		init_meminfo();
     93 
     94 		switch (pid = fork()) {
     95 		case -1:
     96 			tst_brkm(TBROK | TERRNO, cleanup, "fork");
     97 		case 0:
     98 			do_alloc();
     99 			exit(0);
    100 		default:
    101 			check_swapping();
    102 		}
    103 	}
    104 	cleanup();
    105 	tst_exit();
    106 }
    107 
    108 static void init_meminfo(void)
    109 {
    110 	swap_free_init = read_meminfo("SwapFree:");
    111 	if (FILE_LINES_SCANF(cleanup, "/proc/meminfo", "MemAvailable: %ld",
    112 		&mem_available_init)) {
    113 		mem_available_init = read_meminfo("MemFree:")
    114 			+ read_meminfo("Cached:");
    115 	}
    116 	mem_over = mem_available_init * COE_SLIGHT_OVER;
    117 	mem_over_max = mem_available_init * COE_DELTA;
    118 
    119 	/* at least 10MB available physical memory needed */
    120 	if (mem_available_init < 10240)
    121 		tst_brkm(TCONF, cleanup, "Not enough available mem to test.");
    122 
    123 	if (swap_free_init < mem_over_max)
    124 		tst_brkm(TCONF, cleanup, "Not enough swap space to test.");
    125 }
    126 
    127 static void do_alloc(void)
    128 {
    129 	long mem_count;
    130 	void *s;
    131 
    132 	tst_resm(TINFO, "available physical memory: %ld MB",
    133 		mem_available_init / 1024);
    134 	mem_count = mem_available_init + mem_over;
    135 	tst_resm(TINFO, "try to allocate: %ld MB", mem_count / 1024);
    136 	s = malloc(mem_count * 1024);
    137 	if (s == NULL)
    138 		tst_brkm(TBROK | TERRNO, cleanup, "malloc");
    139 	memset(s, 1, mem_count * 1024);
    140 	tst_resm(TINFO, "memory allocated: %ld MB", mem_count / 1024);
    141 	if (raise(SIGSTOP) == -1)
    142 		tst_brkm(TBROK | TERRNO, tst_exit, "kill");
    143 	free(s);
    144 }
    145 
    146 static void check_swapping(void)
    147 {
    148 	int status, i;
    149 	long swap_free_now, swapped;
    150 
    151 	/* wait child stop */
    152 	if (waitpid(pid, &status, WUNTRACED) == -1)
    153 		tst_brkm(TBROK | TERRNO, cleanup, "waitpid");
    154 	if (!WIFSTOPPED(status))
    155 		tst_brkm(TBROK, cleanup, "child was not stopped.");
    156 
    157 	/* Still occupying memory, loop for a while */
    158 	i = 0;
    159 	while (i < 10) {
    160 		swap_free_now = read_meminfo("SwapFree:");
    161 		sleep(1);
    162 		if (abs(swap_free_now - read_meminfo("SwapFree:")) < 512)
    163 			break;
    164 
    165 		i++;
    166 	}
    167 
    168 	swap_free_now = read_meminfo("SwapFree:");
    169 	swapped = swap_free_init - swap_free_now;
    170 	if (swapped > mem_over_max) {
    171 		kill(pid, SIGCONT);
    172 		tst_brkm(TFAIL, cleanup, "heavy swapping detected: "
    173 				"%ld MB swapped.", swapped / 1024);
    174 	}
    175 
    176 	tst_resm(TPASS, "no heavy swapping detected, %ld MB swapped.",
    177 		 swapped / 1024);
    178 	kill(pid, SIGCONT);
    179 	/* wait child exit */
    180 	if (waitpid(pid, &status, 0) == -1)
    181 		tst_brkm(TBROK | TERRNO, cleanup, "waitpid");
    182 }
    183 
    184 void setup(void)
    185 {
    186 	tst_sig(FORK, DEF_HANDLER, cleanup);
    187 
    188 	TEST_PAUSE;
    189 }
    190 
    191 void cleanup(void)
    192 {
    193 }
    194