2 * Migration stress workload
4 * Copyright (c) 2016 Red Hat, Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 #include "qemu/osdep.h"
22 #include <sys/reboot.h>
23 #include <sys/syscall.h>
24 #include <linux/random.h>
26 #include <sys/mount.h>
30 #define PAGE_SIZE 4096
32 static int gettid(void)
34 return syscall(SYS_gettid
);
37 static __attribute__((noreturn
)) void exit_failure(void)
42 fprintf(stderr
, "%s (%05d): ERROR: cannot reboot: %s\n",
43 argv0
, gettid(), strerror(errno
));
50 static __attribute__((noreturn
)) void exit_success(void)
55 fprintf(stderr
, "%s (%05d): ERROR: cannot reboot: %s\n",
56 argv0
, gettid(), strerror(errno
));
63 static int get_command_arg_str(const char *name
,
66 static char line
[1024];
67 FILE *fp
= fopen("/proc/cmdline", "r");
71 fprintf(stderr
, "%s (%05d): ERROR: cannot open /proc/cmdline: %s\n",
72 argv0
, gettid(), strerror(errno
));
76 if (!fgets(line
, sizeof line
, fp
)) {
77 fprintf(stderr
, "%s (%05d): ERROR: cannot read /proc/cmdline: %s\n",
78 argv0
, gettid(), strerror(errno
));
84 start
= strstr(line
, name
);
88 start
+= strlen(name
);
91 fprintf(stderr
, "%s (%05d): ERROR: no value provided for '%s' in /proc/cmdline\n",
92 argv0
, gettid(), name
);
96 end
= strstr(start
, " ");
98 end
= strstr(start
, "\n");
101 fprintf(stderr
, "%s (%05d): ERROR: no value provided for '%s' in /proc/cmdline\n",
102 argv0
, gettid(), name
);
107 *val
= strndup(start
, end
- start
);
109 *val
= strdup(start
);
114 static int get_command_arg_ull(const char *name
,
115 unsigned long long *val
)
120 int ret
= get_command_arg_str(name
, &valstr
);
125 *val
= strtoll(valstr
, &end
, 10);
127 fprintf(stderr
, "%s (%05d): ERROR: cannot parse %s value %s\n",
128 argv0
, gettid(), name
, valstr
);
137 static int random_bytes(char *buf
, size_t len
)
141 fd
= open("/dev/urandom", O_RDONLY
);
143 fprintf(stderr
, "%s (%05d): ERROR: cannot open /dev/urandom: %s\n",
144 argv0
, gettid(), strerror(errno
));
148 if (read(fd
, buf
, len
) != len
) {
149 fprintf(stderr
, "%s (%05d): ERROR: cannot read /dev/urandom: %s\n",
150 argv0
, gettid(), strerror(errno
));
161 static unsigned long long now(void)
165 gettimeofday(&tv
, NULL
);
167 return (tv
.tv_sec
* 1000ull) + (tv
.tv_usec
/ 1000ull);
170 static int stressone(unsigned long long ramsizeMB
)
172 size_t pagesPerMB
= 1024 * 1024 / PAGE_SIZE
;
173 char *ram
= malloc(ramsizeMB
* 1024 * 1024);
176 char *data
= malloc(PAGE_SIZE
);
179 unsigned long long before
, after
;
182 fprintf(stderr
, "%s (%05d): ERROR: cannot allocate %llu MB of RAM: %s\n",
183 argv0
, gettid(), ramsizeMB
, strerror(errno
));
187 fprintf(stderr
, "%s (%d): ERROR: cannot allocate %d bytes of RAM: %s\n",
188 argv0
, gettid(), PAGE_SIZE
, strerror(errno
));
193 /* We don't care about initial state, but we do want
194 * to fault it all into RAM, otherwise the first iter
195 * of the loop below will be quite slow. We cna't use
196 * 0x0 as the byte as gcc optimizes that away into a
197 * calloc instead :-) */
198 memset(ram
, 0xfe, ramsizeMB
* 1024 * 1024);
200 if (random_bytes(data
, PAGE_SIZE
) < 0) {
211 for (i
= 0; i
< ramsizeMB
; i
++, nMB
++) {
212 for (j
= 0; j
< pagesPerMB
; j
++) {
214 for (k
= 0; k
< PAGE_SIZE
; k
+= sizeof(long long)) {
215 ramptr
+= sizeof(long long);
216 dataptr
+= sizeof(long long);
217 *(unsigned long long *)ramptr
^= *(unsigned long long *)dataptr
;
223 fprintf(stderr
, "%s (%05d): INFO: %06llums copied 1 GB in %05llums\n",
224 argv0
, gettid(), after
, after
- before
);
236 static void *stressthread(void *arg
)
238 unsigned long long ramsizeMB
= *(unsigned long long *)arg
;
240 stressone(ramsizeMB
);
245 static int stress(unsigned long long ramsizeGB
, int ncpus
)
248 unsigned long long ramsizeMB
= ramsizeGB
* 1024 / ncpus
;
251 for (i
= 0; i
< ncpus
; i
++) {
253 pthread_create(&thr
, NULL
,
254 stressthread
, &ramsizeMB
);
257 stressone(ramsizeMB
);
263 static int mount_misc(const char *fstype
, const char *dir
)
265 if (mkdir(dir
, 0755) < 0 && errno
!= EEXIST
) {
266 fprintf(stderr
, "%s (%05d): ERROR: cannot create %s: %s\n",
267 argv0
, gettid(), dir
, strerror(errno
));
271 if (mount("none", dir
, fstype
, 0, NULL
) < 0) {
272 fprintf(stderr
, "%s (%05d): ERROR: cannot mount %s: %s\n",
273 argv0
, gettid(), dir
, strerror(errno
));
280 static int mount_all(void)
282 if (mount_misc("proc", "/proc") < 0 ||
283 mount_misc("sysfs", "/sys") < 0 ||
284 mount_misc("tmpfs", "/dev") < 0)
287 mknod("/dev/urandom", 0777 | S_IFCHR
, makedev(1, 9));
288 mknod("/dev/random", 0777 | S_IFCHR
, makedev(1, 8));
293 int main(int argc
, char **argv
)
295 unsigned long long ramsizeGB
= 1;
299 const char *sopt
= "hr:c:";
300 struct option lopt
[] = {
301 { "help", no_argument
, NULL
, 'h' },
302 { "ramsize", required_argument
, NULL
, 'r' },
303 { "cpus", required_argument
, NULL
, 'c' },
311 while ((ch
= getopt_long(argc
, argv
, sopt
, lopt
, &opt_ind
)) != -1) {
315 ramsizeGB
= strtoll(optarg
, &end
, 10);
316 if (errno
!= 0 || *end
) {
317 fprintf(stderr
, "%s (%05d): ERROR: Cannot parse RAM size %s\n",
318 argv0
, gettid(), optarg
);
325 ncpus
= strtoll(optarg
, &end
, 10);
326 if (errno
!= 0 || *end
) {
327 fprintf(stderr
, "%s (%05d): ERROR: Cannot parse CPU count %s\n",
328 argv0
, gettid(), optarg
);
335 fprintf(stderr
, "%s: [--help][--ramsize GB][--cpus N]\n", argv0
);
344 ret
= get_command_arg_ull("ramsize", &ramsizeGB
);
350 ncpus
= sysconf(_SC_NPROCESSORS_ONLN
);
352 fprintf(stdout
, "%s (%05d): INFO: RAM %llu GiB across %d CPUs\n",
353 argv0
, gettid(), ramsizeGB
, ncpus
);
355 if (stress(ramsizeGB
, ncpus
) < 0)