1 /* 2 * Create lots of VMA's mapped by lots of tasks. To tickle objrmap and the 3 * virtual scan. 4 */ 5 6 #include <stdio.h> 7 #include <unistd.h> 8 #include <fcntl.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #include <errno.h> 12 #include <time.h> 13 #include <sys/mman.h> 14 #include <sys/signal.h> 15 #include <sys/stat.h> 16 #include <sys/wait.h> 17 18 char *progname; 19 char *filename; 20 void *mapped_mem; 21 22 int niters; 23 int ntasks = 100; 24 int nvmas = 100; 25 int vmasize = 1024*1024; 26 int vmas_to_do = -1; 27 int pagesize; 28 int fd; 29 char **vma_addresses; 30 volatile int *nr_children_running; 31 int verbose; 32 33 enum access_pattern { 34 ap_random, 35 ap_linear, 36 ap_half 37 } access_pattern = ap_linear; 38 39 void open_file() 40 { 41 fd = open(filename, O_RDWR|O_TRUNC|O_CREAT, 0666); 42 if (fd < 0) { 43 fprintf(stderr, "%s: Cannot open `%s': %s\n", 44 progname, filename, strerror(errno)); 45 exit(1); 46 } 47 } 48 49 void usage(void) 50 { 51 fprintf(stderr, "Usage: %s [-hlrvV] [-iN] [-nN] [-sN] [-tN] filename\n", 52 progname); 53 fprintf(stderr, " -h: Pattern: half of memory is busy\n"); 54 fprintf(stderr, " -l: Pattern: linear\n"); 55 fprintf(stderr, " -r: Pattern: random\n"); 56 fprintf(stderr, " -iN: Number of iterations\n"); 57 fprintf(stderr, " -nN: Number of VMAs\n"); 58 fprintf(stderr, " -sN: VMA size (pages)\n"); 59 fprintf(stderr, " -tN: Run N tasks\n"); 60 fprintf(stderr, " -VN: Number of VMAs to process\n"); 61 fprintf(stderr, " -v: Verbose\n"); 62 exit(1); 63 } 64 65 void touch_pages(int nr_vmas) 66 { 67 int i; 68 69 for (i = 0; i < nr_vmas; i++) { 70 char *p = vma_addresses[i]; 71 int page; 72 73 for (page = 0; page < vmasize; page++) 74 p[page * pagesize]++; 75 } 76 } 77 78 void msync_file(int nr_vmas) 79 { 80 int i; 81 82 for (i = 0; i < nr_vmas; i++) { 83 char *p = vma_addresses[i]; 84 85 msync(p, vmasize * pagesize, MS_ASYNC); 86 } 87 } 88 89 void touch_random_pages(void) 90 { 91 int vma; 92 int page; 93 94 srand(getpid() * time(0)); 95 96 for (vma = 0; vma < vmas_to_do; vma++) { 97 for (page = 0; page < vmasize; page++) { 98 int rand_vma; 99 int rand_page; 100 char *p; 101 102 rand_vma = rand() % nvmas; 103 rand_page = rand() % vmasize; 104 p = vma_addresses[rand_vma] + rand_page * pagesize; 105 (*p)++; 106 } 107 if (verbose > 1) 108 printf("vma %d/%d done\n", vma, nvmas); 109 } 110 } 111 112 void child(int childno) 113 { 114 int iter; 115 116 sleep(1); 117 if (access_pattern == ap_half && childno == 0) { 118 while (*nr_children_running > 1) { 119 touch_pages(nvmas / 2); 120 } 121 return; 122 } 123 124 for (iter = 0; iter < niters; iter++) { 125 if (access_pattern == ap_random) { 126 touch_random_pages(); 127 } else if (access_pattern == ap_linear) { 128 touch_pages(nvmas); 129 } else if (access_pattern == ap_half) { 130 touch_pages(nvmas); 131 } 132 if (verbose > 0) 133 printf("%d/%d\n", iter, niters); 134 } 135 } 136 137 int main(int argc, char *argv[]) 138 { 139 int c; 140 int i; 141 loff_t offset; 142 loff_t file_size; 143 int childno; 144 145 progname = argv[0]; 146 147 while ((c = getopt(argc, argv, "vrlhi:n:s:t:V:")) != -1) { 148 switch (c) { 149 case 'h': 150 access_pattern = ap_half; 151 break; 152 case 'l': 153 access_pattern = ap_linear; 154 break; 155 case 'r': 156 access_pattern = ap_random; 157 break; 158 case 'i': 159 niters = strtol(optarg, NULL, 10); 160 break; 161 case 'n': 162 nvmas = strtol(optarg, NULL, 10); 163 break; 164 case 's': 165 vmasize = strtol(optarg, NULL, 10); 166 break; 167 case 't': 168 ntasks = strtol(optarg, NULL, 10); 169 break; 170 case 'V': 171 vmas_to_do = strtol(optarg, NULL, 10); 172 break; 173 case 'v': 174 verbose++; 175 break; 176 } 177 } 178 179 if (optind == argc) 180 usage(); 181 filename = argv[optind++]; 182 if (optind != argc) 183 usage(); 184 185 if (vmas_to_do == -1) 186 vmas_to_do = nvmas; 187 188 pagesize = getpagesize(); 189 open_file(); 190 191 file_size = nvmas; 192 file_size *= vmasize; 193 file_size += nvmas - 1; 194 file_size *= pagesize; 195 196 printf("Total file size: %lldk, Total memory: %lldk\n", 197 file_size / 1024, 198 ((long long)nvmas * vmasize * pagesize) / 1024); 199 200 if (ftruncate(fd, file_size) < 0) { 201 perror("ftruncate"); 202 exit(1); 203 } 204 205 vma_addresses = malloc(nvmas * sizeof(*vma_addresses)); 206 nr_children_running = (int *)mmap(0, sizeof(*nr_children_running), 207 PROT_READ|PROT_WRITE, 208 MAP_SHARED|MAP_ANONYMOUS, 209 -1, 210 0); 211 if (nr_children_running == MAP_FAILED) { 212 perror("mmap1"); 213 exit(1); 214 } 215 216 offset = 0; 217 218 for (i = 0; i < nvmas; i++) { 219 char *p; 220 221 p = mmap(0, vmasize * pagesize, PROT_READ|PROT_WRITE, 222 MAP_SHARED, fd, offset); 223 if (p == MAP_FAILED) { 224 perror("mmap"); 225 exit(1); 226 } 227 vma_addresses[i] = p; 228 offset += vmasize * pagesize + pagesize; 229 } 230 231 touch_pages(nvmas); 232 msync_file(nvmas); 233 *nr_children_running = ntasks; 234 235 for (childno = 0; childno < ntasks; childno++) { 236 if (fork() == 0) { 237 child(childno); 238 exit(0); 239 } 240 } 241 242 signal(SIGINT, SIG_IGN); 243 244 for (i = 0; i < ntasks; i++) { 245 pid_t pid; 246 int status; 247 248 /* Catch each child error status and report. */ 249 pid = wait3(&status, 0, 0); 250 if (pid < 0) /* No more children? */ 251 break; 252 (*nr_children_running)--; 253 } 254 exit(0); 255 } 256