1 /** 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef PANDA_RUNTIME_TOOLING_PERF_COUNTER_H 17 #define PANDA_RUNTIME_TOOLING_PERF_COUNTER_H 18 19 #include <memory> 20 #include <vector> 21 #include <unordered_map> 22 #include <cstring> 23 #include <optional> 24 25 #include "libpandabase/os/time.h" 26 #include "libpandabase/utils/logger.h" 27 #include "libpandabase/utils/type_converter.h" 28 29 #include <unistd.h> 30 #include <linux/perf_event.h> 31 #include <linux/hw_breakpoint.h> 32 #include <sys/syscall.h> 33 #include <sys/ioctl.h> 34 35 namespace ark::tooling { 36 37 /* 38 See perf_counter.md 39 */ 40 41 class CounterValue { 42 public: 43 static CounterValue CreateUnavailable(); 44 static CounterValue CreateExact(uint64_t value); 45 static CounterValue CreateApprox(uint64_t value, double accuracy); 46 47 uint64_t GetValue() const; 48 bool IsExact() const; 49 bool IsAvailable() const; 50 double GetAccuracy() const; 51 52 private: 53 CounterValue(uint64_t value, bool exact, bool available, double accuracy); 54 uint64_t value_; 55 bool exact_; 56 bool available_; 57 double accuracy_; 58 }; 59 60 class CounterAccumulator { 61 public: 62 void Reset(); 63 void Add(uint64_t value); 64 void AddMissing(); 65 CounterValue GetValue() const; 66 bool IsAvailable() const; 67 bool HasMissing() const; 68 uint64_t GetExact() const; 69 uint64_t GetApprox() const; 70 double GetAccuracy() const; 71 72 private: 73 std::atomic_uint64_t value_ {}; 74 std::atomic_uint64_t missing_ {}; 75 std::atomic_uint64_t total_ {}; 76 }; 77 78 class PerfFileHandler { 79 public: 80 ~PerfFileHandler(); 81 82 NO_COPY_SEMANTIC(PerfFileHandler); 83 84 PerfFileHandler(PerfFileHandler &&other); 85 PerfFileHandler &operator=(PerfFileHandler &&other); 86 87 void Reset(); 88 void Enable(); 89 void Disable(); 90 91 std::optional<uint64_t> GetData() const; 92 93 private: 94 static int OpenDescriptor(uint32_t type, uint64_t config); 95 PerfFileHandler(uint32_t type, uint64_t config); 96 int fd_; 97 friend class PerfCounterDescriptor; 98 }; 99 100 class Perf; 101 class PerfCounterDescriptor; 102 103 class PerfCollector { 104 public: 105 NO_MOVE_SEMANTIC(PerfCollector); 106 NO_COPY_SEMANTIC(PerfCollector); 107 108 PerfCollector(Perf *p, std::vector<const PerfCounterDescriptor *> &list, bool isWallTime); 109 ~PerfCollector(); 110 111 void Reset(); 112 void Enable(); 113 void Disable(); 114 115 private: 116 Perf *perf_; 117 std::unordered_map<const PerfCounterDescriptor *, PerfFileHandler> counters_; 118 bool isWallTime_ {false}; 119 uint64_t startTime_; 120 }; 121 122 class CounterReporter; 123 124 class PerfCounterDescriptor { 125 public: 126 NO_COPY_SEMANTIC(PerfCounterDescriptor); 127 NO_MOVE_SEMANTIC(PerfCounterDescriptor); 128 129 ~PerfCounterDescriptor() = default; 130 131 PerfFileHandler CreatePerfFileHandler() const; 132 133 const char *GetName() const; 134 void Report(std::ostream &out, const Perf *p) const; 135 136 static const PerfCounterDescriptor TASK_CLOCK; 137 static const PerfCounterDescriptor CONTEXT_SWITCHES; 138 static const PerfCounterDescriptor CPU_MIGRATION; 139 static const PerfCounterDescriptor PAGE_FAULT; 140 static const PerfCounterDescriptor TOTAL_CPU_CYCLES; 141 static const PerfCounterDescriptor STALLED_FRONTEND_CYCLES; 142 static const PerfCounterDescriptor STALLED_BACKEND_CYCLES; 143 static const PerfCounterDescriptor INSTRUCTIONS_COUNT; 144 static const PerfCounterDescriptor BRANCHES; 145 static const PerfCounterDescriptor BRANCH_MISSES; 146 static const PerfCounterDescriptor COUNT; 147 148 private: 149 PerfCounterDescriptor(const char *name, uint32_t type, uint64_t config, std::unique_ptr<CounterReporter> reporter); 150 151 const char *name_; 152 uint32_t type_; 153 uint64_t config_; 154 std::unique_ptr<CounterReporter> reporter_; 155 }; 156 157 class Perf { 158 public: 159 Perf(); 160 Perf(std::initializer_list<const PerfCounterDescriptor *> list); 161 ~Perf() = default; 162 163 NO_COPY_SEMANTIC(Perf); 164 NO_MOVE_SEMANTIC(Perf); 165 166 PerfCollector CreateCollector(bool isWallTime = false); 167 void Reset(); 168 void Add(const PerfCounterDescriptor *desc, uint64_t value); 169 void AddMissing(const PerfCounterDescriptor *desc); 170 void AddWallTime(uint64_t time); 171 CounterValue Get(const PerfCounterDescriptor *desc) const; 172 void Report(std::ostream &out) const; 173 174 private: 175 std::vector<const PerfCounterDescriptor *> perfDescriptors_; 176 std::unordered_map<const PerfCounterDescriptor *, CounterAccumulator> counters_; 177 uint64_t wallTime_ {0}; 178 }; 179 180 std::ostream &operator<<(std::ostream &out, const Perf &p); 181 182 extern Perf g_perf; 183 } // namespace ark::tooling 184 185 #endif 186