1409437e1SDaniel P. Berrange /* 2409437e1SDaniel P. Berrange * Migration stress workload 3409437e1SDaniel P. Berrange * 4409437e1SDaniel P. Berrange * Copyright (c) 2016 Red Hat, Inc. 5409437e1SDaniel P. Berrange * 6409437e1SDaniel P. Berrange * This library is free software; you can redistribute it and/or 7409437e1SDaniel P. Berrange * modify it under the terms of the GNU Lesser General Public 8409437e1SDaniel P. Berrange * License as published by the Free Software Foundation; either 93a645d36SGan Qixin * version 2.1 of the License, or (at your option) any later version. 10409437e1SDaniel P. Berrange * 11409437e1SDaniel P. Berrange * This library is distributed in the hope that it will be useful, 12409437e1SDaniel P. Berrange * but WITHOUT ANY WARRANTY; without even the implied warranty of 13409437e1SDaniel P. Berrange * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14409437e1SDaniel P. Berrange * Lesser General Public License for more details. 15409437e1SDaniel P. Berrange * 16409437e1SDaniel P. Berrange * You should have received a copy of the GNU Lesser General Public 17409437e1SDaniel P. Berrange * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18409437e1SDaniel P. Berrange */ 19409437e1SDaniel P. Berrange 208f0a3716SMarkus Armbruster #include "qemu/osdep.h" 21409437e1SDaniel P. Berrange #include <getopt.h> 22409437e1SDaniel P. Berrange #include <sys/reboot.h> 23409437e1SDaniel P. Berrange #include <sys/syscall.h> 24409437e1SDaniel P. Berrange #include <linux/random.h> 25409437e1SDaniel P. Berrange #include <pthread.h> 26409437e1SDaniel P. Berrange #include <sys/mount.h> 27409437e1SDaniel P. Berrange 28409437e1SDaniel P. Berrange const char *argv0; 29409437e1SDaniel P. Berrange 30d2c4f384SJiaxun Yang #define RAM_PAGE_SIZE 4096 31409437e1SDaniel P. Berrange 323909def8SMarc-André Lureau #ifndef CONFIG_GETTID 33409437e1SDaniel P. Berrange static int gettid(void) 34409437e1SDaniel P. Berrange { 35409437e1SDaniel P. Berrange return syscall(SYS_gettid); 36409437e1SDaniel P. Berrange } 373909def8SMarc-André Lureau #endif 38409437e1SDaniel P. Berrange 39409437e1SDaniel P. Berrange static __attribute__((noreturn)) void exit_failure(void) 40409437e1SDaniel P. Berrange { 41409437e1SDaniel P. Berrange if (getpid() == 1) { 42409437e1SDaniel P. Berrange sync(); 43409437e1SDaniel P. Berrange reboot(RB_POWER_OFF); 44409437e1SDaniel P. Berrange fprintf(stderr, "%s (%05d): ERROR: cannot reboot: %s\n", 45409437e1SDaniel P. Berrange argv0, gettid(), strerror(errno)); 46409437e1SDaniel P. Berrange abort(); 47409437e1SDaniel P. Berrange } else { 48409437e1SDaniel P. Berrange exit(1); 49409437e1SDaniel P. Berrange } 50409437e1SDaniel P. Berrange } 51409437e1SDaniel P. Berrange 52409437e1SDaniel P. Berrange static int get_command_arg_str(const char *name, 53409437e1SDaniel P. Berrange char **val) 54409437e1SDaniel P. Berrange { 55409437e1SDaniel P. Berrange static char line[1024]; 56409437e1SDaniel P. Berrange FILE *fp = fopen("/proc/cmdline", "r"); 57409437e1SDaniel P. Berrange char *start, *end; 58409437e1SDaniel P. Berrange 59409437e1SDaniel P. Berrange if (fp == NULL) { 60409437e1SDaniel P. Berrange fprintf(stderr, "%s (%05d): ERROR: cannot open /proc/cmdline: %s\n", 61409437e1SDaniel P. Berrange argv0, gettid(), strerror(errno)); 62409437e1SDaniel P. Berrange return -1; 63409437e1SDaniel P. Berrange } 64409437e1SDaniel P. Berrange 65409437e1SDaniel P. Berrange if (!fgets(line, sizeof line, fp)) { 66409437e1SDaniel P. Berrange fprintf(stderr, "%s (%05d): ERROR: cannot read /proc/cmdline: %s\n", 67409437e1SDaniel P. Berrange argv0, gettid(), strerror(errno)); 68409437e1SDaniel P. Berrange fclose(fp); 69409437e1SDaniel P. Berrange return -1; 70409437e1SDaniel P. Berrange } 71409437e1SDaniel P. Berrange fclose(fp); 72409437e1SDaniel P. Berrange 73409437e1SDaniel P. Berrange start = strstr(line, name); 74409437e1SDaniel P. Berrange if (!start) 75409437e1SDaniel P. Berrange return 0; 76409437e1SDaniel P. Berrange 77409437e1SDaniel P. Berrange start += strlen(name); 78409437e1SDaniel P. Berrange 79409437e1SDaniel P. Berrange if (*start != '=') { 80409437e1SDaniel P. Berrange fprintf(stderr, "%s (%05d): ERROR: no value provided for '%s' in /proc/cmdline\n", 81409437e1SDaniel P. Berrange argv0, gettid(), name); 82409437e1SDaniel P. Berrange } 83409437e1SDaniel P. Berrange start++; 84409437e1SDaniel P. Berrange 85409437e1SDaniel P. Berrange end = strstr(start, " "); 86409437e1SDaniel P. Berrange if (!end) 87409437e1SDaniel P. Berrange end = strstr(start, "\n"); 88409437e1SDaniel P. Berrange 89409437e1SDaniel P. Berrange if (end == start) { 90409437e1SDaniel P. Berrange fprintf(stderr, "%s (%05d): ERROR: no value provided for '%s' in /proc/cmdline\n", 91409437e1SDaniel P. Berrange argv0, gettid(), name); 92409437e1SDaniel P. Berrange return -1; 93409437e1SDaniel P. Berrange } 94409437e1SDaniel P. Berrange 95409437e1SDaniel P. Berrange if (end) 96348fbd58Stony.nguyen@bt.com *val = g_strndup(start, end - start); 97409437e1SDaniel P. Berrange else 98348fbd58Stony.nguyen@bt.com *val = g_strdup(start); 99409437e1SDaniel P. Berrange return 1; 100409437e1SDaniel P. Berrange } 101409437e1SDaniel P. Berrange 102409437e1SDaniel P. Berrange 103409437e1SDaniel P. Berrange static int get_command_arg_ull(const char *name, 104409437e1SDaniel P. Berrange unsigned long long *val) 105409437e1SDaniel P. Berrange { 106409437e1SDaniel P. Berrange char *valstr; 107409437e1SDaniel P. Berrange char *end; 108409437e1SDaniel P. Berrange 109409437e1SDaniel P. Berrange int ret = get_command_arg_str(name, &valstr); 110409437e1SDaniel P. Berrange if (ret <= 0) 111409437e1SDaniel P. Berrange return ret; 112409437e1SDaniel P. Berrange 113409437e1SDaniel P. Berrange errno = 0; 114409437e1SDaniel P. Berrange *val = strtoll(valstr, &end, 10); 115409437e1SDaniel P. Berrange if (errno || *end) { 116409437e1SDaniel P. Berrange fprintf(stderr, "%s (%05d): ERROR: cannot parse %s value %s\n", 117409437e1SDaniel P. Berrange argv0, gettid(), name, valstr); 118348fbd58Stony.nguyen@bt.com g_free(valstr); 119409437e1SDaniel P. Berrange return -1; 120409437e1SDaniel P. Berrange } 121348fbd58Stony.nguyen@bt.com g_free(valstr); 122409437e1SDaniel P. Berrange return 0; 123409437e1SDaniel P. Berrange } 124409437e1SDaniel P. Berrange 125409437e1SDaniel P. Berrange 126409437e1SDaniel P. Berrange static int random_bytes(char *buf, size_t len) 127409437e1SDaniel P. Berrange { 128409437e1SDaniel P. Berrange int fd; 129409437e1SDaniel P. Berrange 130409437e1SDaniel P. Berrange fd = open("/dev/urandom", O_RDONLY); 131409437e1SDaniel P. Berrange if (fd < 0) { 132409437e1SDaniel P. Berrange fprintf(stderr, "%s (%05d): ERROR: cannot open /dev/urandom: %s\n", 133409437e1SDaniel P. Berrange argv0, gettid(), strerror(errno)); 134409437e1SDaniel P. Berrange return -1; 135409437e1SDaniel P. Berrange } 136409437e1SDaniel P. Berrange 137409437e1SDaniel P. Berrange if (read(fd, buf, len) != len) { 138409437e1SDaniel P. Berrange fprintf(stderr, "%s (%05d): ERROR: cannot read /dev/urandom: %s\n", 139409437e1SDaniel P. Berrange argv0, gettid(), strerror(errno)); 140409437e1SDaniel P. Berrange close(fd); 141409437e1SDaniel P. Berrange return -1; 142409437e1SDaniel P. Berrange } 143409437e1SDaniel P. Berrange 144409437e1SDaniel P. Berrange close(fd); 145409437e1SDaniel P. Berrange 146409437e1SDaniel P. Berrange return 0; 147409437e1SDaniel P. Berrange } 148409437e1SDaniel P. Berrange 149409437e1SDaniel P. Berrange 150409437e1SDaniel P. Berrange static unsigned long long now(void) 151409437e1SDaniel P. Berrange { 152409437e1SDaniel P. Berrange struct timeval tv; 153409437e1SDaniel P. Berrange 154409437e1SDaniel P. Berrange gettimeofday(&tv, NULL); 155409437e1SDaniel P. Berrange 156409437e1SDaniel P. Berrange return (tv.tv_sec * 1000ull) + (tv.tv_usec / 1000ull); 157409437e1SDaniel P. Berrange } 158409437e1SDaniel P. Berrange 15971cfce73SMao Zhongyi static void stressone(unsigned long long ramsizeMB) 160409437e1SDaniel P. Berrange { 161d2c4f384SJiaxun Yang size_t pagesPerMB = 1024 * 1024 / RAM_PAGE_SIZE; 162f663492fSMao Zhongyi g_autofree char *ram = g_malloc(ramsizeMB * 1024 * 1024); 163409437e1SDaniel P. Berrange char *ramptr; 164409437e1SDaniel P. Berrange size_t i, j, k; 165d2c4f384SJiaxun Yang g_autofree char *data = g_malloc(RAM_PAGE_SIZE); 166409437e1SDaniel P. Berrange char *dataptr; 167409437e1SDaniel P. Berrange size_t nMB = 0; 168409437e1SDaniel P. Berrange unsigned long long before, after; 169409437e1SDaniel P. Berrange 170409437e1SDaniel P. Berrange /* We don't care about initial state, but we do want 171409437e1SDaniel P. Berrange * to fault it all into RAM, otherwise the first iter 17281864c2eSMao Zhongyi * of the loop below will be quite slow. We can't use 173409437e1SDaniel P. Berrange * 0x0 as the byte as gcc optimizes that away into a 174409437e1SDaniel P. Berrange * calloc instead :-) */ 175409437e1SDaniel P. Berrange memset(ram, 0xfe, ramsizeMB * 1024 * 1024); 176409437e1SDaniel P. Berrange 177d2c4f384SJiaxun Yang if (random_bytes(data, RAM_PAGE_SIZE) < 0) { 17871cfce73SMao Zhongyi return; 179409437e1SDaniel P. Berrange } 180409437e1SDaniel P. Berrange 181409437e1SDaniel P. Berrange before = now(); 182409437e1SDaniel P. Berrange 183409437e1SDaniel P. Berrange while (1) { 184409437e1SDaniel P. Berrange 185409437e1SDaniel P. Berrange ramptr = ram; 186409437e1SDaniel P. Berrange for (i = 0; i < ramsizeMB; i++, nMB++) { 187409437e1SDaniel P. Berrange for (j = 0; j < pagesPerMB; j++) { 188409437e1SDaniel P. Berrange dataptr = data; 189d2c4f384SJiaxun Yang for (k = 0; k < RAM_PAGE_SIZE; k += sizeof(long long)) { 190409437e1SDaniel P. Berrange ramptr += sizeof(long long); 191409437e1SDaniel P. Berrange dataptr += sizeof(long long); 192409437e1SDaniel P. Berrange *(unsigned long long *)ramptr ^= *(unsigned long long *)dataptr; 193409437e1SDaniel P. Berrange } 194409437e1SDaniel P. Berrange } 195409437e1SDaniel P. Berrange 196409437e1SDaniel P. Berrange if (nMB == 1024) { 197409437e1SDaniel P. Berrange after = now(); 198409437e1SDaniel P. Berrange fprintf(stderr, "%s (%05d): INFO: %06llums copied 1 GB in %05llums\n", 199409437e1SDaniel P. Berrange argv0, gettid(), after, after - before); 200409437e1SDaniel P. Berrange before = now(); 201409437e1SDaniel P. Berrange nMB = 0; 202409437e1SDaniel P. Berrange } 203409437e1SDaniel P. Berrange } 204409437e1SDaniel P. Berrange } 205409437e1SDaniel P. Berrange } 206409437e1SDaniel P. Berrange 207409437e1SDaniel P. Berrange 208409437e1SDaniel P. Berrange static void *stressthread(void *arg) 209409437e1SDaniel P. Berrange { 210409437e1SDaniel P. Berrange unsigned long long ramsizeMB = *(unsigned long long *)arg; 211409437e1SDaniel P. Berrange 212409437e1SDaniel P. Berrange stressone(ramsizeMB); 213409437e1SDaniel P. Berrange 214409437e1SDaniel P. Berrange return NULL; 215409437e1SDaniel P. Berrange } 216409437e1SDaniel P. Berrange 21771cfce73SMao Zhongyi static void stress(unsigned long long ramsizeGB, int ncpus) 218409437e1SDaniel P. Berrange { 219409437e1SDaniel P. Berrange size_t i; 220409437e1SDaniel P. Berrange unsigned long long ramsizeMB = ramsizeGB * 1024 / ncpus; 221409437e1SDaniel P. Berrange ncpus--; 222409437e1SDaniel P. Berrange 223409437e1SDaniel P. Berrange for (i = 0; i < ncpus; i++) { 224409437e1SDaniel P. Berrange pthread_t thr; 225409437e1SDaniel P. Berrange pthread_create(&thr, NULL, 226409437e1SDaniel P. Berrange stressthread, &ramsizeMB); 227409437e1SDaniel P. Berrange } 228409437e1SDaniel P. Berrange 229409437e1SDaniel P. Berrange stressone(ramsizeMB); 230409437e1SDaniel P. Berrange } 231409437e1SDaniel P. Berrange 232409437e1SDaniel P. Berrange 233409437e1SDaniel P. Berrange static int mount_misc(const char *fstype, const char *dir) 234409437e1SDaniel P. Berrange { 235*413bebc0SBin Meng if (g_mkdir_with_parents(dir, 0755) < 0 && errno != EEXIST) { 236409437e1SDaniel P. Berrange fprintf(stderr, "%s (%05d): ERROR: cannot create %s: %s\n", 237409437e1SDaniel P. Berrange argv0, gettid(), dir, strerror(errno)); 238409437e1SDaniel P. Berrange return -1; 239409437e1SDaniel P. Berrange } 240409437e1SDaniel P. Berrange 241409437e1SDaniel P. Berrange if (mount("none", dir, fstype, 0, NULL) < 0) { 242409437e1SDaniel P. Berrange fprintf(stderr, "%s (%05d): ERROR: cannot mount %s: %s\n", 243409437e1SDaniel P. Berrange argv0, gettid(), dir, strerror(errno)); 244409437e1SDaniel P. Berrange return -1; 245409437e1SDaniel P. Berrange } 246409437e1SDaniel P. Berrange 247409437e1SDaniel P. Berrange return 0; 248409437e1SDaniel P. Berrange } 249409437e1SDaniel P. Berrange 250409437e1SDaniel P. Berrange static int mount_all(void) 251409437e1SDaniel P. Berrange { 252409437e1SDaniel P. Berrange if (mount_misc("proc", "/proc") < 0 || 253409437e1SDaniel P. Berrange mount_misc("sysfs", "/sys") < 0 || 254409437e1SDaniel P. Berrange mount_misc("tmpfs", "/dev") < 0) 255409437e1SDaniel P. Berrange return -1; 256409437e1SDaniel P. Berrange 257409437e1SDaniel P. Berrange mknod("/dev/urandom", 0777 | S_IFCHR, makedev(1, 9)); 258409437e1SDaniel P. Berrange mknod("/dev/random", 0777 | S_IFCHR, makedev(1, 8)); 259409437e1SDaniel P. Berrange 260409437e1SDaniel P. Berrange return 0; 261409437e1SDaniel P. Berrange } 262409437e1SDaniel P. Berrange 263409437e1SDaniel P. Berrange int main(int argc, char **argv) 264409437e1SDaniel P. Berrange { 265409437e1SDaniel P. Berrange unsigned long long ramsizeGB = 1; 266409437e1SDaniel P. Berrange char *end; 267409437e1SDaniel P. Berrange int ch; 268409437e1SDaniel P. Berrange int opt_ind = 0; 269409437e1SDaniel P. Berrange const char *sopt = "hr:c:"; 270409437e1SDaniel P. Berrange struct option lopt[] = { 271409437e1SDaniel P. Berrange { "help", no_argument, NULL, 'h' }, 272409437e1SDaniel P. Berrange { "ramsize", required_argument, NULL, 'r' }, 273409437e1SDaniel P. Berrange { "cpus", required_argument, NULL, 'c' }, 274409437e1SDaniel P. Berrange { NULL, 0, NULL, 0 } 275409437e1SDaniel P. Berrange }; 276409437e1SDaniel P. Berrange int ret; 277409437e1SDaniel P. Berrange int ncpus = 0; 278409437e1SDaniel P. Berrange 279409437e1SDaniel P. Berrange argv0 = argv[0]; 280409437e1SDaniel P. Berrange 281409437e1SDaniel P. Berrange while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) { 282409437e1SDaniel P. Berrange switch (ch) { 283409437e1SDaniel P. Berrange case 'r': 284409437e1SDaniel P. Berrange errno = 0; 285409437e1SDaniel P. Berrange ramsizeGB = strtoll(optarg, &end, 10); 286409437e1SDaniel P. Berrange if (errno != 0 || *end) { 287409437e1SDaniel P. Berrange fprintf(stderr, "%s (%05d): ERROR: Cannot parse RAM size %s\n", 288409437e1SDaniel P. Berrange argv0, gettid(), optarg); 289409437e1SDaniel P. Berrange exit_failure(); 290409437e1SDaniel P. Berrange } 291409437e1SDaniel P. Berrange break; 292409437e1SDaniel P. Berrange 293409437e1SDaniel P. Berrange case 'c': 294409437e1SDaniel P. Berrange errno = 0; 295409437e1SDaniel P. Berrange ncpus = strtoll(optarg, &end, 10); 296409437e1SDaniel P. Berrange if (errno != 0 || *end) { 297409437e1SDaniel P. Berrange fprintf(stderr, "%s (%05d): ERROR: Cannot parse CPU count %s\n", 298409437e1SDaniel P. Berrange argv0, gettid(), optarg); 299409437e1SDaniel P. Berrange exit_failure(); 300409437e1SDaniel P. Berrange } 301409437e1SDaniel P. Berrange break; 302409437e1SDaniel P. Berrange 303409437e1SDaniel P. Berrange case '?': 304409437e1SDaniel P. Berrange case 'h': 305409437e1SDaniel P. Berrange fprintf(stderr, "%s: [--help][--ramsize GB][--cpus N]\n", argv0); 306409437e1SDaniel P. Berrange exit_failure(); 307409437e1SDaniel P. Berrange } 308409437e1SDaniel P. Berrange } 309409437e1SDaniel P. Berrange 310409437e1SDaniel P. Berrange if (getpid() == 1) { 311409437e1SDaniel P. Berrange if (mount_all() < 0) 312409437e1SDaniel P. Berrange exit_failure(); 313409437e1SDaniel P. Berrange 314409437e1SDaniel P. Berrange ret = get_command_arg_ull("ramsize", &ramsizeGB); 315409437e1SDaniel P. Berrange if (ret < 0) 316409437e1SDaniel P. Berrange exit_failure(); 317409437e1SDaniel P. Berrange } 318409437e1SDaniel P. Berrange 319409437e1SDaniel P. Berrange if (ncpus == 0) 320409437e1SDaniel P. Berrange ncpus = sysconf(_SC_NPROCESSORS_ONLN); 321409437e1SDaniel P. Berrange 322409437e1SDaniel P. Berrange fprintf(stdout, "%s (%05d): INFO: RAM %llu GiB across %d CPUs\n", 323409437e1SDaniel P. Berrange argv0, gettid(), ramsizeGB, ncpus); 324409437e1SDaniel P. Berrange 32571cfce73SMao Zhongyi stress(ramsizeGB, ncpus); 326409437e1SDaniel P. Berrange 32771cfce73SMao Zhongyi exit_failure(); 328409437e1SDaniel P. Berrange } 329