Home | History | Annotate | Download | only in src
      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