1*288bf522SAndroid Build Coastguard Worker /* 2*288bf522SAndroid Build Coastguard Worker * Copyright (C) 2016 The Android Open Source Project 3*288bf522SAndroid Build Coastguard Worker * 4*288bf522SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*288bf522SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*288bf522SAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*288bf522SAndroid Build Coastguard Worker * 8*288bf522SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*288bf522SAndroid Build Coastguard Worker * 10*288bf522SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*288bf522SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*288bf522SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*288bf522SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*288bf522SAndroid Build Coastguard Worker * limitations under the License. 15*288bf522SAndroid Build Coastguard Worker */ 16*288bf522SAndroid Build Coastguard Worker 17*288bf522SAndroid Build Coastguard Worker #ifndef TNT_UTILS_PROFILER_H 18*288bf522SAndroid Build Coastguard Worker #define TNT_UTILS_PROFILER_H 19*288bf522SAndroid Build Coastguard Worker 20*288bf522SAndroid Build Coastguard Worker #include <assert.h> 21*288bf522SAndroid Build Coastguard Worker #include <stdint.h> 22*288bf522SAndroid Build Coastguard Worker 23*288bf522SAndroid Build Coastguard Worker #include <array> 24*288bf522SAndroid Build Coastguard Worker #include <chrono> 25*288bf522SAndroid Build Coastguard Worker 26*288bf522SAndroid Build Coastguard Worker #if defined(__linux__) 27*288bf522SAndroid Build Coastguard Worker # include <unistd.h> 28*288bf522SAndroid Build Coastguard Worker # include <sys/ioctl.h> 29*288bf522SAndroid Build Coastguard Worker # include <linux/perf_event.h> 30*288bf522SAndroid Build Coastguard Worker #endif 31*288bf522SAndroid Build Coastguard Worker 32*288bf522SAndroid Build Coastguard Worker namespace utils { 33*288bf522SAndroid Build Coastguard Worker 34*288bf522SAndroid Build Coastguard Worker class Profiler { 35*288bf522SAndroid Build Coastguard Worker enum { 36*288bf522SAndroid Build Coastguard Worker INSTRUCTIONS = 0, // must be zero 37*288bf522SAndroid Build Coastguard Worker CPU_CYCLES = 1, 38*288bf522SAndroid Build Coastguard Worker DCACHE_REFS = 2, 39*288bf522SAndroid Build Coastguard Worker DCACHE_MISSES = 3, 40*288bf522SAndroid Build Coastguard Worker BRANCHES = 4, 41*288bf522SAndroid Build Coastguard Worker BRANCH_MISSES = 5, 42*288bf522SAndroid Build Coastguard Worker ICACHE_REFS = 6, 43*288bf522SAndroid Build Coastguard Worker ICACHE_MISSES = 7, 44*288bf522SAndroid Build Coastguard Worker 45*288bf522SAndroid Build Coastguard Worker // Must be last one 46*288bf522SAndroid Build Coastguard Worker EVENT_COUNT 47*288bf522SAndroid Build Coastguard Worker }; 48*288bf522SAndroid Build Coastguard Worker 49*288bf522SAndroid Build Coastguard Worker public: 50*288bf522SAndroid Build Coastguard Worker 51*288bf522SAndroid Build Coastguard Worker enum { 52*288bf522SAndroid Build Coastguard Worker EV_CPU_CYCLES = 1 << CPU_CYCLES, 53*288bf522SAndroid Build Coastguard Worker EV_L1D_REFS = 1 << DCACHE_REFS, 54*288bf522SAndroid Build Coastguard Worker EV_L1D_MISSES = 1 << DCACHE_MISSES, 55*288bf522SAndroid Build Coastguard Worker EV_BPU_REFS = 1 << BRANCHES, 56*288bf522SAndroid Build Coastguard Worker EV_BPU_MISSES = 1 << BRANCH_MISSES, 57*288bf522SAndroid Build Coastguard Worker EV_L1I_REFS = 1 << ICACHE_REFS, 58*288bf522SAndroid Build Coastguard Worker EV_L1I_MISSES = 1 << ICACHE_MISSES, 59*288bf522SAndroid Build Coastguard Worker // helpers 60*288bf522SAndroid Build Coastguard Worker EV_L1D_RATES = EV_L1D_REFS | EV_L1D_MISSES, 61*288bf522SAndroid Build Coastguard Worker EV_L1I_RATES = EV_L1I_REFS | EV_L1I_MISSES, 62*288bf522SAndroid Build Coastguard Worker EV_BPU_RATES = EV_BPU_REFS | EV_BPU_MISSES, 63*288bf522SAndroid Build Coastguard Worker }; 64*288bf522SAndroid Build Coastguard Worker 65*288bf522SAndroid Build Coastguard Worker static Profiler& get() noexcept; 66*288bf522SAndroid Build Coastguard Worker 67*288bf522SAndroid Build Coastguard Worker 68*288bf522SAndroid Build Coastguard Worker Profiler(const Profiler& rhs) = delete; 69*288bf522SAndroid Build Coastguard Worker Profiler(Profiler&& rhs) = delete; 70*288bf522SAndroid Build Coastguard Worker Profiler& operator=(const Profiler& rhs) = delete; 71*288bf522SAndroid Build Coastguard Worker Profiler& operator=(Profiler&& rhs) = delete; 72*288bf522SAndroid Build Coastguard Worker 73*288bf522SAndroid Build Coastguard Worker // selects which events are enabled. 74*288bf522SAndroid Build Coastguard Worker // By Default: EV_CPU_CYCLES | EV_L1D_RATES | EV_BPU_RATES 75*288bf522SAndroid Build Coastguard Worker uint32_t resetEvents(uint32_t eventMask) noexcept; 76*288bf522SAndroid Build Coastguard Worker getEnabledEvents()77*288bf522SAndroid Build Coastguard Worker uint32_t getEnabledEvents() const noexcept { return mEnabledEvents; } 78*288bf522SAndroid Build Coastguard Worker 79*288bf522SAndroid Build Coastguard Worker // could return false if performance counters are not supported/enabled isValid()80*288bf522SAndroid Build Coastguard Worker bool isValid() const { return mCountersFd[0] >= 0; } 81*288bf522SAndroid Build Coastguard Worker 82*288bf522SAndroid Build Coastguard Worker class Counters { 83*288bf522SAndroid Build Coastguard Worker friend class Profiler; 84*288bf522SAndroid Build Coastguard Worker uint64_t nr; 85*288bf522SAndroid Build Coastguard Worker uint64_t time_enabled; 86*288bf522SAndroid Build Coastguard Worker uint64_t time_running; 87*288bf522SAndroid Build Coastguard Worker struct { 88*288bf522SAndroid Build Coastguard Worker uint64_t value; 89*288bf522SAndroid Build Coastguard Worker uint64_t id; 90*288bf522SAndroid Build Coastguard Worker } counters[Profiler::EVENT_COUNT]; 91*288bf522SAndroid Build Coastguard Worker 92*288bf522SAndroid Build Coastguard Worker friend Counters operator-(Counters lhs, const Counters& rhs) noexcept { 93*288bf522SAndroid Build Coastguard Worker lhs.nr -= rhs.nr; 94*288bf522SAndroid Build Coastguard Worker lhs.time_enabled -= rhs.time_enabled; 95*288bf522SAndroid Build Coastguard Worker lhs.time_running -= rhs.time_running; 96*288bf522SAndroid Build Coastguard Worker for (size_t i=0 ; i<EVENT_COUNT ; ++i) { 97*288bf522SAndroid Build Coastguard Worker lhs.counters[i].value -= rhs.counters[i].value; 98*288bf522SAndroid Build Coastguard Worker } 99*288bf522SAndroid Build Coastguard Worker return lhs; 100*288bf522SAndroid Build Coastguard Worker } 101*288bf522SAndroid Build Coastguard Worker 102*288bf522SAndroid Build Coastguard Worker public: getInstructions()103*288bf522SAndroid Build Coastguard Worker uint64_t getInstructions() const { return counters[INSTRUCTIONS].value; } getCpuCycles()104*288bf522SAndroid Build Coastguard Worker uint64_t getCpuCycles() const { return counters[CPU_CYCLES].value; } getL1DReferences()105*288bf522SAndroid Build Coastguard Worker uint64_t getL1DReferences() const { return counters[DCACHE_REFS].value; } getL1DMisses()106*288bf522SAndroid Build Coastguard Worker uint64_t getL1DMisses() const { return counters[DCACHE_MISSES].value; } getL1IReferences()107*288bf522SAndroid Build Coastguard Worker uint64_t getL1IReferences() const { return counters[ICACHE_REFS].value; } getL1IMisses()108*288bf522SAndroid Build Coastguard Worker uint64_t getL1IMisses() const { return counters[ICACHE_MISSES].value; } getBranchInstructions()109*288bf522SAndroid Build Coastguard Worker uint64_t getBranchInstructions() const { return counters[BRANCHES].value; } getBranchMisses()110*288bf522SAndroid Build Coastguard Worker uint64_t getBranchMisses() const { return counters[BRANCH_MISSES].value; } 111*288bf522SAndroid Build Coastguard Worker getWallTime()112*288bf522SAndroid Build Coastguard Worker std::chrono::duration<uint64_t, std::nano> getWallTime() const { 113*288bf522SAndroid Build Coastguard Worker return std::chrono::duration<uint64_t, std::nano>(time_enabled); 114*288bf522SAndroid Build Coastguard Worker } 115*288bf522SAndroid Build Coastguard Worker getRunningTime()116*288bf522SAndroid Build Coastguard Worker std::chrono::duration<uint64_t, std::nano> getRunningTime() const { 117*288bf522SAndroid Build Coastguard Worker return std::chrono::duration<uint64_t, std::nano>(time_running); 118*288bf522SAndroid Build Coastguard Worker } 119*288bf522SAndroid Build Coastguard Worker getIPC()120*288bf522SAndroid Build Coastguard Worker double getIPC() const noexcept { 121*288bf522SAndroid Build Coastguard Worker uint64_t cpuCycles = getCpuCycles(); 122*288bf522SAndroid Build Coastguard Worker uint64_t instructions = getInstructions(); 123*288bf522SAndroid Build Coastguard Worker return double(instructions) / double(cpuCycles); 124*288bf522SAndroid Build Coastguard Worker } 125*288bf522SAndroid Build Coastguard Worker getCPI()126*288bf522SAndroid Build Coastguard Worker double getCPI() const noexcept { 127*288bf522SAndroid Build Coastguard Worker uint64_t cpuCycles = getCpuCycles(); 128*288bf522SAndroid Build Coastguard Worker uint64_t instructions = getInstructions(); 129*288bf522SAndroid Build Coastguard Worker return double(cpuCycles) / double(instructions); 130*288bf522SAndroid Build Coastguard Worker } 131*288bf522SAndroid Build Coastguard Worker getL1DMissRate()132*288bf522SAndroid Build Coastguard Worker double getL1DMissRate() const noexcept { 133*288bf522SAndroid Build Coastguard Worker uint64_t cacheReferences = getL1DReferences(); 134*288bf522SAndroid Build Coastguard Worker uint64_t cacheMisses = getL1DMisses(); 135*288bf522SAndroid Build Coastguard Worker return double(cacheMisses) / double(cacheReferences); 136*288bf522SAndroid Build Coastguard Worker } 137*288bf522SAndroid Build Coastguard Worker getL1DHitRate()138*288bf522SAndroid Build Coastguard Worker double getL1DHitRate() const noexcept { 139*288bf522SAndroid Build Coastguard Worker return 1.0 - getL1DMissRate(); 140*288bf522SAndroid Build Coastguard Worker } 141*288bf522SAndroid Build Coastguard Worker getL1IMissRate()142*288bf522SAndroid Build Coastguard Worker double getL1IMissRate() const noexcept { 143*288bf522SAndroid Build Coastguard Worker uint64_t cacheReferences = getL1IReferences(); 144*288bf522SAndroid Build Coastguard Worker uint64_t cacheMisses = getL1IMisses(); 145*288bf522SAndroid Build Coastguard Worker return double(cacheMisses) / double(cacheReferences); 146*288bf522SAndroid Build Coastguard Worker } 147*288bf522SAndroid Build Coastguard Worker getL1IHitRate()148*288bf522SAndroid Build Coastguard Worker double getL1IHitRate() const noexcept { 149*288bf522SAndroid Build Coastguard Worker return 1.0 - getL1IMissRate(); 150*288bf522SAndroid Build Coastguard Worker } 151*288bf522SAndroid Build Coastguard Worker getBranchMissRate()152*288bf522SAndroid Build Coastguard Worker double getBranchMissRate() const noexcept { 153*288bf522SAndroid Build Coastguard Worker uint64_t branchReferences = getBranchInstructions(); 154*288bf522SAndroid Build Coastguard Worker uint64_t branchMisses = getBranchMisses(); 155*288bf522SAndroid Build Coastguard Worker return double(branchMisses) / double(branchReferences); 156*288bf522SAndroid Build Coastguard Worker } 157*288bf522SAndroid Build Coastguard Worker getBranchHitRate()158*288bf522SAndroid Build Coastguard Worker double getBranchHitRate() const noexcept { 159*288bf522SAndroid Build Coastguard Worker return 1.0 - getBranchMissRate(); 160*288bf522SAndroid Build Coastguard Worker } 161*288bf522SAndroid Build Coastguard Worker getMPKI(uint64_t misses)162*288bf522SAndroid Build Coastguard Worker double getMPKI(uint64_t misses) const noexcept { 163*288bf522SAndroid Build Coastguard Worker return (misses * 1000.0) / getInstructions(); 164*288bf522SAndroid Build Coastguard Worker } 165*288bf522SAndroid Build Coastguard Worker 166*288bf522SAndroid Build Coastguard Worker }; 167*288bf522SAndroid Build Coastguard Worker 168*288bf522SAndroid Build Coastguard Worker #if defined(__linux__) 169*288bf522SAndroid Build Coastguard Worker reset()170*288bf522SAndroid Build Coastguard Worker void reset() noexcept { 171*288bf522SAndroid Build Coastguard Worker int fd = mCountersFd[0]; 172*288bf522SAndroid Build Coastguard Worker ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP); 173*288bf522SAndroid Build Coastguard Worker } 174*288bf522SAndroid Build Coastguard Worker start()175*288bf522SAndroid Build Coastguard Worker void start() noexcept { 176*288bf522SAndroid Build Coastguard Worker int fd = mCountersFd[0]; 177*288bf522SAndroid Build Coastguard Worker ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP); 178*288bf522SAndroid Build Coastguard Worker } 179*288bf522SAndroid Build Coastguard Worker stop()180*288bf522SAndroid Build Coastguard Worker void stop() noexcept { 181*288bf522SAndroid Build Coastguard Worker int fd = mCountersFd[0]; 182*288bf522SAndroid Build Coastguard Worker ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP); 183*288bf522SAndroid Build Coastguard Worker } 184*288bf522SAndroid Build Coastguard Worker readCounters(Counters * outCounters)185*288bf522SAndroid Build Coastguard Worker void readCounters(Counters* outCounters) noexcept { 186*288bf522SAndroid Build Coastguard Worker Counters counters; 187*288bf522SAndroid Build Coastguard Worker ssize_t n = read(mCountersFd[0], &counters, sizeof(Counters)); 188*288bf522SAndroid Build Coastguard Worker memset(outCounters, 0, sizeof(Counters)); 189*288bf522SAndroid Build Coastguard Worker if (n > 0) { 190*288bf522SAndroid Build Coastguard Worker outCounters->nr = counters.nr; 191*288bf522SAndroid Build Coastguard Worker outCounters->time_enabled = counters.time_enabled; 192*288bf522SAndroid Build Coastguard Worker outCounters->time_running = counters.time_running; 193*288bf522SAndroid Build Coastguard Worker for (size_t i=0 ; i<size_t(EVENT_COUNT) ; i++) { 194*288bf522SAndroid Build Coastguard Worker if (mCountersFd[i] >= 0) { 195*288bf522SAndroid Build Coastguard Worker outCounters->counters[i] = counters.counters[mIds[i]]; 196*288bf522SAndroid Build Coastguard Worker } 197*288bf522SAndroid Build Coastguard Worker } 198*288bf522SAndroid Build Coastguard Worker } 199*288bf522SAndroid Build Coastguard Worker } 200*288bf522SAndroid Build Coastguard Worker 201*288bf522SAndroid Build Coastguard Worker #else // !__linux__ 202*288bf522SAndroid Build Coastguard Worker reset()203*288bf522SAndroid Build Coastguard Worker void reset() noexcept { } start()204*288bf522SAndroid Build Coastguard Worker void start() noexcept { } stop()205*288bf522SAndroid Build Coastguard Worker void stop() noexcept { } readCounters(Counters * counters)206*288bf522SAndroid Build Coastguard Worker void readCounters(Counters* counters) noexcept { } 207*288bf522SAndroid Build Coastguard Worker 208*288bf522SAndroid Build Coastguard Worker #endif // __linux__ 209*288bf522SAndroid Build Coastguard Worker hasBranchRates()210*288bf522SAndroid Build Coastguard Worker bool hasBranchRates() const noexcept { 211*288bf522SAndroid Build Coastguard Worker return (mCountersFd[BRANCHES] >= 0) && (mCountersFd[BRANCH_MISSES] >= 0); 212*288bf522SAndroid Build Coastguard Worker } 213*288bf522SAndroid Build Coastguard Worker hasICacheRates()214*288bf522SAndroid Build Coastguard Worker bool hasICacheRates() const noexcept { 215*288bf522SAndroid Build Coastguard Worker return (mCountersFd[ICACHE_REFS] >= 0) && (mCountersFd[ICACHE_MISSES] >= 0); 216*288bf522SAndroid Build Coastguard Worker } 217*288bf522SAndroid Build Coastguard Worker 218*288bf522SAndroid Build Coastguard Worker private: 219*288bf522SAndroid Build Coastguard Worker Profiler() noexcept; 220*288bf522SAndroid Build Coastguard Worker ~Profiler() noexcept; 221*288bf522SAndroid Build Coastguard Worker 222*288bf522SAndroid Build Coastguard Worker std::array<uint8_t, EVENT_COUNT> mIds; 223*288bf522SAndroid Build Coastguard Worker std::array<int, EVENT_COUNT> mCountersFd; 224*288bf522SAndroid Build Coastguard Worker uint32_t mEnabledEvents = 0; 225*288bf522SAndroid Build Coastguard Worker }; 226*288bf522SAndroid Build Coastguard Worker 227*288bf522SAndroid Build Coastguard Worker } // namespace utils 228*288bf522SAndroid Build Coastguard Worker 229*288bf522SAndroid Build Coastguard Worker #endif // TNT_UTILS_PROFILER_H 230