"Fossies" - the Fresh Open Source Software Archive

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

    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 #if defined(__NR_get_mempolicy) &&  \
   28     defined(__NR_mbind) &&      \
   29     defined(__NR_migrate_pages) &&  \
   30     defined(__NR_move_pages) &&     \
   31     defined(__NR_set_mempolicy)
   32 
   33 #define BITS_PER_BYTE       (8)
   34 #define NUMA_LONG_BITS      (sizeof(unsigned long) * BITS_PER_BYTE)
   35 
   36 #define MPOL_DEFAULT        (0)
   37 #define MPOL_PREFERRED      (1)
   38 #define MPOL_BIND       (2)
   39 #define MPOL_INTERLEAVE     (3)
   40 #define MPOL_LOCAL      (4)
   41 
   42 #define MPOL_F_NODE     (1 << 0)
   43 #define MPOL_F_ADDR     (1 << 1)
   44 #define MPOL_F_MEMS_ALLOWED (1 << 2)
   45 
   46 #define MPOL_MF_STRICT      (1 << 0)
   47 #define MPOL_MF_MOVE        (1 << 1)
   48 #define MPOL_MF_MOVE_ALL    (1 << 2)
   49 
   50 #define MMAP_SZ         (4 * MB)
   51 
   52 typedef struct node {
   53     struct node *next;
   54     uint32_t    node_id;
   55 } node_t;
   56 
   57 /*
   58  *  stress_numa_get_max_nodes()
   59  *  probe for maximum number of nodes
   60  */
   61 static unsigned long stress_numa_get_max_nodes(void)
   62 {
   63     unsigned long sz = BITS_PER_BYTE, *mask = NULL;
   64 
   65     do {
   66         int mode = 0;
   67         unsigned long *newmask = realloc(mask, sz / BITS_PER_BYTE);
   68 
   69         if (!newmask)
   70             break;
   71         mask = newmask;
   72         if (shim_get_mempolicy(&mode, mask, sz, 0, 0) == 0)
   73             goto done;
   74         sz <<= 1;
   75     } while ((sz < 0x100000) && (errno == EINVAL));
   76 
   77     /* Failed */
   78     sz = 0;
   79 done:
   80     free(mask);
   81 
   82     return sz;
   83 }
   84 
   85 /*
   86  *  stress_numa_free_nodes()
   87  *  free circular list of node info
   88  */
   89 static void stress_numa_free_nodes(node_t *nodes)
   90 {
   91     node_t *n = nodes;
   92 
   93     while (n) {
   94         node_t *next = n->next;
   95 
   96         free(n);
   97         n = next;
   98 
   99         if (n == nodes)
  100             break;
  101     }
  102 }
  103 
  104 /*
  105  *  hex_to_int()
  106  *  convert ASCII hex digit to integer
  107  */
  108 static inline int hex_to_int(const char ch)
  109 {
  110     if (ch >= '0' && ch <= '9')
  111         return ch - '0';
  112     if (ch >= 'a' && ch <= 'f')
  113         return ch - 'a' + 10;
  114     if (ch >= 'A' && ch <= 'F')
  115         return ch - 'F' + 10;
  116     return -1;
  117 }
  118 
  119 /*
  120  *  stress_numa_get_mem_nodes(void)
  121  *  collect number of NUMA memory nodes, add them to a
  122  *  circular linked list
  123  */
  124 static int stress_numa_get_mem_nodes(node_t **node_ptr)
  125 {
  126     FILE *fp;
  127     unsigned long n = 0, node_id = 0;
  128     node_t *tail = NULL;
  129     *node_ptr = NULL;
  130     char buffer[8192], *str = NULL, *ptr;
  131 
  132     fp = fopen("/proc/self/status", "r");
  133     if (!fp)
  134         return -1;
  135 
  136     while (fgets(buffer, sizeof(buffer), fp)) {
  137         if (!strncmp(buffer, "Mems_allowed:", 13)) {
  138             str = buffer + 13;
  139             break;
  140         }
  141     }
  142     (void)fclose(fp);
  143 
  144     if (!str)
  145         return -1;
  146 
  147     ptr = buffer + strlen(buffer) - 2;
  148 
  149     /*
  150      *  Parse hex digits into NUMA node ids, these
  151      *  are listed with least significant node last
  152      *  so we need to scan backwards from the end of
  153      *  the string back to the start.
  154      */
  155     while (*ptr != ' ' && (ptr > str)) {
  156         int val, i;
  157 
  158         /* Skip commas */
  159         if (*ptr == ',') {
  160             ptr--;
  161             continue;
  162         }
  163 
  164         val = hex_to_int(*ptr);
  165         if (val < 0)
  166             return -1;
  167 
  168         /* Each hex digit represent 4 memory nodes */
  169         for (i = 0; i < 4; i++) {
  170             if (val & (1 << i)) {
  171                 node_t *node = calloc(1, sizeof(*node));
  172                 if (!node)
  173                     return -1;
  174                 node->node_id = node_id;
  175                 node->next = *node_ptr;
  176                 *node_ptr = node;
  177                 if (!tail)
  178                     tail = node;
  179                 tail->next = node;
  180                 n++;
  181             }
  182             node_id++;
  183         }
  184         ptr--;
  185     }
  186 
  187     return n;
  188 }
  189 
  190 /*
  191  *  stress_numa()
  192  *  stress the Linux NUMA interfaces
  193  */
  194 static int stress_numa(const args_t *args)
  195 {
  196     long numa_nodes;
  197     unsigned long max_nodes;
  198     const unsigned long lbits = NUMA_LONG_BITS;
  199     const unsigned long page_sz = args->page_size;
  200     const unsigned long num_pages = MMAP_SZ / page_sz;
  201     uint8_t *buf;
  202     node_t *n;
  203     int rc = EXIT_FAILURE;
  204 
  205     numa_nodes = stress_numa_get_mem_nodes(&n);
  206     if (numa_nodes < 1) {
  207         pr_inf("%s: no NUMA nodes not found, "
  208             "aborting test\n", args->name);
  209         rc = EXIT_NO_RESOURCE;
  210         goto numa_free;
  211     }
  212     max_nodes = stress_numa_get_max_nodes();
  213     if (max_nodes == 0) {
  214         pr_inf("%s: cannot determine maximum number "
  215             "of NUMA nodes, aborting test\n", args->name);
  216         rc = EXIT_NO_RESOURCE;
  217         goto numa_free;
  218     }
  219     if (!args->instance) {
  220         pr_inf("%s: system has %lu of a maximum %lu memory NUMA nodes\n",
  221             args->name, numa_nodes, max_nodes);
  222     }
  223 
  224     /*
  225      *  We need a buffer to migrate around NUMA nodes
  226      */
  227     buf = mmap(NULL, MMAP_SZ, PROT_READ | PROT_WRITE,
  228         MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
  229     if (buf == MAP_FAILED) {
  230         rc = exit_status(errno);
  231         pr_fail("%s: mmap'd region of %zu bytes failed",
  232             args->name, (size_t)MMAP_SZ);
  233         goto numa_free;
  234     }
  235 
  236     do {
  237         int j, mode, ret, status[num_pages], dest_nodes[num_pages];
  238         unsigned long i, node_mask[lbits], old_node_mask[lbits];
  239         void *pages[num_pages];
  240         uint8_t *ptr;
  241         node_t *n_tmp;
  242         unsigned cpu, curr_node;
  243 
  244         /*
  245          *  Fetch memory policy
  246          */
  247         ret = shim_get_mempolicy(&mode, node_mask, max_nodes,
  248             (unsigned long)buf, MPOL_F_ADDR);
  249         if (ret < 0) {
  250             pr_fail_err("get_mempolicy");
  251             goto err;
  252         }
  253         if (!g_keep_stressing_flag)
  254             break;
  255 
  256         ret = shim_set_mempolicy(MPOL_PREFERRED, NULL, max_nodes);
  257         if (ret < 0) {
  258             pr_fail_err("set_mempolicy");
  259             goto err;
  260         }
  261         (void)memset(buf, 0xff, MMAP_SZ);
  262         if (!g_keep_stressing_flag)
  263             break;
  264 
  265         /*
  266          *  Fetch CPU and node, we just waste some cycled
  267          *  doing this for stress reasons only
  268          */
  269         (void)shim_getcpu(&cpu, &curr_node, NULL);
  270 
  271         /*
  272          *  mbind the buffer, first try MPOL_STRICT which
  273          *  may fail with EIO
  274          */
  275         (void)memset(node_mask, 0, sizeof(node_mask));
  276         STRESS_SETBIT(node_mask, n->node_id);
  277         ret = shim_mbind(buf, MMAP_SZ, MPOL_BIND, node_mask,
  278             max_nodes, MPOL_MF_STRICT);
  279         if (ret < 0) {
  280             if (errno != EIO) {
  281                 pr_fail_err("mbind");
  282                 goto err;
  283             }
  284         } else {
  285             (void)memset(buf, 0xaa, MMAP_SZ);
  286         }
  287         if (!g_keep_stressing_flag)
  288             break;
  289 
  290         /*
  291          *  mbind the buffer, now try MPOL_DEFAULT
  292          */
  293         (void)memset(node_mask, 0, sizeof(node_mask));
  294         STRESS_SETBIT(node_mask, n->node_id);
  295         ret = shim_mbind(buf, MMAP_SZ, MPOL_BIND, node_mask,
  296             max_nodes, MPOL_DEFAULT);
  297         if (ret < 0) {
  298             if (errno != EIO) {
  299                 pr_fail_err("mbind");
  300                 goto err;
  301             }
  302         } else {
  303             (void)memset(buf, 0x5c, MMAP_SZ);
  304         }
  305         if (!g_keep_stressing_flag)
  306             break;
  307 
  308         /* Move to next node */
  309         n = n->next;
  310 
  311         /*
  312          *  Migrate all this processes pages to the current new node
  313          */
  314         (void)memset(old_node_mask, 0xff, sizeof(old_node_mask));
  315         (void)memset(node_mask, 0, sizeof(node_mask));
  316         STRESS_SETBIT(node_mask, n->node_id);
  317         ret = shim_migrate_pages(args->pid, max_nodes,
  318             old_node_mask, node_mask);
  319         if (ret < 0) {
  320             pr_fail_err("migrate_pages");
  321             goto err;
  322         }
  323         if (!g_keep_stressing_flag)
  324             break;
  325 
  326         n_tmp = n;
  327         for (j = 0; j < 16; j++) {
  328             /*
  329              *  Now move pages to lots of different numa nodes
  330              */
  331             for (ptr = buf, i = 0; i < num_pages; i++, ptr += page_sz, n_tmp = n_tmp->next) {
  332                 pages[i] = ptr;
  333                 dest_nodes[i] = n_tmp->node_id;
  334             }
  335             (void)memset(status, 0, sizeof(status));
  336             ret = shim_move_pages(args->pid, num_pages, pages,
  337                 dest_nodes, status, MPOL_MF_MOVE);
  338             if (ret < 0) {
  339                 pr_fail_err("move_pages");
  340                 goto err;
  341             }
  342             (void)memset(buf, j, MMAP_SZ);
  343             if (!g_keep_stressing_flag)
  344                 break;
  345         }
  346         inc_counter(args);
  347     } while (keep_stressing());
  348 
  349     rc = EXIT_SUCCESS;
  350 err:
  351     (void)munmap(buf, MMAP_SZ);
  352 numa_free:
  353     stress_numa_free_nodes(n);
  354 
  355     return rc;
  356 }
  357 
  358 stressor_info_t stress_numa_info = {
  359     .stressor = stress_numa,
  360     .class = CLASS_CPU | CLASS_MEMORY | CLASS_OS
  361 };
  362 #else
  363 stressor_info_t stress_numa_info = {
  364     .stressor = stress_not_implemented,
  365     .class = CLASS_CPU | CLASS_MEMORY | CLASS_OS
  366 };
  367 #endif