"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.13.05/core-thrash.c" (11 Oct 2021, 7104 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 "core-thrash.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 #if defined(__linux__) &&   \
   28     defined(HAVE_PTRACE)
   29 
   30 #define KSM_RUN_MERGE       "1"
   31 
   32 static pid_t thrash_pid;
   33 static pid_t parent_pid;
   34 static volatile bool thrash_run;
   35 
   36 static void MLOCKED_TEXT stress_thrash_handler(int signum)
   37 {
   38     (void)signum;
   39 
   40     thrash_run = false;
   41 }
   42 
   43 /*
   44  *  stress_pagein_proc()
   45  *  force pages into memory for a given process
   46  */
   47 static int stress_pagein_proc(const pid_t pid)
   48 {
   49     char path[PATH_MAX];
   50     char buffer[4096];
   51     int fdmem, rc = 0;
   52     FILE *fpmap;
   53     const size_t page_size = stress_get_pagesize();
   54 
   55     if ((pid == parent_pid) || (pid == getpid()))
   56         return 0;
   57 
   58     (void)snprintf(path, sizeof(path), "/proc/%" PRIdMAX" /mem", (intmax_t)pid);
   59     fdmem = open(path, O_RDONLY);
   60     if (fdmem < 0)
   61         return -errno;
   62 
   63     (void)snprintf(path, sizeof(path), "/proc/%" PRIdMAX" /maps", (intmax_t)pid);
   64     fpmap = fopen(path, "r");
   65     if (!fpmap) {
   66         rc = -errno;
   67         goto exit_fdmem;
   68     }
   69 
   70     /*
   71      * Look for field 0060b000-0060c000 r--p 0000b000 08:01 1901726
   72      */
   73     while (thrash_run && fgets(buffer, sizeof(buffer), fpmap)) {
   74         uintmax_t begin, end, len;
   75         uintptr_t off;
   76         char tmppath[1024];
   77         char prot[5];
   78 
   79         if (sscanf(buffer, "%" SCNx64 "-%" SCNx64
   80                    " %5s %*x %*x:%*x %*d %1023s", &begin, &end, prot, tmppath) != 4)
   81             continue;
   82 
   83         /* ignore non-readable or non-private mappings */
   84         if (prot[0] != 'r' && prot[3] != 'p')
   85             continue;
   86         len = end - begin;
   87 
   88         /* Ignore bad range */
   89         if ((begin >= end) || (len == 0) || (begin == 0))
   90             continue;
   91         /* Skip huge ranges more than 2GB */
   92         if (len > 0x80000000UL)
   93             continue;
   94 
   95         for (off = begin; thrash_run && (off < end); off += page_size) {
   96             unsigned long data;
   97             off_t pos;
   98             ssize_t sz;
   99 
  100             pos = lseek(fdmem, (off_t)off, SEEK_SET);
  101             if (pos != (off_t)off)
  102                 continue;
  103             sz = read(fdmem, &data, sizeof(data));
  104             (void)sz;
  105         }
  106     }
  107 
  108     (void)fclose(fpmap);
  109 exit_fdmem:
  110     (void)close(fdmem);
  111 
  112     return rc;
  113 }
  114 
  115 /*
  116  *  stress_compact_memory()
  117  *  trigger memory compaction, Linux only
  118  */
  119 static inline void stress_compact_memory(void)
  120 {
  121 #if defined(__linux__)
  122     ssize_t ret;
  123 
  124     if (!thrash_run)
  125         return;
  126 
  127     ret = system_write("/proc/sys/vm/compact_memory", "1", 1);
  128     (void)ret;
  129 #endif
  130 }
  131 
  132 /*
  133  *  stress_zone_reclaim()
  134  *  trigger reclaim when zones run out of memory
  135  */
  136 static inline void stress_zone_reclaim(void)
  137 {
  138 #if defined(__linux__)
  139     ssize_t ret;
  140     char mode[2];
  141 
  142     if (!thrash_run)
  143         return;
  144 
  145     mode[0] = '0' + (stress_mwc8() & 7);
  146     mode[1] = '\0';
  147 
  148     ret = system_write("/proc/sys/vm/zone_reclaim_mode", mode, 1);
  149     (void)ret;
  150 #endif
  151 }
  152 
  153 /*
  154  *  stress_slab_shrink()
  155  *  shrink slabs to help release some memory
  156  */
  157 static inline void stress_slab_shrink(void)
  158 {
  159     DIR *dir;
  160     struct dirent *d;
  161     static const char slabpath[] = "/sys/kernel/slab";
  162     int ret;
  163 
  164     /*
  165      *  older shrink interface, may fail
  166      */
  167     ret = system_write("/sys/kernel/slab/cache/shrink", "1", 1);
  168     (void)ret;
  169 
  170     dir = opendir(slabpath);
  171     if (!dir)
  172         return;
  173 
  174     /*
  175      *  shrink all slabs
  176      */
  177     while ((d = readdir(dir)) != NULL) {
  178         if (isalpha((int)d->d_name[0]))  {
  179             char path[PATH_MAX];
  180 
  181             (void)snprintf(path, sizeof(path), "%s/%s", slabpath, d->d_name);
  182             ret = system_write(path, "1", 1);
  183             (void)ret;
  184         }
  185     }
  186     (void)closedir(dir);
  187 }
  188 
  189 /*
  190  *  stress_drop_caches()
  191  *  drop caches
  192  */
  193 static inline void stress_drop_caches(void)
  194 {
  195 #if defined(__linux__)
  196     static int method = 0;
  197     char str[3];
  198     int ret;
  199 
  200     str[0] = '1' + method;
  201     str[1] = '\0';
  202 
  203     ret = system_write("/proc/sys/vm/drop_caches", str, 1);
  204     (void)ret;
  205 
  206     if (method++ >= 2)
  207         method = 0;
  208 #endif
  209 }
  210 
  211 /*
  212  *  stress_merge_memory()
  213  *  trigger ksm memory merging, Linux only
  214  */
  215 static inline void stress_merge_memory(void)
  216 {
  217 #if defined(__linux__)
  218     ssize_t ret;
  219 
  220     if (!thrash_run)
  221         return;
  222 
  223     ret = system_write("/proc/sys/mm/ksm/run", KSM_RUN_MERGE, 1);
  224     (void)ret;
  225 #endif
  226 }
  227 
  228 /*
  229  *  stress_pagein_all_procs()
  230  *  force pages into memory for all processes
  231  */
  232 static int stress_pagein_all_procs(void)
  233 {
  234     DIR *dp;
  235     struct dirent *d;
  236 
  237     dp = opendir("/proc");
  238     if (!dp)
  239         return -1;
  240 
  241     while (thrash_run && ((d = readdir(dp)) != NULL)) {
  242         intmax_t pid;
  243 
  244         if (isdigit(d->d_name[0]) &&
  245             sscanf(d->d_name, "%" SCNdMAX, &pid) == 1) {
  246             char procpath[128];
  247             struct stat statbuf;
  248 
  249             (void)snprintf(procpath, sizeof(procpath), "/proc/%" PRIdMAX, pid);
  250             if (stat(procpath, &statbuf) < 0)
  251                 continue;
  252 
  253             if (statbuf.st_uid == 0)
  254                 continue;
  255 
  256             stress_pagein_proc((pid_t)pid);
  257         }
  258     }
  259     (void)closedir(dp);
  260 
  261     return 0;
  262 }
  263 
  264 /*
  265  *  stress_thrash_start()
  266  *  start paging in thrash process
  267  */
  268 int stress_thrash_start(void)
  269 {
  270     if (geteuid() != 0) {
  271         pr_inf("not running as root, ignoring --thrash option\n");
  272         return -1;
  273     }
  274     if (thrash_pid) {
  275         pr_err("thrash background process already started\n");
  276         return -1;
  277     }
  278     parent_pid = getpid();
  279     thrash_run = true;
  280     thrash_pid = fork();
  281     if (thrash_pid < 0) {
  282         thrash_run = false;
  283         pr_err("thrash background process failed to fork: %d (%s)\n",
  284             errno, strerror(errno));
  285         return -1;
  286     } else if (thrash_pid == 0) {
  287 #if defined(SCHED_RR)
  288         int ret;
  289 
  290         ret = stress_set_sched(getpid(), SCHED_RR, 10, true);
  291         (void)ret;
  292 #endif
  293         stress_set_proc_name("stress-ng-thrash");
  294         if (stress_sighandler("main", SIGALRM, stress_thrash_handler, NULL) < 0)
  295             _exit(0);
  296 
  297         while (thrash_run) {
  298             if ((stress_mwc8() & 0x3) == 0) {
  299                 stress_slab_shrink();
  300                 stress_pagein_all_procs();
  301             }
  302             if ((stress_mwc8() & 0x7) == 0)
  303                 stress_drop_caches();
  304             stress_compact_memory();
  305             stress_merge_memory();
  306             stress_zone_reclaim();
  307             (void)sleep(1);
  308         }
  309         thrash_run = false;
  310         _exit(0);
  311     }
  312     return 0;
  313 }
  314 
  315 /*
  316  *  stress_thrash_stop()
  317  *  stop paging in thrash process
  318  */
  319 void stress_thrash_stop(void)
  320 {
  321     int status;
  322 
  323     thrash_run = false;
  324 
  325     if (!thrash_pid)
  326         return;
  327 
  328     (void)kill(thrash_pid, SIGALRM);
  329     (void)shim_waitpid(thrash_pid, &status, 0);
  330     if (kill(thrash_pid, 0) == 0) {
  331         (void)shim_usleep(250000);
  332         (void)kill(thrash_pid, SIGKILL);
  333         (void)shim_waitpid(thrash_pid, &status, 0);
  334     }
  335 
  336     thrash_pid = 0;
  337 }
  338 
  339 #else
  340 int stress_thrash_start(void)
  341 {
  342     return 0;
  343 }
  344 
  345 void stress_thrash_stop(void)
  346 {
  347 }
  348 #endif