Home | History | Annotate | Download | only in icachetest
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "Profiler.h"
     18 
     19 #include <stdlib.h>
     20 #include <string.h>
     21 #include <unistd.h>
     22 
     23 #include <algorithm>
     24 #include <iostream>
     25 
     26 #if defined(__linux__)
     27 
     28 #include <sys/syscall.h>
     29 
     30 #ifdef __ARM_ARCH
     31     enum ARMv8PmuPerfTypes{
     32         // Common micro-architecture events
     33         ARMV8_PMUV3_PERFCTR_L1_ICACHE_REFILL    = 0x01,
     34         ARMV8_PMUV3_PERFCTR_L1_ICACHE_ACCESS    = 0x14,
     35         ARMV8_PMUV3_PERFCTR_L2_CACHE_ACCESS     = 0x16,
     36         ARMV8_PMUV3_PERFCTR_L2_CACHE_REFILL     = 0x17,
     37         ARMV8_PMUV3_PERFCTR_L2_CACHE_WB         = 0x18,
     38     };
     39 #endif
     40 
     41 static int perf_event_open(struct perf_event_attr* hw_event, pid_t pid,
     42         int cpu, int group_fd, unsigned long flags) {
     43     return syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags);
     44 }
     45 
     46 #endif // __linux__
     47 
     48 namespace utils {
     49 
     50 Profiler& Profiler::get() noexcept {
     51     static Profiler sProfiler;
     52     return sProfiler;
     53 }
     54 
     55 Profiler::Profiler() noexcept {
     56     std::uninitialized_fill(mCountersFd.begin(), mCountersFd.end(), -1);
     57     Profiler::resetEvents(EV_CPU_CYCLES | EV_L1D_RATES | EV_BPU_RATES);
     58 }
     59 
     60 Profiler::~Profiler() noexcept {
     61     for (int fd : mCountersFd) {
     62         if (fd >= 0) {
     63             close(fd);
     64         }
     65     }
     66 }
     67 
     68 uint32_t Profiler::resetEvents(uint32_t eventMask) noexcept {
     69     // close all counters
     70     for (int& fd : mCountersFd) {
     71         if (fd >= 0) {
     72             close(fd);
     73             fd = -1;
     74         }
     75     }
     76     mEnabledEvents = 0;
     77 
     78 #if defined(__linux__)
     79 
     80     struct perf_event_attr pe;
     81     memset(&pe, 0, sizeof(struct perf_event_attr));
     82     pe.type = PERF_TYPE_HARDWARE;
     83     pe.size = sizeof(struct perf_event_attr);
     84     pe.config = PERF_COUNT_HW_INSTRUCTIONS;
     85     pe.disabled = 1;
     86     pe.exclude_kernel = 1;
     87     pe.exclude_hv = 1;
     88     pe.read_format = PERF_FORMAT_GROUP |
     89                      PERF_FORMAT_ID |
     90                      PERF_FORMAT_TOTAL_TIME_ENABLED |
     91                      PERF_FORMAT_TOTAL_TIME_RUNNING;
     92 
     93     uint8_t count = 0;
     94     int fd = perf_event_open(&pe, 0, -1, -1, 0);
     95     if (fd >= 0) {
     96         const int groupFd = fd;
     97         mIds[INSTRUCTIONS] = count++;
     98         mCountersFd[INSTRUCTIONS] = fd;
     99 
    100         pe.read_format = PERF_FORMAT_GROUP | PERF_FORMAT_ID;
    101 
    102         if (eventMask & EV_CPU_CYCLES) {
    103             pe.type = PERF_TYPE_HARDWARE;
    104             pe.config = PERF_COUNT_HW_CPU_CYCLES;
    105             mCountersFd[CPU_CYCLES] = perf_event_open(&pe, 0, -1, groupFd, 0);
    106             if (mCountersFd[CPU_CYCLES] > 0) {
    107                 mIds[CPU_CYCLES] = count++;
    108                 mEnabledEvents |= EV_CPU_CYCLES;
    109             }
    110         }
    111 
    112         if (eventMask & EV_L1D_REFS) {
    113             pe.type = PERF_TYPE_HARDWARE;
    114             pe.config = PERF_COUNT_HW_CACHE_REFERENCES;
    115             mCountersFd[DCACHE_REFS] = perf_event_open(&pe, 0, -1, groupFd, 0);
    116             if (mCountersFd[DCACHE_REFS] > 0) {
    117                 mIds[DCACHE_REFS] = count++;
    118                 mEnabledEvents |= EV_L1D_REFS;
    119             }
    120         }
    121 
    122         if (eventMask & EV_L1D_MISSES) {
    123             pe.type = PERF_TYPE_HARDWARE;
    124             pe.config = PERF_COUNT_HW_CACHE_MISSES;
    125             mCountersFd[DCACHE_MISSES] = perf_event_open(&pe, 0, -1, groupFd, 0);
    126             if (mCountersFd[DCACHE_MISSES] > 0) {
    127                 mIds[DCACHE_MISSES] = count++;
    128                 mEnabledEvents |= EV_L1D_MISSES;
    129             }
    130         }
    131 
    132         if (eventMask & EV_BPU_REFS) {
    133             pe.type = PERF_TYPE_HARDWARE;
    134             pe.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS;
    135             mCountersFd[BRANCHES] = perf_event_open(&pe, 0, -1, groupFd, 0);
    136             if (mCountersFd[BRANCHES] > 0) {
    137                 mIds[BRANCHES] = count++;
    138                 mEnabledEvents |= EV_BPU_REFS;
    139             }
    140         }
    141 
    142         if (eventMask & EV_BPU_MISSES) {
    143             pe.type = PERF_TYPE_HARDWARE;
    144             pe.config = PERF_COUNT_HW_BRANCH_MISSES;
    145             mCountersFd[BRANCH_MISSES] = perf_event_open(&pe, 0, -1, groupFd, 0);
    146             if (mCountersFd[BRANCH_MISSES] > 0) {
    147                 mIds[BRANCH_MISSES] = count++;
    148                 mEnabledEvents |= EV_BPU_MISSES;
    149             }
    150         }
    151 
    152 #ifdef __ARM_ARCH
    153         if (eventMask & EV_L1I_REFS) {
    154             pe.type = PERF_TYPE_RAW;
    155             pe.config = ARMV8_PMUV3_PERFCTR_L1_ICACHE_ACCESS;
    156             mCountersFd[ICACHE_REFS] = perf_event_open(&pe, 0, -1, groupFd, 0);
    157             if (mCountersFd[ICACHE_REFS] > 0) {
    158                 mIds[ICACHE_REFS] = count++;
    159                 mEnabledEvents |= EV_L1I_REFS;
    160             }
    161         }
    162 
    163         if (eventMask & EV_L1I_MISSES) {
    164             pe.type = PERF_TYPE_RAW;
    165             pe.config = ARMV8_PMUV3_PERFCTR_L1_ICACHE_REFILL;
    166             mCountersFd[ICACHE_MISSES] = perf_event_open(&pe, 0, -1, groupFd, 0);
    167             if (mCountersFd[ICACHE_MISSES] > 0) {
    168                 mIds[ICACHE_MISSES] = count++;
    169                 mEnabledEvents |= EV_L1I_MISSES;
    170             }
    171         }
    172 #else
    173         if (eventMask & EV_L1I_REFS) {
    174             pe.type = PERF_TYPE_HW_CACHE;
    175             pe.config = PERF_COUNT_HW_CACHE_L1I |
    176                 (PERF_COUNT_HW_CACHE_OP_READ<<8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS<<16);
    177             mCountersFd[ICACHE_REFS] = perf_event_open(&pe, 0, -1, groupFd, 0);
    178             if (mCountersFd[ICACHE_REFS] > 0) {
    179                 mIds[ICACHE_REFS] = count++;
    180                 mEnabledEvents |= EV_L1I_REFS;
    181             }
    182         }
    183 
    184         if (eventMask & EV_L1I_MISSES) {
    185             pe.type = PERF_TYPE_HW_CACHE;
    186             pe.config = PERF_COUNT_HW_CACHE_L1I |
    187                 (PERF_COUNT_HW_CACHE_OP_READ<<8) | (PERF_COUNT_HW_CACHE_RESULT_MISS<<16);
    188             mCountersFd[ICACHE_MISSES] = perf_event_open(&pe, 0, -1, groupFd, 0);
    189             if (mCountersFd[ICACHE_MISSES] > 0) {
    190                 mIds[ICACHE_MISSES] = count++;
    191                 mEnabledEvents |= EV_L1I_MISSES;
    192             }
    193         }
    194 #endif
    195     }
    196 #endif // __linux__
    197     return mEnabledEvents;
    198 }
    199 
    200 } // namespace utils
    201