"Fossies" - the Fresh Open Source Software Archive

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

    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(STRESS_X86) || defined(STRESS_ARM) || \
   28      defined(STRESS_S390) || defined(STRESS_PPC64)) && \
   29      defined(__GNUC__) && NEED_GNUC(4,6,0) && \
   30      defined(HAVE_MPROTECT)
   31 
   32 #define SIZE_1K     (1024)
   33 #define SIZE_4K     (4 * SIZE_1K)
   34 #define SIZE_16K    (16 * SIZE_1K)
   35 #define SIZE_64K    (64 * SIZE_1K)
   36 
   37 /*
   38  *  STRESS_ICACHE_FUNC()
   39  *  generates a simple function that is page aligned in its own
   40  *  section so we can change the code mapping and make it
   41  *  modifyable to force I-cache refreshes by modifying the code
   42  */
   43 #define STRESS_ICACHE_FUNC(func_name, page_sz)              \
   44 static void SECTION(stress_icache_callee) ALIGNED(page_sz)      \
   45 func_name(void)                             \
   46 {                                   \
   47     return;                             \
   48 }                                   \
   49 
   50 
   51 /*
   52  *  STRESS_ICACHE()
   53  *  macro to generate functions that stress instruction cache
   54  *  load misses
   55  *
   56  *  I-cache load misses can be observed using:
   57  *      perf stat -e L1-icache-load-misses stress-ng --icache 0 -t 1
   58  */
   59 #define STRESS_ICACHE(func_name, page_sz, icache_func)          \
   60 static int SECTION(stress_icache_caller) ALIGNED(page_sz)       \
   61 func_name(const args_t *args)                       \
   62 {                                   \
   63     uint8_t *addr = (uint8_t *)icache_func;             \
   64     const size_t ps = args->page_size;              \
   65     void *page_addr = (void *)((uintptr_t)addr & ~(ps - 1));    \
   66                                     \
   67     if (icache_madvise(args, addr, page_sz) < 0)            \
   68         return EXIT_NO_RESOURCE;                \
   69                                     \
   70     do {                                \
   71         register uint8_t val;                   \
   72         register int i = 1024;                  \
   73                                     \
   74         while (--i) {                       \
   75             volatile uint8_t *vaddr =           \
   76                 (volatile uint8_t *)addr;       \
   77             /*                      \
   78              *  Change protection to make page modifyable.  \
   79              *  It may be that some architectures don't     \
   80              *  allow this, so don't bail out on an     \
   81              *  EXIT_FAILURE; this is a not necessarily a   \
   82              *  fault in the the stressor, just an arch     \
   83              *  resource protection issue.          \
   84              */                     \
   85             if (mprotect((void *)page_addr, page_sz,    \
   86                 PROT_READ | PROT_WRITE) < 0) {      \
   87                 pr_inf("%s: PROT_WRITE mprotect failed "\
   88                     "on text page %p: errno=%d "    \
   89                     "(%s)\n", args->name, vaddr,    \
   90                     errno, strerror(errno));    \
   91                 return EXIT_NO_RESOURCE;        \
   92             }                       \
   93             /*                      \
   94              *  Modifying executable code on x86 will   \
   95              *  call a I-cache reload when we execute   \
   96              *  the modfied ops.                \
   97              */                     \
   98             val = *vaddr;                   \
   99             *vaddr ^= ~0;                   \
  100             /*                      \
  101              * ARM CPUs need us to clear the I$ between \
  102              * each modification of the object code.    \
  103              *                      \
  104              * We may need to do the same for other CPUs    \
  105              * as the default code assumes smart x86 style  \
  106              * I$ behaviour.                \
  107              */                     \
  108             shim_clear_cache((char *)addr, (char *)addr + 64);\
  109             *vaddr = val;                   \
  110             shim_clear_cache((char *)addr, (char *)addr + 64);\
  111             /*                      \
  112              *  Set back to a text segment READ/EXEC page   \
  113              *  attributes, this really should not fail.    \
  114              */                     \
  115             if (mprotect((void *)page_addr, page_sz,    \
  116                 PROT_READ | PROT_EXEC) < 0) {       \
  117                 pr_err("%s: mprotect failed: errno=%d " \
  118                     "(%s)\n", args->name, errno,    \
  119                     strerror(errno));       \
  120                 return EXIT_FAILURE;            \
  121             }                       \
  122             icache_func();                  \
  123             (void)shim_cacheflush((char *)addr, page_sz, ICACHE); \
  124         }                           \
  125         inc_counter(args);                  \
  126     } while (keep_stressing());                 \
  127                                     \
  128     return EXIT_SUCCESS;                        \
  129 }
  130 
  131 static inline int icache_madvise(const args_t *args, void *addr, size_t size)
  132 {
  133 #if defined(MADV_NOHUGEPAGE)
  134     if (shim_madvise((void *)addr, size, MADV_NOHUGEPAGE) < 0) {
  135         /*
  136          * We may get EINVAL on kernels that don't support this
  137          * so don't treat that as non-fatal as this is just advistory
  138          */
  139         if (errno != EINVAL) {
  140             pr_inf("%s: madvise MADV_NOHUGEPAGE failed on text "
  141                 "page %p: errno=%d (%s)\n",
  142                 args->name, addr, errno, strerror(errno));
  143             return -1;
  144         }
  145     }
  146 #else
  147     (void)args;
  148     (void)addr;
  149     (void)size;
  150 #endif
  151     return 0;
  152 }
  153 
  154 #if defined(HAVE_ALIGNED_64K)
  155 STRESS_ICACHE_FUNC(stress_icache_func_64K, SIZE_64K)
  156 #endif
  157 STRESS_ICACHE_FUNC(stress_icache_func_16K, SIZE_16K)
  158 STRESS_ICACHE_FUNC(stress_icache_func_4K, SIZE_4K)
  159 
  160 #if defined(HAVE_ALIGNED_64K)
  161 STRESS_ICACHE(stress_icache_64K, SIZE_64K, stress_icache_func_64K)
  162 #endif
  163 STRESS_ICACHE(stress_icache_16K, SIZE_16K, stress_icache_func_16K)
  164 STRESS_ICACHE(stress_icache_4K, SIZE_4K, stress_icache_func_4K)
  165 
  166 /*
  167  *  stress_icache()
  168  *  entry point for stress instruction cache load misses
  169  *
  170  *  I-cache load misses can be observed using:
  171  *      perf stat -e L1-icache-load-misses stress-ng --icache 0 -t 1
  172  */
  173 static int stress_icache(const args_t *args)
  174 {
  175         int ret;
  176 
  177     switch (args->page_size) {
  178     case SIZE_4K:
  179         ret = stress_icache_4K(args);
  180         break;
  181     case SIZE_16K:
  182         ret = stress_icache_16K(args);
  183         break;
  184 #if defined(HAVE_ALIGNED_64K)
  185     case SIZE_64K:
  186         ret = stress_icache_64K(args);
  187         break;
  188 #endif
  189     default:
  190 #if defined(HAVE_ALIGNED_64K)
  191         pr_inf("%s: page size %zu is not %u or %u or %u, cannot test\n",
  192             args->name, args->page_size,
  193             SIZE_4K, SIZE_16K, SIZE_64K);
  194 #else
  195         pr_inf("%s: page size %zu is not %u or %u, cannot test\n",
  196             args->name, args->page_size,
  197             SIZE_4K, SIZE_16K);
  198 #endif
  199         ret = EXIT_NO_RESOURCE;
  200     }
  201         return ret;
  202 }
  203 
  204 stressor_info_t stress_icache_info = {
  205     .stressor = stress_icache,
  206     .class = CLASS_CPU_CACHE
  207 };
  208 #else
  209 stressor_info_t stress_icache_info = {
  210     .stressor = stress_not_implemented,
  211     .class = CLASS_CPU_CACHE
  212 };
  213 #endif