cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

stress.c (8314B)


      1/*
      2 * Migration stress workload
      3 *
      4 * Copyright (c) 2016 Red Hat, Inc.
      5 *
      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.1 of the License, or (at your option) any later version.
     10 *
     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.
     15 *
     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/>.
     18 */
     19
     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>
     27
     28const char *argv0;
     29
     30#define RAM_PAGE_SIZE 4096
     31
     32#ifndef CONFIG_GETTID
     33static int gettid(void)
     34{
     35    return syscall(SYS_gettid);
     36}
     37#endif
     38
     39static __attribute__((noreturn)) void exit_failure(void)
     40{
     41    if (getpid() == 1) {
     42        sync();
     43        reboot(RB_POWER_OFF);
     44        fprintf(stderr, "%s (%05d): ERROR: cannot reboot: %s\n",
     45                argv0, gettid(), strerror(errno));
     46        abort();
     47    } else {
     48        exit(1);
     49    }
     50}
     51
     52static int get_command_arg_str(const char *name,
     53                               char **val)
     54{
     55    static char line[1024];
     56    FILE *fp = fopen("/proc/cmdline", "r");
     57    char *start, *end;
     58
     59    if (fp == NULL) {
     60        fprintf(stderr, "%s (%05d): ERROR: cannot open /proc/cmdline: %s\n",
     61                argv0, gettid(), strerror(errno));
     62        return -1;
     63    }
     64
     65    if (!fgets(line, sizeof line, fp)) {
     66        fprintf(stderr, "%s (%05d): ERROR: cannot read /proc/cmdline: %s\n",
     67                argv0, gettid(), strerror(errno));
     68        fclose(fp);
     69        return -1;
     70    }
     71    fclose(fp);
     72
     73    start = strstr(line, name);
     74    if (!start)
     75        return 0;
     76
     77    start += strlen(name);
     78
     79    if (*start != '=') {
     80        fprintf(stderr, "%s (%05d): ERROR: no value provided for '%s' in /proc/cmdline\n",
     81                argv0, gettid(), name);
     82    }
     83    start++;
     84
     85    end = strstr(start, " ");
     86    if (!end)
     87        end = strstr(start, "\n");
     88
     89    if (end == start) {
     90        fprintf(stderr, "%s (%05d): ERROR: no value provided for '%s' in /proc/cmdline\n",
     91                argv0, gettid(), name);
     92        return -1;
     93    }
     94
     95    if (end)
     96        *val = g_strndup(start, end - start);
     97    else
     98        *val = g_strdup(start);
     99    return 1;
    100}
    101
    102
    103static int get_command_arg_ull(const char *name,
    104                               unsigned long long *val)
    105{
    106    char *valstr;
    107    char *end;
    108
    109    int ret = get_command_arg_str(name, &valstr);
    110    if (ret <= 0)
    111        return ret;
    112
    113    errno = 0;
    114    *val = strtoll(valstr, &end, 10);
    115    if (errno || *end) {
    116        fprintf(stderr, "%s (%05d): ERROR: cannot parse %s value %s\n",
    117                argv0, gettid(), name, valstr);
    118        g_free(valstr);
    119        return -1;
    120    }
    121    g_free(valstr);
    122    return 0;
    123}
    124
    125
    126static int random_bytes(char *buf, size_t len)
    127{
    128    int fd;
    129
    130    fd = open("/dev/urandom", O_RDONLY);
    131    if (fd < 0) {
    132        fprintf(stderr, "%s (%05d): ERROR: cannot open /dev/urandom: %s\n",
    133                argv0, gettid(), strerror(errno));
    134        return -1;
    135    }
    136
    137    if (read(fd, buf, len) != len) {
    138        fprintf(stderr, "%s (%05d): ERROR: cannot read /dev/urandom: %s\n",
    139                argv0, gettid(), strerror(errno));
    140        close(fd);
    141        return -1;
    142    }
    143
    144    close(fd);
    145
    146    return 0;
    147}
    148
    149
    150static unsigned long long now(void)
    151{
    152    struct timeval tv;
    153
    154    gettimeofday(&tv, NULL);
    155
    156    return (tv.tv_sec * 1000ull) + (tv.tv_usec / 1000ull);
    157}
    158
    159static void stressone(unsigned long long ramsizeMB)
    160{
    161    size_t pagesPerMB = 1024 * 1024 / RAM_PAGE_SIZE;
    162    g_autofree char *ram = g_malloc(ramsizeMB * 1024 * 1024);
    163    char *ramptr;
    164    size_t i, j, k;
    165    g_autofree char *data = g_malloc(RAM_PAGE_SIZE);
    166    char *dataptr;
    167    size_t nMB = 0;
    168    unsigned long long before, after;
    169
    170    /* We don't care about initial state, but we do want
    171     * to fault it all into RAM, otherwise the first iter
    172     * of the loop below will be quite slow. We can't use
    173     * 0x0 as the byte as gcc optimizes that away into a
    174     * calloc instead :-) */
    175    memset(ram, 0xfe, ramsizeMB * 1024 * 1024);
    176
    177    if (random_bytes(data, RAM_PAGE_SIZE) < 0) {
    178        return;
    179    }
    180
    181    before = now();
    182
    183    while (1) {
    184
    185        ramptr = ram;
    186        for (i = 0; i < ramsizeMB; i++, nMB++) {
    187            for (j = 0; j < pagesPerMB; j++) {
    188                dataptr = data;
    189                for (k = 0; k < RAM_PAGE_SIZE; k += sizeof(long long)) {
    190                    ramptr += sizeof(long long);
    191                    dataptr += sizeof(long long);
    192                    *(unsigned long long *)ramptr ^= *(unsigned long long *)dataptr;
    193                }
    194            }
    195
    196            if (nMB == 1024) {
    197                after = now();
    198                fprintf(stderr, "%s (%05d): INFO: %06llums copied 1 GB in %05llums\n",
    199                        argv0, gettid(), after, after - before);
    200                before = now();
    201                nMB = 0;
    202            }
    203        }
    204    }
    205}
    206
    207
    208static void *stressthread(void *arg)
    209{
    210    unsigned long long ramsizeMB = *(unsigned long long *)arg;
    211
    212    stressone(ramsizeMB);
    213
    214    return NULL;
    215}
    216
    217static void stress(unsigned long long ramsizeGB, int ncpus)
    218{
    219    size_t i;
    220    unsigned long long ramsizeMB = ramsizeGB * 1024 / ncpus;
    221    ncpus--;
    222
    223    for (i = 0; i < ncpus; i++) {
    224        pthread_t thr;
    225        pthread_create(&thr, NULL,
    226                       stressthread,   &ramsizeMB);
    227    }
    228
    229    stressone(ramsizeMB);
    230}
    231
    232
    233static int mount_misc(const char *fstype, const char *dir)
    234{
    235    if (mkdir(dir, 0755) < 0 && errno != EEXIST) {
    236        fprintf(stderr, "%s (%05d): ERROR: cannot create %s: %s\n",
    237                argv0, gettid(), dir, strerror(errno));
    238        return -1;
    239    }
    240
    241    if (mount("none", dir, fstype, 0, NULL) < 0) {
    242        fprintf(stderr, "%s (%05d): ERROR: cannot mount %s: %s\n",
    243                argv0, gettid(), dir, strerror(errno));
    244        return -1;
    245    }
    246
    247    return 0;
    248}
    249
    250static int mount_all(void)
    251{
    252    if (mount_misc("proc", "/proc") < 0 ||
    253        mount_misc("sysfs", "/sys") < 0 ||
    254        mount_misc("tmpfs", "/dev") < 0)
    255        return -1;
    256
    257    mknod("/dev/urandom", 0777 | S_IFCHR, makedev(1, 9));
    258    mknod("/dev/random", 0777 | S_IFCHR, makedev(1, 8));
    259
    260    return 0;
    261}
    262
    263int main(int argc, char **argv)
    264{
    265    unsigned long long ramsizeGB = 1;
    266    char *end;
    267    int ch;
    268    int opt_ind = 0;
    269    const char *sopt = "hr:c:";
    270    struct option lopt[] = {
    271        { "help", no_argument, NULL, 'h' },
    272        { "ramsize", required_argument, NULL, 'r' },
    273        { "cpus", required_argument, NULL, 'c' },
    274        { NULL, 0, NULL, 0 }
    275    };
    276    int ret;
    277    int ncpus = 0;
    278
    279    argv0 = argv[0];
    280
    281    while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
    282        switch (ch) {
    283        case 'r':
    284            errno = 0;
    285            ramsizeGB = strtoll(optarg, &end, 10);
    286            if (errno != 0 || *end) {
    287                fprintf(stderr, "%s (%05d): ERROR: Cannot parse RAM size %s\n",
    288                        argv0, gettid(), optarg);
    289                exit_failure();
    290            }
    291            break;
    292
    293        case 'c':
    294            errno = 0;
    295            ncpus = strtoll(optarg, &end, 10);
    296            if (errno != 0 || *end) {
    297                fprintf(stderr, "%s (%05d): ERROR: Cannot parse CPU count %s\n",
    298                        argv0, gettid(), optarg);
    299                exit_failure();
    300            }
    301            break;
    302
    303        case '?':
    304        case 'h':
    305            fprintf(stderr, "%s: [--help][--ramsize GB][--cpus N]\n", argv0);
    306            exit_failure();
    307        }
    308    }
    309
    310    if (getpid() == 1) {
    311        if (mount_all() < 0)
    312            exit_failure();
    313
    314        ret = get_command_arg_ull("ramsize", &ramsizeGB);
    315        if (ret < 0)
    316            exit_failure();
    317    }
    318
    319    if (ncpus == 0)
    320        ncpus = sysconf(_SC_NPROCESSORS_ONLN);
    321
    322    fprintf(stdout, "%s (%05d): INFO: RAM %llu GiB across %d CPUs\n",
    323            argv0, gettid(), ramsizeGB, ncpus);
    324
    325    stress(ramsizeGB, ncpus);
    326
    327    exit_failure();
    328}