"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-revio.c" (15 Mar 2019, 11560 Bytes) of package /linux/privat/stress-ng-0.09.56.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "stress-revio.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.09.52_vs_0.09.54.

    1 /*
    2  * Copyright (C) 2013-2019 Canonical, Ltd.
    3  *
    4  * This program is free software; you can redistribute it and/or
    5  * modify it under the terms of the GNU General Public License
    6  * as published by the Free Software Foundation; either version 2
    7  * of the License, or (at your option) any later version.
    8  *
    9  * This program is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12  * GNU General Public License for more details.
   13  *
   14  * You should have received a copy of the GNU General Public License
   15  * along with this program; if not, write to the Free Software
   16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
   17  *
   18  * This code is a complete clean re-write of the stress tool by
   19  * Colin Ian King <colin.king@canonical.com> and attempts to be
   20  * backwardly compatible with the stress tool by Amos Waterland
   21  * <apw@rossby.metr.ou.edu> but has more stress tests and more
   22  * functionality.
   23  *
   24  */
   25 #include "stress-ng.h"
   26 
   27 #define BUF_ALIGNMENT       (4096)
   28 
   29 #define DEFAULT_REVIO_WRITE_SIZE (1024)
   30 
   31 /* POSIX fadvise modes */
   32 #define REVIO_OPT_FADV_NORMAL   (0x00000100)
   33 #define REVIO_OPT_FADV_SEQ  (0x00000200)
   34 #define REVIO_OPT_FADV_RND  (0x00000400)
   35 #define REVIO_OPT_FADV_NOREUSE  (0x00000800)
   36 #define REVIO_OPT_FADV_WILLNEED (0x00001000)
   37 #define REVIO_OPT_FADV_DONTNEED (0x00002000)
   38 #define REVIO_OPT_FADV_MASK (0x00003f00)
   39 
   40 /* Open O_* modes */
   41 #define REVIO_OPT_O_SYNC    (0x00010000)
   42 #define REVIO_OPT_O_DSYNC   (0x00020000)
   43 #define REVIO_OPT_O_DIRECT  (0x00040000)
   44 #define REVIO_OPT_O_NOATIME (0x00080000)
   45 #define REVIO_OPT_O_MASK    (0x000f0000)
   46 
   47 /* Other modes */
   48 #define REVIO_OPT_UTIMES    (0x00100000)
   49 #define REVIO_OPT_FSYNC     (0x00200000)
   50 #define REVIO_OPT_FDATASYNC (0x00400000)
   51 #define REVIO_OPT_SYNCFS    (0x00800000)
   52 
   53 typedef struct {
   54     const char *opt;    /* User option */
   55     const int flag;     /* REVIO_OPT_ flag */
   56     const int exclude;  /* Excluded REVIO_OPT_ flags */
   57     const int advice;   /* posix_fadvise value */
   58     const int oflag;    /* open O_* flags */
   59 } revio_opts_t;
   60 
   61 static const revio_opts_t revio_opts[] = {
   62 #if defined(O_SYNC)
   63     { "sync",   REVIO_OPT_O_SYNC, 0, 0, O_SYNC },
   64 #endif
   65 #if defined(O_DSYNC)
   66     { "dsync",  REVIO_OPT_O_DSYNC, 0, 0, O_DSYNC },
   67 #endif
   68 #if defined(O_DIRECT)
   69     { "direct", REVIO_OPT_O_DIRECT, 0, 0, O_DIRECT },
   70 #endif
   71 #if defined(O_NOATIME)
   72     { "noatime",    REVIO_OPT_O_NOATIME, 0, 0, O_NOATIME },
   73 #endif
   74 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_NORMAL)
   75     { "fadv-normal",REVIO_OPT_FADV_NORMAL,
   76         (REVIO_OPT_FADV_SEQ | REVIO_OPT_FADV_RND |
   77          REVIO_OPT_FADV_NOREUSE | REVIO_OPT_FADV_WILLNEED |
   78          REVIO_OPT_FADV_DONTNEED),
   79         POSIX_FADV_NORMAL, 0 },
   80 #endif
   81 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_SEQ)
   82     { "fadv-seq",   REVIO_OPT_FADV_SEQ,
   83         (REVIO_OPT_FADV_NORMAL | REVIO_OPT_FADV_RND),
   84         POSIX_FADV_SEQUENTIAL, 0 },
   85 #endif
   86 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_RANDOM)
   87     { "fadv-rnd",   REVIO_OPT_FADV_RND,
   88         (REVIO_OPT_FADV_NORMAL | REVIO_OPT_FADV_SEQ),
   89         POSIX_FADV_RANDOM, 0 },
   90 #endif
   91 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_NOREUSE)
   92     { "fadv-noreuse", REVIO_OPT_FADV_NOREUSE,
   93         REVIO_OPT_FADV_NORMAL,
   94         POSIX_FADV_NOREUSE, 0 },
   95 #endif
   96 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
   97     { "fadv-willneed", REVIO_OPT_FADV_WILLNEED,
   98         (REVIO_OPT_FADV_NORMAL | REVIO_OPT_FADV_DONTNEED),
   99         POSIX_FADV_WILLNEED, 0 },
  100 #endif
  101 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED)
  102     { "fadv-dontneed", REVIO_OPT_FADV_DONTNEED,
  103         (REVIO_OPT_FADV_NORMAL | REVIO_OPT_FADV_WILLNEED),
  104         POSIX_FADV_DONTNEED, 0 },
  105 #endif
  106 #if defined(HAVE_FSYNC)
  107     { "fsync",  REVIO_OPT_FSYNC, 0, 0, 0 },
  108 #endif
  109 #if defined(HAVE_FDATASYNC)
  110     { "fdatasync",  REVIO_OPT_FDATASYNC, 0, 0, 0 },
  111 #endif
  112 #if defined(HAVE_SYNCFS)
  113     { "syncfs", REVIO_OPT_SYNCFS, 0, 0, 0 },
  114 #endif
  115     { "utimes", REVIO_OPT_UTIMES, 0, 0, 0 },
  116 };
  117 
  118 int stress_set_revio_bytes(const char *opt)
  119 {
  120     uint64_t revio_bytes;
  121 
  122     revio_bytes = get_uint64_byte_filesystem(opt, 1);
  123     check_range_bytes("revio-bytes", revio_bytes,
  124         MIN_REVIO_BYTES, MAX_REVIO_BYTES);
  125     return set_setting("revio-bytes", TYPE_ID_UINT64, &revio_bytes);
  126 }
  127 
  128 /*
  129  *  stress_revio_write()
  130  *  write with writev or write depending on mode
  131  */
  132 static ssize_t stress_revio_write(
  133     const int fd,
  134     uint8_t *buf,
  135     const size_t count,
  136     const int revio_flags)
  137 {
  138     ssize_t ret;
  139 
  140     (void)revio_flags;
  141 
  142 #if defined(HAVE_FUTIMES)
  143     if (revio_flags & REVIO_OPT_UTIMES)
  144         (void)futimes(fd, NULL);
  145 #endif
  146 
  147     ret = write(fd, buf, count);
  148 
  149 #if defined(HAVE_FSYNC)
  150     if (revio_flags & REVIO_OPT_FSYNC)
  151         (void)shim_fsync(fd);
  152 #endif
  153 #if defined(HAVE_FDATASYNC)
  154     if (revio_flags & REVIO_OPT_FDATASYNC)
  155         (void)shim_fdatasync(fd);
  156 #endif
  157 #if defined(HAVE_SYNCFS)
  158     if (revio_flags & REVIO_OPT_SYNCFS)
  159         (void)syncfs(fd);
  160 #endif
  161 
  162     return ret;
  163 }
  164 
  165 /*
  166  *  stress_set_revio_opts
  167  *  parse --revio-opts option(s) list
  168  */
  169 int stress_set_revio_opts(const char *opts)
  170 {
  171     char *str, *ptr, *token;
  172     int revio_flags = 0;
  173     int revio_oflags = 0;
  174     bool opts_set = false;
  175 
  176     str = stress_const_optdup(opts);
  177     if (!str)
  178         return -1;
  179 
  180     for (ptr = str; (token = strtok(ptr, ",")) != NULL; ptr = NULL) {
  181         size_t i;
  182         bool opt_ok = false;
  183 
  184         for (i = 0; i < SIZEOF_ARRAY(revio_opts); i++) {
  185             if (!strcmp(token, revio_opts[i].opt)) {
  186                 int exclude = revio_flags & revio_opts[i].exclude;
  187                 if (exclude) {
  188                     int j;
  189 
  190                     for (j = 0; revio_opts[j].opt; j++) {
  191                         if ((exclude & revio_opts[j].flag) == exclude) {
  192                             (void)fprintf(stderr,
  193                                 "revio-opt option '%s' is not "
  194                                 "compatible with option '%s'\n",
  195                                 token,
  196                                 revio_opts[j].opt);
  197                             break;
  198                         }
  199                     }
  200                     free(str);
  201                     return -1;
  202                 }
  203                 revio_flags  |= revio_opts[i].flag;
  204                 revio_oflags |= revio_opts[i].oflag;
  205                 opt_ok = true;
  206                 opts_set = true;
  207             }
  208         }
  209         if (!opt_ok) {
  210             (void)fprintf(stderr, "revio-opt option '%s' not known, options are:", token);
  211             for (i = 0; i < SIZEOF_ARRAY(revio_opts); i++)
  212                 (void)fprintf(stderr, "%s %s",
  213                     i == 0 ? "" : ",", revio_opts[i].opt);
  214             (void)fprintf(stderr, "\n");
  215             free(str);
  216             return -1;
  217         }
  218     }
  219 
  220     set_setting("revio-flags", TYPE_ID_INT, &revio_flags);
  221     set_setting("revio-oflags", TYPE_ID_INT, &revio_oflags);
  222     set_setting("revio-opts-set", TYPE_ID_BOOL, &opts_set);
  223     free(str);
  224 
  225     return 0;
  226 }
  227 
  228 /*
  229  *  stress_revio_advise()
  230  *  set posix_fadvise options
  231  */
  232 static int stress_revio_advise(const args_t *args, const int fd, const int flags)
  233 {
  234 #if (defined(POSIX_FADV_SEQ) || defined(POSIX_FADV_RANDOM) || \
  235     defined(POSIX_FADV_NOREUSE) || defined(POSIX_FADV_WILLNEED) || \
  236     defined(POSIX_FADV_DONTNEED)) && defined(HAVE_POSIX_FADVISE)
  237     size_t i;
  238 
  239     if (!(flags & REVIO_OPT_FADV_MASK))
  240         return 0;
  241 
  242     for (i = 0; i < SIZEOF_ARRAY(revio_opts); i++) {
  243         if (revio_opts[i].flag & flags) {
  244             if (posix_fadvise(fd, 0, 0, revio_opts[i].advice) < 0) {
  245                 pr_fail_err("posix_fadvise");
  246                 return -1;
  247             }
  248         }
  249     }
  250 #else
  251     (void)args;
  252     (void)fd;
  253     (void)flags;
  254 #endif
  255     return 0;
  256 }
  257 
  258 static inline size_t stress_revio_get_extents(const int fd)
  259 {
  260 #if defined(FS_IOC_FIEMAP) && defined(HAVE_LINUX_FIEMAP_H)
  261     struct fiemap fiemap;
  262 
  263     (void)memset(&fiemap, 0, sizeof(fiemap));
  264     fiemap.fm_length = ~0;
  265 
  266     /* Find out how many extents there are */
  267     if (ioctl(fd, FS_IOC_FIEMAP, &fiemap) < 0)
  268         return 0;
  269 
  270     return fiemap.fm_mapped_extents;
  271 #else
  272     (void)fd;
  273 
  274     return 0;
  275 #endif
  276 }
  277 
  278 /*
  279  *  stress_revio
  280  *  stress I/O via writes in reverse
  281  */
  282 static int stress_revio(const args_t *args)
  283 {
  284     uint8_t *buf = NULL;
  285     void *alloc_buf;
  286     uint64_t i;
  287     int rc = EXIT_FAILURE;
  288     ssize_t ret;
  289     char filename[PATH_MAX];
  290     size_t opt_index = 0;
  291     uint64_t revio_bytes = DEFAULT_REVIO_BYTES;
  292     uint32_t iterations = 0;
  293     int revio_flags = 0, revio_oflags = 0;
  294     int flags, fadvise_flags;
  295     bool opts_set = false;
  296     double avg_extents = 0.0;
  297 
  298     (void)get_setting("revio-flags", &revio_flags);
  299     (void)get_setting("revio-oflags", &revio_oflags);
  300     (void)get_setting("revio-opts-set", &opts_set);
  301 
  302     revio_flags |= REVIO_OPT_O_DIRECT;  /* HACK */
  303 
  304     flags = O_CREAT | O_RDWR | O_TRUNC | revio_oflags;
  305     fadvise_flags = revio_flags & REVIO_OPT_FADV_MASK;
  306 
  307     if (!get_setting("revio-bytes", &revio_bytes)) {
  308         if (g_opt_flags & OPT_FLAGS_MAXIMIZE)
  309             revio_bytes = MAX_REVIO_BYTES;
  310         if (g_opt_flags & OPT_FLAGS_MINIMIZE)
  311             revio_bytes = MIN_REVIO_BYTES;
  312     }
  313 
  314     revio_bytes /= args->num_instances;
  315 
  316     /* Ensure complete file size is not less than the I/O size */
  317     if (revio_bytes < DEFAULT_REVIO_WRITE_SIZE) {
  318         revio_bytes = DEFAULT_REVIO_WRITE_SIZE;
  319         pr_inf("%s: increasing file size to write size of %"
  320             PRIu64 " bytes\n",
  321             args->name, revio_bytes);
  322     }
  323 
  324 
  325     ret = stress_temp_dir_mk_args(args);
  326     if (ret < 0)
  327         return exit_status(-ret);
  328 
  329 #if defined(HAVE_POSIX_MEMALIGN)
  330     ret = posix_memalign((void **)&alloc_buf, BUF_ALIGNMENT, (size_t)DEFAULT_REVIO_WRITE_SIZE);
  331     if (ret || !alloc_buf) {
  332         rc = exit_status(errno);
  333         pr_err("%s: cannot allocate buffer\n", args->name);
  334         (void)stress_temp_dir_rm_args(args);
  335         return rc;
  336     }
  337     buf = alloc_buf;
  338 #else
  339     /* Work around lack of posix_memalign */
  340     alloc_buf = malloc((size_t)DEFAULT_REVIO_WRITE_SIZE + BUF_ALIGNMENT);
  341     if (!alloc_buf) {
  342         pr_err("%s: cannot allocate buffer\n", args->name);
  343         (void)stress_temp_dir_rm_args(args);
  344         return rc;
  345     }
  346     buf = (uint8_t *)stress_align_address(alloc_buf, BUF_ALIGNMENT);
  347 #endif
  348 
  349     stress_strnrnd((char *)buf, DEFAULT_REVIO_WRITE_SIZE);
  350 
  351     (void)stress_temp_filename_args(args,
  352         filename, sizeof(filename), mwc32());
  353 
  354     do {
  355         int fd;
  356 
  357         /*
  358          * aggressive option with no other option enables
  359          * the "work through all the options" mode
  360          */
  361         if (!opts_set && (g_opt_flags & OPT_FLAGS_AGGRESSIVE)) {
  362             opt_index = (opt_index + 1) % SIZEOF_ARRAY(revio_opts);
  363 
  364             revio_flags  = revio_opts[opt_index].flag;
  365             revio_oflags = revio_opts[opt_index].oflag;
  366         }
  367 
  368         if ((fd = open(filename, flags, S_IRUSR | S_IWUSR)) < 0) {
  369             if ((errno == ENOSPC) || (errno == ENOMEM))
  370                 continue;   /* Retry */
  371             pr_fail_err("open");
  372             goto finish;
  373         }
  374         if (ftruncate(fd, (off_t)revio_bytes) < 0) {
  375             pr_fail_err("ftruncate");
  376             (void)close(fd);
  377             goto finish;
  378         }
  379         (void)unlink(filename);
  380 
  381         if (stress_revio_advise(args, fd, fadvise_flags) < 0) {
  382             (void)close(fd);
  383             goto finish;
  384         }
  385 
  386         /* Sequential Reverse Write */
  387         for (i = 0; i < revio_bytes; i += DEFAULT_REVIO_WRITE_SIZE * (8 + (mwc8() & 7))) {
  388             size_t j;
  389             off_t lseek_ret, offset = revio_bytes - i;
  390 seq_wr_retry:
  391             if (!keep_stressing())
  392                 break;
  393 
  394             lseek_ret = lseek(fd, offset, SEEK_SET);
  395             if (lseek_ret < 0) {
  396                 pr_fail_err("write");
  397                 (void)close(fd);
  398                 goto finish;
  399             }
  400 
  401             for (j = 0; j < DEFAULT_REVIO_WRITE_SIZE; j += 512)
  402                 buf[j] = (i * j) & 0xff;
  403             ret = stress_revio_write(fd, buf, (size_t)DEFAULT_REVIO_WRITE_SIZE, revio_flags);
  404             if (ret <= 0) {
  405                 if ((errno == EAGAIN) || (errno == EINTR))
  406                     goto seq_wr_retry;
  407                 if (errno == ENOSPC)
  408                     break;
  409                 if (errno) {
  410                     pr_fail_err("write");
  411                     (void)close(fd);
  412                     goto finish;
  413                 }
  414                 continue;
  415             }
  416             inc_counter(args);
  417         }
  418         iterations++;
  419         avg_extents += (double)stress_revio_get_extents(fd);
  420         (void)close(fd);
  421     } while (keep_stressing());
  422 
  423     if ((iterations > 0) && (avg_extents > 0.0)) {
  424         avg_extents /= (double)iterations;
  425         pr_inf("%s: average number of extents %.2f\n", args->name, avg_extents * args->num_instances);
  426     }
  427 
  428     rc = EXIT_SUCCESS;
  429 finish:
  430     free(alloc_buf);
  431     (void)stress_temp_dir_rm_args(args);
  432     return rc;
  433 }
  434 
  435 stressor_info_t stress_revio_info = {
  436     .stressor = stress_revio,
  437     .class = CLASS_IO | CLASS_OS
  438 };