"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-switch.c" (15 Mar 2019, 5112 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-switch.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.09.54_vs_0.09.55.

    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 SWITCH_STOP 'X'
   28 #define THRESH_FREQ (100)       /* Delay adjustment rate in HZ */
   29 #define NANO_SECS   (1000000000)
   30 
   31 /*
   32  *  stress_set_switch_freq()
   33  *  set context switch freq in Hz from given option
   34  */
   35 int stress_set_switch_freq(const char *opt)
   36 {
   37     uint64_t switch_freq;
   38 
   39     switch_freq = get_uint64(opt);
   40     check_range("switch-freq", switch_freq, 0, NANO_SECS);
   41     return set_setting("switch-freq", TYPE_ID_UINT64, &switch_freq);
   42 }
   43 
   44 /*
   45  *  stress_switch
   46  *  stress by heavy context switching
   47  */
   48 static int stress_switch(const args_t *args)
   49 {
   50     pid_t pid;
   51     int pipefds[2];
   52     size_t buf_size;
   53     uint64_t switch_freq = 0;
   54 
   55     (void)get_setting("switch-freq", &switch_freq);
   56 
   57 #if defined(HAVE_PIPE2) &&  \
   58     defined(O_DIRECT)
   59     if (pipe2(pipefds, O_DIRECT) < 0) {
   60         /*
   61          *  Fallback to pipe if pipe2 fails
   62          */
   63         if (pipe(pipefds) < 0) {
   64             pr_fail_dbg("pipe");
   65             return EXIT_FAILURE;
   66         }
   67     }
   68     buf_size = 1;
   69 #else
   70     if (pipe(pipefds) < 0) {
   71         pr_fail_dbg("pipe");
   72         return EXIT_FAILURE;
   73     }
   74     buf_size = args->page_size;
   75 #endif
   76 
   77 #if defined(F_SETPIPE_SZ)
   78     if (fcntl(pipefds[0], F_SETPIPE_SZ, buf_size) < 0) {
   79         pr_dbg("%s: could not force pipe size to 1 page, "
   80             "errno = %d (%s)\n",
   81             args->name, errno, strerror(errno));
   82     }
   83     if (fcntl(pipefds[1], F_SETPIPE_SZ, buf_size) < 0) {
   84         pr_dbg("%s: could not force pipe size to 1 page, "
   85             "errno = %d (%s)\n",
   86             args->name, errno, strerror(errno));
   87     }
   88 #endif
   89 
   90 again:
   91     pid = fork();
   92     if (pid < 0) {
   93         if (g_keep_stressing_flag && (errno == EAGAIN))
   94             goto again;
   95         (void)close(pipefds[0]);
   96         (void)close(pipefds[1]);
   97         pr_fail_dbg("fork");
   98         return EXIT_FAILURE;
   99     } else if (pid == 0) {
  100         char buf[buf_size];
  101 
  102         (void)setpgid(0, g_pgrp);
  103         stress_parent_died_alarm();
  104 
  105         (void)close(pipefds[1]);
  106 
  107         while (g_keep_stressing_flag) {
  108             ssize_t ret;
  109 
  110             ret = read(pipefds[0], buf, sizeof(buf));
  111             if (ret < 0) {
  112                 if ((errno == EAGAIN) || (errno == EINTR))
  113                     continue;
  114                 pr_fail_dbg("read");
  115                 break;
  116             }
  117             if (ret == 0)
  118                 break;
  119             if (*buf == SWITCH_STOP)
  120                 break;
  121         }
  122         (void)close(pipefds[0]);
  123         _exit(EXIT_SUCCESS);
  124     } else {
  125         char buf[buf_size];
  126         int status;
  127         double t1, t2, t;
  128         uint64_t delay, switch_delay = (switch_freq == 0) ? 0 : NANO_SECS / switch_freq;
  129         uint64_t i = 0, threshold = switch_freq / THRESH_FREQ;
  130 
  131         /* Parent */
  132         (void)setpgid(pid, g_pgrp);
  133         (void)close(pipefds[0]);
  134         (void)memset(buf, '_', buf_size);
  135 
  136         delay = switch_delay;
  137 
  138         t1 = time_now();
  139         do {
  140             ssize_t ret;
  141 
  142             inc_counter(args);
  143 
  144             ret = write(pipefds[1], buf, sizeof(buf));
  145             if (ret <= 0) {
  146                 if ((errno == EAGAIN) || (errno == EINTR))
  147                     continue;
  148                 if (errno) {
  149                     pr_fail_dbg("write");
  150                     break;
  151                 }
  152                 continue;
  153             }
  154 
  155             if (switch_freq) {
  156                 /*
  157                  *  Small delays take a while, so skip these
  158                  */
  159                 if (delay > 1000)
  160                     shim_nanosleep_uint64(delay);
  161 
  162                 /*
  163                  *  This is expensive, so only update the
  164                  *  delay infrequently (at THRESH_FREQ HZ)
  165                  */
  166                 if (++i >= threshold) {
  167                     double overrun, overrun_by;
  168 
  169                     i = 0;
  170                     t = t1 + ((((double)get_counter(args)) * switch_delay) / NANO_SECS);
  171                     overrun = (time_now() - t) * (double)NANO_SECS;
  172                     overrun_by = (double)switch_delay - overrun;
  173 
  174                     if (overrun_by < 0.0) {
  175                         /* Massive overrun, skip a delay */
  176                         delay = 0;
  177                     } else {
  178                         /* Overrun or underrun? */
  179                         delay = (double)overrun_by;
  180                         if (delay > switch_delay) {
  181                             /* Don't delay more than the switch delay */
  182                             delay = switch_delay;
  183                         }
  184                     }
  185                 }
  186             }
  187         } while (keep_stressing());
  188 
  189         t2 = time_now();
  190         pr_inf("%s: %.2f nanoseconds per context switch (based on parent run time)\n",
  191             args->name,
  192             ((t2 - t1) * NANO_SECS) / (double)get_counter(args));
  193 
  194         (void)memset(buf, SWITCH_STOP, sizeof(buf));
  195         if (write(pipefds[1], buf, sizeof(buf)) <= 0)
  196             pr_fail_dbg("termination write");
  197         (void)kill(pid, SIGKILL);
  198         (void)waitpid(pid, &status, 0);
  199     }
  200 
  201     return EXIT_SUCCESS;
  202 }
  203 
  204 stressor_info_t stress_switch_info = {
  205     .stressor = stress_switch,
  206     .class = CLASS_SCHEDULER | CLASS_OS
  207 };