error: Eliminate error_propagate() with Coccinelle, part 2
[qemu/ar7.git] / tests / migration / stress.c
bloba062ef6b555b6ff9ca51e74403e3ba98e25664a5
1 /*
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"
21 #include <getopt.h>
22 #include <sys/reboot.h>
23 #include <sys/syscall.h>
24 #include <linux/random.h>
25 #include <pthread.h>
26 #include <sys/mount.h>
28 const char *argv0;
30 #define PAGE_SIZE 4096
32 static int gettid(void)
34 return syscall(SYS_gettid);
37 static __attribute__((noreturn)) void exit_failure(void)
39 if (getpid() == 1) {
40 sync();
41 reboot(RB_POWER_OFF);
42 fprintf(stderr, "%s (%05d): ERROR: cannot reboot: %s\n",
43 argv0, gettid(), strerror(errno));
44 abort();
45 } else {
46 exit(1);
50 static __attribute__((noreturn)) void exit_success(void)
52 if (getpid() == 1) {
53 sync();
54 reboot(RB_POWER_OFF);
55 fprintf(stderr, "%s (%05d): ERROR: cannot reboot: %s\n",
56 argv0, gettid(), strerror(errno));
57 abort();
58 } else {
59 exit(0);
63 static int get_command_arg_str(const char *name,
64 char **val)
66 static char line[1024];
67 FILE *fp = fopen("/proc/cmdline", "r");
68 char *start, *end;
70 if (fp == NULL) {
71 fprintf(stderr, "%s (%05d): ERROR: cannot open /proc/cmdline: %s\n",
72 argv0, gettid(), strerror(errno));
73 return -1;
76 if (!fgets(line, sizeof line, fp)) {
77 fprintf(stderr, "%s (%05d): ERROR: cannot read /proc/cmdline: %s\n",
78 argv0, gettid(), strerror(errno));
79 fclose(fp);
80 return -1;
82 fclose(fp);
84 start = strstr(line, name);
85 if (!start)
86 return 0;
88 start += strlen(name);
90 if (*start != '=') {
91 fprintf(stderr, "%s (%05d): ERROR: no value provided for '%s' in /proc/cmdline\n",
92 argv0, gettid(), name);
94 start++;
96 end = strstr(start, " ");
97 if (!end)
98 end = strstr(start, "\n");
100 if (end == start) {
101 fprintf(stderr, "%s (%05d): ERROR: no value provided for '%s' in /proc/cmdline\n",
102 argv0, gettid(), name);
103 return -1;
106 if (end)
107 *val = g_strndup(start, end - start);
108 else
109 *val = g_strdup(start);
110 return 1;
114 static int get_command_arg_ull(const char *name,
115 unsigned long long *val)
117 char *valstr;
118 char *end;
120 int ret = get_command_arg_str(name, &valstr);
121 if (ret <= 0)
122 return ret;
124 errno = 0;
125 *val = strtoll(valstr, &end, 10);
126 if (errno || *end) {
127 fprintf(stderr, "%s (%05d): ERROR: cannot parse %s value %s\n",
128 argv0, gettid(), name, valstr);
129 g_free(valstr);
130 return -1;
132 g_free(valstr);
133 return 0;
137 static int random_bytes(char *buf, size_t len)
139 int fd;
141 fd = open("/dev/urandom", O_RDONLY);
142 if (fd < 0) {
143 fprintf(stderr, "%s (%05d): ERROR: cannot open /dev/urandom: %s\n",
144 argv0, gettid(), strerror(errno));
145 return -1;
148 if (read(fd, buf, len) != len) {
149 fprintf(stderr, "%s (%05d): ERROR: cannot read /dev/urandom: %s\n",
150 argv0, gettid(), strerror(errno));
151 close(fd);
152 return -1;
155 close(fd);
157 return 0;
161 static unsigned long long now(void)
163 struct timeval tv;
165 gettimeofday(&tv, NULL);
167 return (tv.tv_sec * 1000ull) + (tv.tv_usec / 1000ull);
170 static void stressone(unsigned long long ramsizeMB)
172 size_t pagesPerMB = 1024 * 1024 / PAGE_SIZE;
173 g_autofree char *ram = g_malloc(ramsizeMB * 1024 * 1024);
174 char *ramptr;
175 size_t i, j, k;
176 g_autofree char *data = g_malloc(PAGE_SIZE);
177 char *dataptr;
178 size_t nMB = 0;
179 unsigned long long before, after;
181 /* We don't care about initial state, but we do want
182 * to fault it all into RAM, otherwise the first iter
183 * of the loop below will be quite slow. We can't use
184 * 0x0 as the byte as gcc optimizes that away into a
185 * calloc instead :-) */
186 memset(ram, 0xfe, ramsizeMB * 1024 * 1024);
188 if (random_bytes(data, PAGE_SIZE) < 0) {
189 return;
192 before = now();
194 while (1) {
196 ramptr = ram;
197 for (i = 0; i < ramsizeMB; i++, nMB++) {
198 for (j = 0; j < pagesPerMB; j++) {
199 dataptr = data;
200 for (k = 0; k < PAGE_SIZE; k += sizeof(long long)) {
201 ramptr += sizeof(long long);
202 dataptr += sizeof(long long);
203 *(unsigned long long *)ramptr ^= *(unsigned long long *)dataptr;
207 if (nMB == 1024) {
208 after = now();
209 fprintf(stderr, "%s (%05d): INFO: %06llums copied 1 GB in %05llums\n",
210 argv0, gettid(), after, after - before);
211 before = now();
212 nMB = 0;
219 static void *stressthread(void *arg)
221 unsigned long long ramsizeMB = *(unsigned long long *)arg;
223 stressone(ramsizeMB);
225 return NULL;
228 static void stress(unsigned long long ramsizeGB, int ncpus)
230 size_t i;
231 unsigned long long ramsizeMB = ramsizeGB * 1024 / ncpus;
232 ncpus--;
234 for (i = 0; i < ncpus; i++) {
235 pthread_t thr;
236 pthread_create(&thr, NULL,
237 stressthread, &ramsizeMB);
240 stressone(ramsizeMB);
244 static int mount_misc(const char *fstype, const char *dir)
246 if (mkdir(dir, 0755) < 0 && errno != EEXIST) {
247 fprintf(stderr, "%s (%05d): ERROR: cannot create %s: %s\n",
248 argv0, gettid(), dir, strerror(errno));
249 return -1;
252 if (mount("none", dir, fstype, 0, NULL) < 0) {
253 fprintf(stderr, "%s (%05d): ERROR: cannot mount %s: %s\n",
254 argv0, gettid(), dir, strerror(errno));
255 return -1;
258 return 0;
261 static int mount_all(void)
263 if (mount_misc("proc", "/proc") < 0 ||
264 mount_misc("sysfs", "/sys") < 0 ||
265 mount_misc("tmpfs", "/dev") < 0)
266 return -1;
268 mknod("/dev/urandom", 0777 | S_IFCHR, makedev(1, 9));
269 mknod("/dev/random", 0777 | S_IFCHR, makedev(1, 8));
271 return 0;
274 int main(int argc, char **argv)
276 unsigned long long ramsizeGB = 1;
277 char *end;
278 int ch;
279 int opt_ind = 0;
280 const char *sopt = "hr:c:";
281 struct option lopt[] = {
282 { "help", no_argument, NULL, 'h' },
283 { "ramsize", required_argument, NULL, 'r' },
284 { "cpus", required_argument, NULL, 'c' },
285 { NULL, 0, NULL, 0 }
287 int ret;
288 int ncpus = 0;
290 argv0 = argv[0];
292 while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
293 switch (ch) {
294 case 'r':
295 errno = 0;
296 ramsizeGB = strtoll(optarg, &end, 10);
297 if (errno != 0 || *end) {
298 fprintf(stderr, "%s (%05d): ERROR: Cannot parse RAM size %s\n",
299 argv0, gettid(), optarg);
300 exit_failure();
302 break;
304 case 'c':
305 errno = 0;
306 ncpus = strtoll(optarg, &end, 10);
307 if (errno != 0 || *end) {
308 fprintf(stderr, "%s (%05d): ERROR: Cannot parse CPU count %s\n",
309 argv0, gettid(), optarg);
310 exit_failure();
312 break;
314 case '?':
315 case 'h':
316 fprintf(stderr, "%s: [--help][--ramsize GB][--cpus N]\n", argv0);
317 exit_failure();
321 if (getpid() == 1) {
322 if (mount_all() < 0)
323 exit_failure();
325 ret = get_command_arg_ull("ramsize", &ramsizeGB);
326 if (ret < 0)
327 exit_failure();
330 if (ncpus == 0)
331 ncpus = sysconf(_SC_NPROCESSORS_ONLN);
333 fprintf(stdout, "%s (%05d): INFO: RAM %llu GiB across %d CPUs\n",
334 argv0, gettid(), ramsizeGB, ncpus);
336 stress(ramsizeGB, ncpus);
338 exit_failure();