1 /******************************************************************************/ 2 /* */ 3 /* Copyright (c) International Business Machines Corp., 2001 */ 4 /* */ 5 /* This program is free software; you can redistribute it and/or modify */ 6 /* it under the terms of the GNU General Public License as published by */ 7 /* the Free Software Foundation; either version 2 of the License, or */ 8 /* (at your option) any later version. */ 9 /* */ 10 /* This program is distributed in the hope that it will be useful, */ 11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ 13 /* the GNU General Public License for more details. */ 14 /* */ 15 /* You should have received a copy of the GNU General Public License */ 16 /* along with this program; if not, write to the Free Software */ 17 /* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ 18 /* */ 19 /******************************************************************************/ 20 21 /******************************************************************************/ 22 /* */ 23 /* History: July - 02 - 2001 Created by Manoj Iyer, IBM Austin TX. */ 24 /* email:manjo (at) austin.ibm.com */ 25 /* */ 26 /* July - 07 - 2001 Modified - changed MAP_PRIVATE to MAP_SHARED */ 27 /* read defect 187 for details. */ 28 /* */ 29 /* July - 09 - 2001 Modified - added option to MAP_PRIVATE or */ 30 /* MAP_SHARED, -p, default is to MAP_SHARED. */ 31 /* */ 32 /* July - 09 - 2001 Modified - added option '-a' MAP_ANONYMOUS. */ 33 /* Default is to map a file. */ 34 /* */ 35 /* Aug - 01 - 2001 Modified - added option 'a' to getop list. */ 36 /* */ 37 /* Oct - 25 - 2001 Modified - changed scheme. Test will be run */ 38 /* once unless -x option is used. */ 39 /* */ 40 /* Apr - 16 - 2003 Modified - replaced tempnam() use with */ 41 /* mkstemp(). -Robbie Williamson */ 42 /* email:robbiew (at) us.ibm.com */ 43 /* */ 44 /* May - 12 - 2003 Modified - remove the huge files when */ 45 /* we are done with the test - Paul Larson */ 46 /* email:plars (at) linuxtestproject.org */ 47 /* File: mmap2.c */ 48 /* */ 49 /* Description: Test the LINUX memory manager. The program is aimed at */ 50 /* stressing the memory manager by repeaded map/write/unmap of a */ 51 /* large (by default 128MB) file. */ 52 /* */ 53 /* Create a file of the specified size in mb, map the file, */ 54 /* change the contents of the file and unmap it. This is repeated*/ 55 /* several times for the specified number of hours. */ 56 /* */ 57 /******************************************************************************/ 58 59 #include <stdio.h> 60 #include <sys/types.h> 61 #include <sys/stat.h> 62 #include <fcntl.h> 63 #include <unistd.h> 64 #include <errno.h> 65 #include <sys/mman.h> 66 #include <sched.h> 67 #include <stdlib.h> 68 #include <signal.h> 69 #include <sys/time.h> 70 #include <sys/wait.h> 71 #include <signal.h> 72 #include <string.h> 73 #include <getopt.h> 74 #include "test.h" 75 76 #define MB (1024 * 1024) 77 #ifndef TRUE 78 #define TRUE 1 79 #endif 80 #ifndef FALSE 81 #define FALSE 0 82 #endif 83 84 static int mkfile(int size) 85 { 86 int fd; 87 int index = 0; 88 char buff[4096]; 89 char template[PATH_MAX]; 90 91 memset(buff, 'a', 4096); 92 snprintf(template, PATH_MAX, "ashfileXXXXXX"); 93 fd = mkstemp(template); 94 if (fd == -1) { 95 perror("mkfile(): mkstemp()"); 96 return -1; 97 } else { 98 unlink(template); 99 fprintf(stdout, "creating tmp file and writing 'a' to it "); 100 } 101 102 while (index < (size * MB)) { 103 index += 4096; 104 if (write(fd, buff, 4096) == -1) { 105 perror("mkfile(): write()"); 106 return -1; 107 } 108 } 109 fprintf(stdout, "created file of size %d\n" 110 "content of the file is 'a'\n", index); 111 112 if (fsync(fd) == -1) { 113 perror("mkfile(): fsync()"); 114 return -1; 115 } 116 return fd; 117 } 118 119 static void sig_handler(int signal) 120 { 121 if (signal != SIGALRM) { 122 fprintf(stderr, "sig_handlder(): unexpected signal caught" 123 "[%d]\n", signal); 124 exit(-1); 125 } else 126 fprintf(stdout, "Test ended, success\n"); 127 exit(0); 128 } 129 130 static void usage(char *progname) 131 { 132 fprintf(stderr, 133 "Usage: %s -h -s -x\n" 134 "\t -a set map_flags to MAP_ANONYMOUS\n" 135 "\t -h help, usage message.\n" 136 "\t -p set map_flag to MAP_PRIVATE.\tdefault:" 137 "MAP_SHARED\n" 138 "\t -s size of the file/memory to be mmaped.\tdefault:" 139 "128MB\n" 140 "\t -x time for which test is to be run.\tdefault:" 141 "24 Hrs\n", progname); 142 exit(-1); 143 } 144 145 unsigned long get_available_memory_mb(void) 146 { 147 unsigned long ps, pn; 148 149 ps = sysconf(_SC_PAGESIZE); 150 pn = sysconf(_SC_AVPHYS_PAGES); 151 return (ps / 1024) * pn / 1024; 152 } 153 154 int main(int argc, char **argv) 155 { 156 int fd; 157 unsigned long fsize = 128; 158 float exec_time = 24; 159 int c; 160 int sig_ndx; 161 int map_flags = MAP_SHARED; 162 int map_anon = FALSE; 163 int run_once = TRUE; 164 char *memptr; 165 unsigned long avail_memory_mb; 166 struct sigaction sigptr; 167 168 static struct signal_info { 169 int signum; 170 char *signame; 171 } sig_info[] = { 172 { 173 SIGHUP, "SIGHUP"}, { 174 SIGINT, "SIGINT"}, { 175 SIGQUIT, "SIGQUIT"}, { 176 SIGABRT, "SIGABRT"}, { 177 SIGBUS, "SIGBUS"}, { 178 SIGSEGV, "SIGSEGV"}, { 179 SIGALRM, "SIGALRM"}, { 180 SIGUSR1, "SIGUSR1"}, { 181 SIGUSR2, "SIGUSR2"}, { 182 -1, "ENDSIG"} 183 }; 184 185 while ((c = getopt(argc, argv, "ahps:x:")) != -1) { 186 switch (c) { 187 case 'a': 188 map_anon = TRUE; 189 break; 190 case 'h': 191 usage(argv[0]); 192 exit(-1); 193 break; 194 case 'p': 195 map_flags = MAP_PRIVATE; 196 break; 197 case 's': 198 fsize = atoi(optarg); 199 if (fsize == 0) 200 fprintf(stderr, "Using default " 201 "fsize %lu MB\n", fsize = 128); 202 break; 203 case 'x': 204 exec_time = atof(optarg); 205 if (exec_time == 0) 206 fprintf(stderr, "Using default exec " 207 "time %f hrs", exec_time = (float)24); 208 run_once = FALSE; 209 break; 210 default: 211 usage(argv[0]); 212 break; 213 } 214 } 215 216 fprintf(stdout, "MM Stress test, map/write/unmap large file\n" 217 "\tTest scheduled to run for: %f\n" 218 "\tSize of temp file in MB: %lu\n", exec_time, fsize); 219 220 avail_memory_mb = get_available_memory_mb(); 221 fprintf(stdout, "Available memory: %ldMB\n", avail_memory_mb); 222 if (fsize > avail_memory_mb) { 223 fprintf(stdout, "Not enough memory to run this case\n"); 224 exit(0); 225 } 226 227 alarm(exec_time * 3600.00); 228 229 sigptr.sa_handler = sig_handler; 230 sigfillset(&sigptr.sa_mask); 231 sigptr.sa_flags = 0; 232 for (sig_ndx = 0; sig_info[sig_ndx].signum != -1; sig_ndx++) { 233 sigaddset(&sigptr.sa_mask, sig_info[sig_ndx].signum); 234 if (sigaction(sig_info[sig_ndx].signum, &sigptr, 235 NULL) == -1) { 236 perror("man(): sigaction()"); 237 fprintf(stderr, "could not set handler for SIGALRM," 238 "errno = %d\n", errno); 239 exit(-1); 240 } 241 } 242 243 do { 244 if (!map_anon) { 245 fd = mkfile(fsize); 246 if (fd == -1) { 247 fprintf(stderr, "main(): mkfile(): Failed " 248 "to create temp file.\n"); 249 exit(-1); 250 } 251 } else { 252 fd = -1; 253 map_flags = map_flags | MAP_ANONYMOUS; 254 } 255 memptr = mmap(0, (fsize * MB), PROT_READ | PROT_WRITE, 256 map_flags, fd, 0); 257 if (memptr == MAP_FAILED) { 258 perror("main(): mmap()"); 259 exit(-1); 260 } else 261 fprintf(stdout, "file mapped at %p\n" 262 "changing file content to 'A'\n", memptr); 263 264 memset(memptr, 'A', ((fsize * MB) / sizeof(char))); 265 266 if (msync(memptr, ((fsize * MB) / sizeof(char)), 267 MS_SYNC | MS_INVALIDATE) == -1) { 268 perror("main(): msync()"); 269 exit(-1); 270 } 271 272 if (munmap(memptr, (fsize * MB) / sizeof(char)) == -1) { 273 perror("main(): munmap()"); 274 exit(-1); 275 } else 276 fprintf(stdout, "unmapped file at %p\n", memptr); 277 278 close(fd); 279 sync(); 280 } while (TRUE && !run_once); 281 exit(0); 282 } 283