xref: /aosp_15_r20/system/extras/tests/icachetest/Profiler.h (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
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