"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/core-perf.c" (15 Mar 2019, 19891 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 "core-perf.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.09.55_vs_0.09.56.

    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 #include "core-perf-event.h"
   27 
   28 #if defined(STRESS_PERF_STATS) &&   \
   29     defined(HAVE_LINUX_PERF_EVENT_H)
   30 /* perf enabled systems */
   31 
   32 #define THOUSAND    (1.0E3)
   33 #define MILLION     (1.0E6)
   34 #define BILLION     (1.0E9)
   35 #define TRILLION    (1.0E12)
   36 #define QUADRILLION (1.0E15)
   37 #define QUINTILLION (1.0E18)
   38 #define SEXTILLION  (1.0E21)
   39 #define SEPTILLION  (1.0E24)
   40 
   41 #define UNRESOLVED  (~0UL)
   42 
   43 /* used for table of perf events to gather */
   44 typedef struct {
   45     unsigned long type;     /* perf types */
   46     unsigned long config;       /* perf type specific config */
   47     char *path;         /* perf trace point path (only for trace points) */
   48     char *label;            /* human readable name for perf type */
   49 } perf_info_t;
   50 
   51 /* perf data */
   52 typedef struct {
   53     uint64_t counter;       /* perf counter */
   54     uint64_t time_enabled;      /* perf time enabled */
   55     uint64_t time_running;      /* perf time running */
   56 } perf_data_t;
   57 
   58 typedef struct {
   59     double      threshold;
   60     double      scale;
   61     char        *suffix;
   62 } perf_scale_t;
   63 
   64 /* Tracepoint */
   65 #define PERF_INFO_TP(path, label)   \
   66     { PERF_TYPE_TRACEPOINT, UNRESOLVED, path, label }
   67 
   68 /* Hardware */
   69 #define PERF_INFO_HW(config, label) \
   70     { PERF_TYPE_HARDWARE, PERF_COUNT_ ## config, NULL, label }
   71 
   72 /* Software */
   73 #define PERF_INFO_SW(config, label) \
   74     { PERF_TYPE_SOFTWARE, PERF_COUNT_ ## config, NULL, label }
   75 
   76 /* Hardware Cache */
   77 #define PERF_INFO_HW_C(cache_id, op_id, result_id, label)   \
   78     { PERF_TYPE_HW_CACHE,                   \
   79       (PERF_COUNT_HW_CACHE_ ## cache_id) |          \
   80       ((PERF_COUNT_HW_CACHE_OP_ ## op_id) << 8) |       \
   81       ((PERF_COUNT_HW_CACHE_RESULT_ ## result_id) << 16),   \
   82       NULL, label }
   83 
   84 #define STRESS_PERF_DEFINED(x) _SNG_PERF_COUNT_ ## x
   85 
   86 
   87 /*
   88  *  Perf scaling factors
   89  */
   90 static const perf_scale_t perf_scale[] = {
   91     { THOUSAND,     1.0,        "/sec" },
   92     { 100 * THOUSAND,   THOUSAND,   "K/sec" },
   93     { 100 * MILLION,    MILLION,    "M/sec" },
   94     { 100 * BILLION,    BILLION,    "B/sec" },
   95     { 100 * TRILLION,   TRILLION,   "T/sec" },
   96     { 100 * QUADRILLION,    QUADRILLION,    "P/sec" },
   97     { 100 * QUINTILLION,    QUINTILLION,    "E/sec" },
   98     { 100 * SEXTILLION, SEXTILLION, "Z/sec" },
   99     { 100 * SEPTILLION, SEPTILLION, "Y/sec" },
  100     { -1,           -1,     NULL }
  101 };
  102 
  103 /* perf counters to be read */
  104 static perf_info_t perf_info[STRESS_PERF_MAX] = {
  105     /*
  106      *  Hardware conters
  107      */
  108 #if STRESS_PERF_DEFINED(HW_CPU_CYCLES)
  109     PERF_INFO_HW(HW_CPU_CYCLES,     "CPU Cycles"),
  110 #endif
  111 #if STRESS_PERF_DEFINED(HW_INSTRUCTIONS)
  112     PERF_INFO_HW(HW_INSTRUCTIONS,       "Instructions"),
  113 #endif
  114 #if STRESS_PERF_DEFINED(HW_BRANCH_INSTRUCTIONS)
  115     PERF_INFO_HW(HW_BRANCH_INSTRUCTIONS,    "Branch Instructions"),
  116 #endif
  117 #if STRESS_PERF_DEFINED(HW_BRANCH_MISSES)
  118     PERF_INFO_HW(HW_BRANCH_MISSES,      "Branch Misses"),
  119 #endif
  120 #if STRESS_PERF_DEFINED(HW_STALLED_CYCLES_FRONTEND)
  121     PERF_INFO_HW(HW_STALLED_CYCLES_FRONTEND,"Stalled Cycles Frontend"),
  122 #endif
  123 #if STRESS_PERF_DEFINED(HW_STALLED_CYCLES_BACKEND)
  124     PERF_INFO_HW(HW_STALLED_CYCLES_BACKEND,"Stalled Cycles Backend"),
  125 #endif
  126 #if STRESS_PERF_DEFINED(HW_BUS_CYCLES)
  127     PERF_INFO_HW(HW_BUS_CYCLES,     "Bus Cycles"),
  128 #endif
  129 #if STRESS_PERF_DEFINED(HW_REF_CPU_CYCLES)
  130     PERF_INFO_HW(HW_REF_CPU_CYCLES,     "Total Cycles"),
  131 #endif
  132 
  133 #if STRESS_PERF_DEFINED(HW_CACHE_REFERENCES)
  134     PERF_INFO_HW(HW_CACHE_REFERENCES,   "Cache References"),
  135 #endif
  136 #if STRESS_PERF_DEFINED(HW_CACHE_MISSES)
  137     PERF_INFO_HW(HW_CACHE_MISSES,       "Cache Misses"),
  138 #endif
  139 
  140     /*
  141      *  Hardware Cache counters
  142      */
  143 #if STRESS_PERF_DEFINED(HW_CACHE_L1D)
  144     PERF_INFO_HW_C(L1D, READ, ACCESS,   "Cache L1D Read"),
  145     PERF_INFO_HW_C(L1D, READ, MISS,     "Cache L1D Read Miss"),
  146     PERF_INFO_HW_C(L1D, WRITE, ACCESS,  "Cache L1D Write"),
  147     PERF_INFO_HW_C(L1D, WRITE, MISS,    "Cache L1D Write Miss"),
  148     PERF_INFO_HW_C(L1D, PREFETCH, ACCESS,   "Cache L1D Prefetch"),
  149     PERF_INFO_HW_C(L1D, PREFETCH, MISS,     "Cache L1D Prefetch Miss"),
  150 #endif
  151 
  152 #if STRESS_PERF_DEFINED(HW_CACHE_L1I)
  153     PERF_INFO_HW_C(L1I, READ, ACCESS,   "Cache L1I Read"),
  154     PERF_INFO_HW_C(L1I, READ, MISS,     "Cache L1I Read Miss"),
  155     PERF_INFO_HW_C(L1I, WRITE, ACCESS,  "Cache L1I Write"),
  156     PERF_INFO_HW_C(L1I, WRITE, MISS,    "Cache L1I Write Miss"),
  157     PERF_INFO_HW_C(L1I, PREFETCH, ACCESS,   "Cache L1I Prefetch"),
  158     PERF_INFO_HW_C(L1I, PREFETCH, MISS, "Cache L1I Prefetch Miss"),
  159 #endif
  160 
  161 #if STRESS_PERF_DEFINED(HW_CACHE_LL)
  162     PERF_INFO_HW_C(LL, READ, ACCESS,    "Cache LL Read"),
  163     PERF_INFO_HW_C(LL, READ, MISS,      "Cache LL Read Miss"),
  164     PERF_INFO_HW_C(LL, WRITE, ACCESS,   "Cache LL Write"),
  165     PERF_INFO_HW_C(LL, WRITE, MISS,     "Cache LL Write Miss"),
  166     PERF_INFO_HW_C(LL, PREFETCH, ACCESS,    "Cache LL Prefetch"),
  167     PERF_INFO_HW_C(LL, PREFETCH, MISS,  "Cache LL Prefetch Miss"),
  168 #endif
  169 
  170 #if STRESS_PERF_DEFINED(HW_CACHE_DTLB)
  171     PERF_INFO_HW_C(DTLB, READ, ACCESS,  "Cache DTLB Read"),
  172     PERF_INFO_HW_C(DTLB, READ, MISS,    "Cache DTLB Read Miss"),
  173     PERF_INFO_HW_C(DTLB, WRITE, ACCESS,     "Cache DTLB Write"),
  174     PERF_INFO_HW_C(DTLB, WRITE, MISS,   "Cache DTLB Write Miss"),
  175     PERF_INFO_HW_C(DTLB, PREFETCH, ACCESS,  "Cache DTLB Prefetch"),
  176     PERF_INFO_HW_C(DTLB, PREFETCH, MISS,    "Cache DTLB Prefetch Miss"),
  177 #endif
  178 
  179 #if STRESS_PERF_DEFINED(HW_CACHE_ITLB)
  180     PERF_INFO_HW_C(ITLB, READ, ACCESS,  "Cache ITLB Read"),
  181     PERF_INFO_HW_C(ITLB, READ, MISS,    "Cache ITLB Read Miss"),
  182     PERF_INFO_HW_C(ITLB, WRITE, ACCESS, "Cache ITLB Write"),
  183     PERF_INFO_HW_C(ITLB, WRITE, MISS,   "Cache ITLB Write Miss"),
  184     PERF_INFO_HW_C(ITLB, PREFETCH, ACCESS,  "Cache ITLB Prefetch"),
  185     PERF_INFO_HW_C(ITLB, PREFETCH, MISS,    "Cache DILB Prefetch Miss"),
  186 #endif
  187 
  188 #if STRESS_PERF_DEFINED(HW_CACHE_BPU)
  189     PERF_INFO_HW_C(BPU, READ, ACCESS,   "Cache BPU Read"),
  190     PERF_INFO_HW_C(BPU, READ, MISS,     "Cache BPU Read Miss"),
  191     PERF_INFO_HW_C(BPU, WRITE, ACCESS,  "Cache BPU Write"),
  192     PERF_INFO_HW_C(BPU, WRITE, MISS,    "Cache BPU Write Miss"),
  193     PERF_INFO_HW_C(BPU, PREFETCH, ACCESS,   "Cache BPU Prefetch"),
  194     PERF_INFO_HW_C(BPU, PREFETCH, MISS, "Cache DILB Prefetch Miss"),
  195 #endif
  196 
  197 #if STRESS_PERF_DEFINED(HW_CACHE_NODE)
  198     PERF_INFO_HW_C(NODE, READ, ACCESS,  "Cache NODE Read"),
  199     PERF_INFO_HW_C(NODE, READ, MISS,    "Cache NODE Read Miss"),
  200     PERF_INFO_HW_C(NODE, WRITE, ACCESS, "Cache NODE Write"),
  201     PERF_INFO_HW_C(NODE, WRITE, MISS,   "Cache NODE Write Miss"),
  202     PERF_INFO_HW_C(NODE, PREFETCH, ACCESS,  "Cache NODE Prefetch"),
  203     PERF_INFO_HW_C(NODE, PREFETCH, MISS,    "Cache DILB Prefetch Miss"),
  204 #endif
  205 
  206     /*
  207      *  Software counters
  208      */
  209 #if STRESS_PERF_DEFINED(SW_CPU_CLOCK)
  210     PERF_INFO_SW(SW_CPU_CLOCK,      "CPU Clock"),
  211 #endif
  212 #if STRESS_PERF_DEFINED(SW_TASK_CLOCK)
  213     PERF_INFO_SW(SW_TASK_CLOCK,     "Task Clock"),
  214 #endif
  215 #if STRESS_PERF_DEFINED(SW_PAGE_FAULTS)
  216     PERF_INFO_SW(SW_PAGE_FAULTS,        "Page Faults Total"),
  217 #endif
  218 #if STRESS_PERF_DEFINED(SW_PAGE_FAULTS_MIN)
  219     PERF_INFO_SW(SW_PAGE_FAULTS_MIN,    "Page Faults Minor"),
  220 #endif
  221 #if STRESS_PERF_DEFINED(SW_PAGE_FAULTS_MAJ)
  222     PERF_INFO_SW(SW_PAGE_FAULTS_MAJ,    "Page Faults Major"),
  223 #endif
  224 #if STRESS_PERF_DEFINED(SW_CONTEXT_SWITCHES)
  225     PERF_INFO_SW(SW_CONTEXT_SWITCHES,   "Context Switches"),
  226 #endif
  227 #if STRESS_PERF_DEFINED(SW_CPU_MIGRATIONS)
  228     PERF_INFO_SW(SW_CPU_MIGRATIONS, "CPU Migrations"),
  229 #endif
  230 #if STRESS_PERF_DEFINED(SW_ALIGNMENT_FAULTS)
  231     PERF_INFO_SW(SW_ALIGNMENT_FAULTS,   "Alignment Faults"),
  232 #endif
  233 #if STRESS_PERF_DEFINED(SW_EMULATION_FAULTS)
  234     PERF_INFO_SW(SW_EMULATION_FAULTS,   "Emulation Faults"),
  235 #endif
  236 
  237     /*
  238      *  Tracepoint counters
  239      */
  240     PERF_INFO_TP("exceptions/page_fault_user",  "Page Faults User"),
  241     PERF_INFO_TP("exceptions/page_fault_kernel",    "Page Faults Kernel"),
  242     PERF_INFO_TP("raw_syscalls/sys_enter",      "System Call Enter"),
  243     PERF_INFO_TP("raw_syscalls/sys_exit",       "System Call Exit"),
  244 
  245     PERF_INFO_TP("tlb/tlb_flush",           "TLB Flushes"),
  246     PERF_INFO_TP("kmem/kmalloc",            "Kmalloc"),
  247     PERF_INFO_TP("kmem/kmalloc_node",       "Kmalloc Node"),
  248     PERF_INFO_TP("kmem/kfree",          "Kfree"),
  249     PERF_INFO_TP("kmem/kmem_cache_alloc",       "Kmem Cache Alloc"),
  250     PERF_INFO_TP("kmem/kmem_cache_alloc_node",  "Kmem Cache Alloc Node"),
  251     PERF_INFO_TP("kmem/kmem_cache_free",        "Kmem Cache Free"),
  252     PERF_INFO_TP("kmem/mm_page_alloc",      "MM Page Alloc"),
  253     PERF_INFO_TP("kmem/mm_page_free",       "MM Page Free"),
  254 
  255     PERF_INFO_TP("rcu/rcu_utilization",     "RCU Utilization"),
  256 
  257     PERF_INFO_TP("sched/sched_migrate_task",    "Sched Migrate Task"),
  258     PERF_INFO_TP("sched/sched_move_numa",       "Sched Move NUMA"),
  259     PERF_INFO_TP("sched/sched_wakeup",      "Sched Wakeup"),
  260     PERF_INFO_TP("sched/sched_process_exec",    "Sched Proc Exec"),
  261     PERF_INFO_TP("sched/sched_process_exit",    "Sched Proc Exit"),
  262     PERF_INFO_TP("sched/sched_process_fork",    "Sched Proc Fork"),
  263     PERF_INFO_TP("sched/sched_process_free",    "Sched Proc Free"),
  264     PERF_INFO_TP("sched/sched_process_hang",    "Sched Proc Hang"),
  265     PERF_INFO_TP("sched/sched_process_wait",    "Sched Proc Wait"),
  266     PERF_INFO_TP("sched/sched_switch",      "Sched Switch"),
  267 
  268     PERF_INFO_TP("signal/signal_generate",      "Signal Generate"),
  269     PERF_INFO_TP("signal/signal_deliver",       "Signal Deliver"),
  270 
  271     PERF_INFO_TP("irq/irq_handler_entry",       "IRQ Entry"),
  272     PERF_INFO_TP("irq/irq_handler_exit",        "IRQ Exit"),
  273     PERF_INFO_TP("irq/softirq_entry",       "Soft IRQ Entry"),
  274     PERF_INFO_TP("irq/softirq_exit",        "Soft IRQ Exit"),
  275 
  276     PERF_INFO_TP("writeback/writeback_dirty_inode", "Writeback Dirty Inode"),
  277     PERF_INFO_TP("writeback/writeback_dirty_page",  "Writeback Dirty Page"),
  278 
  279     PERF_INFO_TP("migrate/mm_migrate_pages",    "Migrate MM Pages"),
  280 
  281     PERF_INFO_TP("skb/consume_skb",         "SKB Consume"),
  282     PERF_INFO_TP("skb/kfree_skb",           "SKB Kfree"),
  283 
  284     PERF_INFO_TP("iommu/io_page_fault",     "IOMMU IO Page Fault"),
  285     PERF_INFO_TP("iommu/map",           "IOMMU Map"),
  286     PERF_INFO_TP("iommu/unmap",         "IOMMU Unmap"),
  287 
  288     PERF_INFO_TP("filemap/mm_filemap_add_to_page_cache",        "Filemap page-cache add"),
  289     PERF_INFO_TP("filemap/mm_filemap_delete_from_page_cache",   "Filemap page-cache del"),
  290 
  291     PERF_INFO_TP("oom/compact_retry",       "OOM Compact Retry"),
  292     PERF_INFO_TP("oom/wake_reaper",         "OOM Wake Reaper"),
  293 
  294     PERF_INFO_TP("thermal/thermal_zone_trip",   "Thermal Zone Trip"),
  295 
  296     { 0, 0, NULL, NULL }
  297 };
  298 
  299 static inline void perf_type_tracepoint_resolve_config(perf_info_t *pi)
  300 {
  301     char path[PATH_MAX];
  302     unsigned long config;
  303     FILE *fp;
  304 
  305     if (!pi->path)
  306         return;
  307 
  308     (void)snprintf(path, sizeof(path), "/sys/kernel/debug/tracing/events/%s/id",
  309         pi->path);
  310     if ((fp = fopen(path, "r")) == NULL)
  311         return;
  312     if (fscanf(fp, "%lu", &config) != 1) {
  313         (void)fclose(fp);
  314         return;
  315     }
  316     (void)fclose(fp);
  317 
  318     pi->config = config;
  319 }
  320 
  321 void perf_init(void)
  322 {
  323     size_t i;
  324 
  325     for (i = 0; i < STRESS_PERF_MAX; i++) {
  326         if (perf_info[i].type == PERF_TYPE_TRACEPOINT) {
  327             perf_type_tracepoint_resolve_config(&perf_info[i]);
  328         }
  329     }
  330 }
  331 
  332 static inline int sys_perf_event_open(
  333     struct perf_event_attr *attr,
  334     pid_t pid,
  335     int cpu,
  336     int group_fd,
  337     unsigned long flags)
  338 {
  339     return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
  340 }
  341 
  342 /*
  343  *  perf_yaml_label()
  344  *  turns text into a yaml compatible label.
  345  */
  346 static char *perf_yaml_label(char *dst, const char *src, const size_t n)
  347 {
  348     if (n) {
  349         char *d = dst;
  350         const char *s = src;
  351         size_t i = n;
  352 
  353         do {
  354             if (*s == ' ')
  355                 *d = '_';
  356             else if (isupper(*s))
  357                 *d = tolower(*s);
  358             else if (*s)
  359                 *d = *s;
  360             else {
  361                 while (--i != 0)
  362                     *d++ = 0;
  363                 break;
  364             }
  365             s++;
  366             d++;
  367         } while (--i != 0);
  368     }
  369     return dst;
  370 }
  371 
  372 /*
  373  *  perf_open()
  374  *  open perf, get leader and perf fd's
  375  */
  376 int perf_open(stress_perf_t *sp)
  377 {
  378     size_t i;
  379 
  380     if (!sp)
  381         return -1;
  382     if (g_shared->perf.no_perf)
  383         return -1;
  384 
  385     (void)memset(sp, 0, sizeof(*sp));
  386     sp->perf_opened = 0;
  387 
  388     for (i = 0; i < STRESS_PERF_MAX; i++) {
  389         sp->perf_stat[i].fd = -1;
  390         sp->perf_stat[i].counter = 0;
  391     }
  392 
  393     for (i = 0; i < STRESS_PERF_MAX && perf_info[i].label; i++) {
  394         if (perf_info[i].config != UNRESOLVED) {
  395             struct perf_event_attr attr;
  396 
  397             (void)memset(&attr, 0, sizeof(attr));
  398             attr.type = perf_info[i].type;
  399             attr.config = perf_info[i].config;
  400             attr.disabled = 1;
  401             attr.inherit = 1;
  402             attr.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
  403                        PERF_FORMAT_TOTAL_TIME_RUNNING;
  404             attr.size = sizeof(attr);
  405             sp->perf_stat[i].fd =
  406                 sys_perf_event_open(&attr, 0, -1, -1, 0);
  407             if (sp->perf_stat[i].fd > -1)
  408                 sp->perf_opened++;
  409         }
  410     }
  411     if (!sp->perf_opened) {
  412         int ret;
  413 
  414         ret = shim_pthread_spin_lock(&g_shared->perf.lock);
  415         if (!ret) {
  416             pr_dbg("perf: spin lock on perf.lock failed: %d (%s)\n",
  417                 ret, strerror(ret));
  418             return -1;
  419         }
  420         if (!g_shared->perf.no_perf) {
  421             pr_dbg("perf: perf_event_open failed, no "
  422                 "perf events [%u]\n", getpid());
  423             g_shared->perf.no_perf = true;
  424         }
  425         ret = shim_pthread_spin_unlock(&g_shared->perf.lock);
  426         if (!ret) {
  427             pr_dbg("perf: spin unlock on perf.lock failed: %d (%s)\n",
  428                 ret, strerror(ret));
  429             return -1;
  430         }
  431         return -1;
  432     }
  433 
  434     return 0;
  435 }
  436 
  437 /*
  438  *  perf_enable()
  439  *  enable perf counters
  440  */
  441 int perf_enable(stress_perf_t *sp)
  442 {
  443     size_t i;
  444 
  445     if (!sp)
  446         return -1;
  447     if (!sp->perf_opened)
  448         return 0;
  449 
  450     for (i = 0; i < STRESS_PERF_MAX && perf_info[i].label; i++) {
  451         int fd = sp->perf_stat[i].fd;
  452 
  453         if (fd > -1) {
  454             if (ioctl(fd, PERF_EVENT_IOC_RESET,
  455                   PERF_IOC_FLAG_GROUP) < 0) {
  456                 (void)close(fd);
  457                 sp->perf_stat[i].fd = -1;
  458                 continue;
  459             }
  460             if (ioctl(fd, PERF_EVENT_IOC_ENABLE,
  461                   PERF_IOC_FLAG_GROUP) < 0) {
  462                 (void)close(fd);
  463                 sp->perf_stat[i].fd = -1;
  464             }
  465         }
  466     }
  467     return 0;
  468 }
  469 
  470 /*
  471  *  perf_disable()
  472  *  disable perf counters
  473  */
  474 int perf_disable(stress_perf_t *sp)
  475 {
  476     size_t i;
  477 
  478     if (!sp)
  479         return -1;
  480     if (!sp->perf_opened)
  481         return 0;
  482 
  483     for (i = 0; i < STRESS_PERF_MAX && perf_info[i].label; i++) {
  484         int fd = sp->perf_stat[i].fd;
  485 
  486         if (fd > -1) {
  487             if (ioctl(fd, PERF_EVENT_IOC_DISABLE,
  488                       PERF_IOC_FLAG_GROUP) < 0) {
  489                 (void)close(fd);
  490                 sp->perf_stat[i].fd = -1;
  491             }
  492         }
  493     }
  494     return 0;
  495 }
  496 
  497 /*
  498  *  perf_close()
  499  *  read counters and close
  500  */
  501 int perf_close(stress_perf_t *sp)
  502 {
  503     size_t i = 0;
  504     perf_data_t data;
  505     ssize_t ret;
  506     int rc = -1;
  507     double scale;
  508 
  509     if (!sp)
  510         return -1;
  511     if (!sp->perf_opened)
  512         goto out_ok;
  513 
  514     for (i = 0; i < STRESS_PERF_MAX && perf_info[i].label; i++) {
  515         int fd = sp->perf_stat[i].fd;
  516         if (fd < 0 ) {
  517             sp->perf_stat[i].counter = STRESS_PERF_INVALID;
  518             continue;
  519         }
  520 
  521         (void)memset(&data, 0, sizeof(data));
  522         ret = read(fd, &data, sizeof(data));
  523         if (ret != sizeof(data))
  524             sp->perf_stat[i].counter = STRESS_PERF_INVALID;
  525         else {
  526             /* Ensure we don't get division by zero */
  527             if (data.time_running == 0) {
  528                 scale = (data.time_enabled == 0) ? 1.0 : 0.0;
  529             } else {
  530                 scale = (double)data.time_enabled /
  531                     data.time_running;
  532             }
  533             sp->perf_stat[i].counter = (uint64_t)
  534                 ((double)data.counter * scale);
  535         }
  536         (void)close(fd);
  537         sp->perf_stat[i].fd = -1;
  538     }
  539 
  540 out_ok:
  541     rc = 0;
  542     for (; i < STRESS_PERF_MAX; i++)
  543         sp->perf_stat[i].counter = STRESS_PERF_INVALID;
  544 
  545     return rc;
  546 }
  547 
  548 /*
  549  *  perf_stat_succeeded()
  550  *  did perf event open work OK?
  551  */
  552 bool perf_stat_succeeded(const stress_perf_t *sp)
  553 {
  554     return sp->perf_opened > 0;
  555 }
  556 
  557 /*
  558  *  perf_stat_scale()
  559  *  scale a counter by duration seconds
  560  *  into a human readable form
  561  */
  562 static const char *perf_stat_scale(const uint64_t counter, const double duration)
  563 {
  564     static char buffer[40];
  565     char *suffix = "E/sec";
  566     double scale = QUINTILLION;
  567     size_t i;
  568 
  569     double scaled =
  570         duration > 0.0 ? (double)counter / duration : 0.0;
  571 
  572     for (i = 0; perf_scale[i].suffix; i++) {
  573         if (scaled < perf_scale[i].threshold) {
  574             suffix = perf_scale[i].suffix;
  575             scale = perf_scale[i].scale;
  576             break;
  577         }
  578     }
  579     scaled /= scale;
  580 
  581     (void)snprintf(buffer, sizeof(buffer), "%11.2f %-5s",
  582         scaled, suffix);
  583 
  584     return buffer;
  585 }
  586 
  587 void perf_stat_dump(FILE *yaml, proc_info_t *procs_head, const double duration)
  588 {
  589     bool no_perf_stats = true;
  590     proc_info_t *pi;
  591 
  592 #if defined(HAVE_LOCALE_H)
  593     (void)setlocale(LC_ALL, "");
  594 #endif
  595 
  596     pr_yaml(yaml, "perfstats:\n");
  597 
  598     for (pi = procs_head; pi; pi = pi->next) {
  599         int p;
  600         uint64_t counter_totals[STRESS_PERF_MAX];
  601         uint64_t total_cpu_cycles = 0;
  602         uint64_t total_cache_refs = 0;
  603         uint64_t total_branches = 0;
  604         bool got_data = false;
  605         char *munged;
  606 
  607         (void)memset(counter_totals, 0, sizeof(counter_totals));
  608 
  609         /* Sum totals across all instances of the stressor */
  610         for (p = 0; p < STRESS_PERF_MAX && perf_info[p].label; p++) {
  611             int32_t j;
  612             stress_perf_t *sp = &pi->stats[0]->sp;
  613 
  614             if (!perf_stat_succeeded(sp))
  615                 continue;
  616 
  617             for (j = 0; j < pi->started_procs; j++) {
  618                 const uint64_t counter = sp->perf_stat[p].counter;
  619 
  620                 if (counter == STRESS_PERF_INVALID) {
  621                     counter_totals[p] = STRESS_PERF_INVALID;
  622                     break;
  623                 }
  624                 counter_totals[p] += counter;
  625                 got_data |= (counter > 0);
  626             }
  627             if (perf_info[p].type == PERF_TYPE_HARDWARE) {
  628                 unsigned long config = perf_info[p].config;
  629 
  630                 if (config == PERF_COUNT_HW_CPU_CYCLES)
  631                     total_cpu_cycles = counter_totals[p];
  632                 else if (config == PERF_COUNT_HW_CACHE_REFERENCES)
  633                     total_cache_refs = counter_totals[p];
  634                 else if (config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS)
  635                     total_branches = counter_totals[p];
  636             }
  637         }
  638 
  639         if (!got_data)
  640             continue;
  641 
  642         munged = stress_munge_underscore(pi->stressor->name);
  643         pr_inf("%s:\n", munged);
  644         pr_yaml(yaml, "    - stressor: %s\n", munged);
  645         pr_yaml(yaml, "      duration: %f\n", duration);
  646 
  647         for (p = 0; p < STRESS_PERF_MAX && perf_info[p].label; p++) {
  648             const char *l = perf_info[p].label;
  649             uint64_t ct = counter_totals[p];
  650 
  651             if (l && (ct != STRESS_PERF_INVALID)) {
  652                 char extra[32];
  653                 char yaml_label[128];
  654                 *extra = '\0';
  655 
  656                 no_perf_stats = false;
  657 
  658                 if (perf_info[p].type == PERF_TYPE_HARDWARE) {
  659                     unsigned long config = perf_info[p].config;
  660                     if ((config == PERF_COUNT_HW_INSTRUCTIONS) &&
  661                         (total_cpu_cycles > 0))
  662                         (void)snprintf(extra, sizeof(extra),
  663                             " (%.3f instr. per cycle)",
  664                             (double)ct / (double)total_cpu_cycles);
  665                     else if ((config == PERF_COUNT_HW_CACHE_MISSES) &&
  666                          (total_cache_refs > 0))
  667                         (void)snprintf(extra, sizeof(extra),
  668                             " (%5.2f%%)",
  669                             100.0 * (double)ct / (double)total_cache_refs);
  670                     else if ((config == PERF_COUNT_HW_BRANCH_MISSES) &&
  671                         (total_branches > 0))
  672                         (void)snprintf(extra, sizeof(extra),
  673                             " (%5.2f%%)",
  674                             100.0 * (double)ct / (double)total_branches);
  675                 }
  676 
  677                 pr_inf("%'26" PRIu64 " %-24s %s%s\n",
  678                     ct, l, perf_stat_scale(ct, duration),
  679                     extra);
  680 
  681                 perf_yaml_label(yaml_label, l, sizeof(yaml_label));
  682                 pr_yaml(yaml, "      %s_total: %" PRIu64
  683                     "\n", yaml_label, ct);
  684                 pr_yaml(yaml, "      %s_per_second: %f\n",
  685                     yaml_label, (double)ct / duration);
  686             }
  687         }
  688         pr_yaml(yaml, "\n");
  689     }
  690     if (no_perf_stats) {
  691         if (geteuid() != 0) {
  692             char buffer[64];
  693             int ret;
  694             bool paranoid = false;
  695             int level = 0;
  696             static char *path = "/proc/sys/kernel/perf_event_paranoid";
  697 
  698             ret = system_read(path, buffer, sizeof(buffer) - 1);
  699             if (ret > 0) {
  700                 if (sscanf(buffer, "%5d", &level) == 1)
  701                     paranoid = true;
  702             }
  703             if (paranoid & (level > 1)) {
  704                 pr_inf("Cannot read perf counters, "
  705                     "do not have CAP_SYS_ADMIN capability "
  706                     "or %s is set too high (%d)\n",
  707                     path, level);
  708             }
  709         } else {
  710             pr_inf("perf counters are not available "
  711                 "on this device\n");
  712         }
  713     }
  714 }
  715 #endif