"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.13.05/stress-aio.c" (11 Oct 2021, 9952 Bytes) of package /linux/privat/stress-ng-0.13.05.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-aio.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.13.04_vs_0.13.05.

    1 /*
    2  * Copyright (C) 2013-2021 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 static const stress_help_t help[] = {
   28     { NULL, "aio N",    "start N workers that issue async I/O requests" },
   29     { NULL, "aio-ops N",    "stop after N bogo async I/O requests" },
   30     { NULL, "aio-requests N", "number of async I/O requests per worker" },
   31     { NULL, NULL,       NULL }
   32 };
   33 
   34 #if defined(HAVE_LIB_RT) && \
   35     defined(HAVE_AIO_H)  && \
   36     defined(HAVE_AIO_CANCEL) && \
   37     defined(HAVE_AIO_READ) &&   \
   38     defined(HAVE_AIO_WRITE)
   39 
   40 #define BUFFER_SZ   (16)
   41 
   42 /* per request async I/O data */
   43 typedef struct {
   44     int     request;        /* Request slot */
   45     int     status;         /* AIO error status */
   46     struct aiocb    aiocb;          /* AIO cb */
   47     uint8_t     buffer[BUFFER_SZ];  /* Associated read/write buffer */
   48     volatile uint64_t count;        /* Signal handled count */
   49 } stress_io_req_t;
   50 
   51 static volatile bool do_accounting = true;
   52 #endif
   53 
   54 static int stress_set_aio_requests(const char *opt)
   55 {
   56     uint32_t aio_requests;
   57 
   58     aio_requests = stress_get_uint32(opt);
   59     stress_check_range("aio-requests", (uint64_t)aio_requests,
   60         MIN_AIO_REQUESTS, MAX_AIO_REQUESTS);
   61     return stress_set_setting("aio-requests", TYPE_ID_UINT32, &aio_requests);
   62 }
   63 
   64 static const stress_opt_set_func_t opt_set_funcs[] = {
   65     { OPT_aio_requests, stress_set_aio_requests },
   66     { 0,            NULL },
   67 };
   68 
   69 #if defined(HAVE_LIB_RT) && \
   70     defined(HAVE_AIO_H) &&  \
   71     defined(HAVE_AIO_CANCEL) && \
   72     defined(HAVE_AIO_READ) &&   \
   73     defined(HAVE_AIO_WRITE)
   74 /*
   75  *  aio_fill_buffer()
   76  *  fill buffer with some known pattern
   77  */
   78 static inline void aio_fill_buffer(
   79     const uint8_t request,
   80     uint8_t *const buffer,
   81     const size_t size)
   82 {
   83     register size_t i;
   84 
   85     for (i = 0; i < size; i++)
   86         buffer[i] = (uint8_t)(request + i);
   87 }
   88 
   89 /*
   90  *  aio_signal_handler()
   91  *  handle an async I/O signal
   92  */
   93 static void MLOCKED_TEXT aio_signal_handler(int sig, siginfo_t *si, void *ucontext)
   94 {
   95     stress_io_req_t *io_req = (stress_io_req_t *)si->si_value.sival_ptr;
   96 
   97     (void)sig;
   98     (void)si;
   99     (void)ucontext;
  100 
  101     if (do_accounting && io_req)
  102         io_req->count++;
  103 }
  104 
  105 /*
  106  *  aio_issue_cancel()
  107  *  cancel an in-progress async I/O request
  108  */
  109 static void aio_issue_cancel(const char *name, stress_io_req_t *io_req)
  110 {
  111     int ret, retries = 0;
  112 
  113     for (;;) {
  114         ret = aio_error(&io_req->aiocb);
  115         if (ret != EINPROGRESS)
  116             return;
  117 
  118         ret = aio_cancel(io_req->aiocb.aio_fildes,
  119             &io_req->aiocb);
  120         switch (ret) {
  121         case AIO_CANCELED:
  122         case AIO_ALLDONE:
  123             return;
  124         case AIO_NOTCANCELED:
  125             if (retries++ > 25) {
  126                 /* Give up */
  127                 pr_inf("%s aio request %d could not be cancelled: error=%d (%s)\n",
  128                     name, io_req->request,
  129                     errno, strerror(errno));
  130             }
  131             /* Wait a bit and retry */
  132             (void)shim_usleep_interruptible(250000);
  133             break;
  134         default:
  135             pr_err("%s: %d error: %d %s\n",
  136                 name, io_req->request,
  137                 errno, strerror(errno));
  138             break;
  139         }
  140     }
  141 }
  142 
  143 /*
  144  *  issue_aio_request()
  145  *  construct an AIO request and action it
  146  */
  147 static int issue_aio_request(
  148     const char *name,
  149     const int fd,
  150     const off_t offset,
  151     stress_io_req_t *const io_req,
  152     const uint32_t request,
  153     int (*aio_func)(struct aiocb *aiocbp))
  154 {
  155     while (keep_stressing_flag()) {
  156         int ret;
  157 
  158         io_req->request = (int)request;
  159         io_req->status = EINPROGRESS;
  160         io_req->aiocb.aio_fildes = fd;
  161         io_req->aiocb.aio_buf = io_req->buffer;
  162         io_req->aiocb.aio_nbytes = BUFFER_SZ;
  163         io_req->aiocb.aio_reqprio = 0;
  164         io_req->aiocb.aio_offset = offset;
  165         io_req->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
  166         io_req->aiocb.aio_sigevent.sigev_signo = SIGUSR1;
  167         io_req->aiocb.aio_sigevent.sigev_value.sival_ptr = io_req;
  168 
  169         ret = aio_func(&io_req->aiocb);
  170         if (ret < 0) {
  171             if ((errno == EAGAIN) ||
  172                 (errno == EINTR) ||
  173                 (errno == EBUSY))
  174                 continue;
  175             pr_err("%s: failed to issue aio request: %d (%s)\n",
  176                 name, errno, strerror(errno));
  177         }
  178         return ret;
  179     }
  180     /* Given up */
  181     return 1;
  182 }
  183 
  184 #if defined(HAVE_AIO_FSYNC) &&  \
  185     defined(O_SYNC) &&      \
  186     defined(O_DSYNC)
  187 /*
  188  *  issue_aio_sync_request()
  189  *  construct an AIO sync request and action it
  190  */
  191 static int issue_aio_sync_request(
  192     const char *name,
  193     const int fd,
  194     stress_io_req_t *const io_req)
  195 {
  196     while (keep_stressing_flag()) {
  197         int ret;
  198         const int op = stress_mwc1() ? O_SYNC : O_DSYNC;
  199 
  200         io_req->request = 0;
  201         io_req->status = EINPROGRESS;
  202         io_req->aiocb.aio_fildes = fd;
  203         io_req->aiocb.aio_buf = 0;
  204         io_req->aiocb.aio_nbytes = 0;
  205         io_req->aiocb.aio_reqprio = 0;
  206         io_req->aiocb.aio_offset = 0;
  207         io_req->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
  208         io_req->aiocb.aio_sigevent.sigev_signo = SIGUSR1;
  209         io_req->aiocb.aio_sigevent.sigev_value.sival_ptr = io_req;
  210 
  211         ret = aio_fsync(op, &io_req->aiocb);
  212         if (ret < 0) {
  213             if ((errno == EAGAIN) || (errno == EINTR))
  214                 continue;
  215             pr_err("%s: failed to issue aio request: %d (%s)\n",
  216                 name, errno, strerror(errno));
  217         }
  218         return ret;
  219     }
  220     /* Given up */
  221     return 1;
  222 }
  223 #endif
  224 
  225 /*
  226  *  stress_aio
  227  *  stress asynchronous I/O
  228  */
  229 static int stress_aio(const stress_args_t *args)
  230 {
  231     int ret, fd, rc = EXIT_FAILURE;
  232     stress_io_req_t *io_reqs;
  233     struct sigaction sa, sa_old;
  234     char filename[PATH_MAX];
  235     uint32_t total = 0, i, opt_aio_requests = DEFAULT_AIO_REQUESTS;
  236     double t1 = 0.0, t2 = 0.0, dt;
  237 
  238     if (!stress_get_setting("aio-requests", &opt_aio_requests)) {
  239         if (g_opt_flags & OPT_FLAGS_MAXIMIZE)
  240             opt_aio_requests = MAX_AIO_REQUESTS;
  241         if (g_opt_flags & OPT_FLAGS_MINIMIZE)
  242             opt_aio_requests = MIN_AIO_REQUESTS;
  243     }
  244 
  245     if ((io_reqs = calloc(opt_aio_requests, sizeof(*io_reqs))) == NULL) {
  246         pr_err("%s: cannot allocate io request structures\n", args->name);
  247         return EXIT_NO_RESOURCE;
  248     }
  249 
  250     ret = stress_temp_dir_mk_args(args);
  251     if (ret < 0) {
  252         ret = exit_status(-ret);
  253         free(io_reqs);
  254 
  255         return ret;
  256     }
  257 
  258     (void)stress_temp_filename_args(args,
  259         filename, sizeof(filename), stress_mwc32());
  260 
  261     if ((fd = open(filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) {
  262         rc = exit_status(errno);
  263         pr_fail("%s: open on %s failed, errno=%d (%s)\n",
  264             args->name, filename, errno, strerror(errno));
  265         goto finish;
  266     }
  267     (void)unlink(filename);
  268 
  269     (void)sigemptyset(&sa.sa_mask);
  270     sa.sa_flags = SA_RESTART | SA_SIGINFO;
  271     sa.sa_sigaction = aio_signal_handler;
  272     if (sigaction(SIGUSR1, &sa, &sa_old) < 0)
  273         pr_fail("%s: sigaction on SIGUSR1 failed, errno=%d (%s)\n",
  274             args->name, errno, strerror(errno));
  275 
  276     /* Kick off requests */
  277     for (i = 0; i < opt_aio_requests; i++) {
  278         aio_fill_buffer((uint8_t)i, io_reqs[i].buffer, BUFFER_SZ);
  279         ret = issue_aio_request(args->name, fd, (off_t)i * BUFFER_SZ,
  280             &io_reqs[i], i, aio_write);
  281         if (ret < 0)
  282             goto cancel;
  283         if (ret > 0) {
  284             rc = EXIT_SUCCESS;
  285             goto cancel;
  286         }
  287     }
  288     stress_set_proc_state(args->name, STRESS_STATE_RUN);
  289 
  290     t1 = stress_time_now();
  291     do {
  292         (void)shim_usleep_interruptible(250000); /* wait until a signal occurs */
  293 
  294         for (i = 0; keep_stressing(args) && (i < opt_aio_requests); i++) {
  295             if (io_reqs[i].status != EINPROGRESS)
  296                 continue;
  297 
  298             io_reqs[i].status = aio_error(&io_reqs[i].aiocb);
  299             switch (io_reqs[i].status) {
  300             case ECANCELED:
  301             case 0:
  302                 /* Succeeded or cancelled, so redo another */
  303                 inc_counter(args);
  304 #if defined(HAVE_AIO_FSYNC) &&  \
  305     defined(O_SYNC) &&      \
  306     defined(O_DSYNC)
  307                 if (i != (opt_aio_requests - 1)) {
  308                     ret = issue_aio_request(args->name, fd,
  309                         (off_t)i * BUFFER_SZ,
  310                         &io_reqs[i], i,
  311                         stress_mwc1() ? aio_read : aio_write);
  312                 } else {
  313                     ret = issue_aio_sync_request(args->name,
  314                         fd, &io_reqs[i]);
  315                 }
  316 #else
  317                 ret = issue_aio_request(args->name, fd,
  318                     (off_t)i * BUFFER_SZ, &io_reqs[i], i,
  319                     stress_mwc1() ? aio_read : aio_write);
  320 #endif
  321                 if (ret < 0)
  322                     goto cancel;
  323 
  324                 break;
  325             case EINPROGRESS:
  326                 break;
  327             case ENOSPC:
  328                 /* Silently ignore ENOSPC write failures */
  329                 break;
  330             default:
  331                 /* Something went wrong */
  332                 pr_fail("%s: aio_error, io_reqs[%" PRIu32 "].status = %d (%s)\n",
  333                     args->name, i,
  334                     io_reqs[i].status,
  335                     strerror(io_reqs[i].status));
  336 
  337                 goto cancel;
  338             }
  339         }
  340     } while (keep_stressing(args));
  341     t2 = stress_time_now();
  342 
  343     rc = EXIT_SUCCESS;
  344 
  345 cancel:
  346     /* Stop accounting */
  347     do_accounting = false;
  348     /* Cancel pending AIO requests */
  349     for (i = 0; i < opt_aio_requests; i++) {
  350         aio_issue_cancel(args->name, &io_reqs[i]);
  351         total += io_reqs[i].count;
  352     }
  353 
  354     (void)close(fd);
  355 finish:
  356     stress_set_proc_state(args->name, STRESS_STATE_DEINIT);
  357     free(io_reqs);
  358 
  359     pr_dbg("%s: total of %" PRIu32 " async I/O signals "
  360         "caught (instance %d)\n",
  361         args->name, total, args->instance);
  362 
  363     dt = t2 - t1;
  364     if (dt > 0.0)
  365         stress_misc_stats_set(args->misc_stats, 0, "async I/O signals per sec", (double)total / dt);
  366     (void)stress_temp_dir_rm_args(args);
  367     return rc;
  368 }
  369 
  370 stressor_info_t stress_aio_info = {
  371     .stressor = stress_aio,
  372     .class = CLASS_IO | CLASS_INTERRUPT | CLASS_OS,
  373     .opt_set_funcs = opt_set_funcs,
  374     .help = help
  375 };
  376 #else
  377 stressor_info_t stress_aio_info = {
  378     .stressor = stress_not_implemented,
  379     .class = CLASS_IO | CLASS_INTERRUPT | CLASS_OS,
  380     .opt_set_funcs = opt_set_funcs,
  381     .help = help
  382 };
  383 #endif