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
open_file()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
usage(void)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
touch_pages(int nr_vmas)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
msync_file(int nr_vmas)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
touch_random_pages(void)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
child(int childno)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
main(int argc,char * argv[])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