1 /** 2 * Copyright (c) 2021-2022 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_DPROFILER_TRACE_H 17 #define PANDA_RUNTIME_DPROFILER_TRACE_H 18 19 #include "macros.h" 20 #include "include/mem/panda_containers.h" 21 #include "include/mem/panda_string.h" 22 #include "include/mem/panda_smart_pointers.h" 23 #include "include/runtime.h" 24 #include "include/runtime_notification.h" 25 #include "runtime/include/method.h" 26 #include "runtime/include/language_context.h" 27 #include "os/mutex.h" 28 #include <memory> 29 #include <string> 30 #include <unordered_set> 31 32 namespace panda { 33 34 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects) 35 extern os::memory::Mutex g_traceLock; 36 37 enum EventFlag { 38 TRACE_METHOD_ENTER = 0x00, 39 TRACE_METHOD_EXIT = 0x01, 40 TRACE_METHOD_UNWIND = 0x02, 41 }; 42 class Trace : public RuntimeListener { 43 public: 44 static constexpr size_t ENCODE_EVENT_BITS = 2; WriteDataByte(uint8_t * data,uint64_t value,uint8_t size)45 static void WriteDataByte(uint8_t *data, uint64_t value, uint8_t size) 46 { 47 for (uint8_t i = 0; i < size; i++) { 48 *data = static_cast<uint8_t>(value); 49 value = value >> WRITE_LENGTH; 50 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 51 data++; 52 } 53 } 54 GetDataFromBuffer(const uint8_t * buffer,size_t num)55 static uint64_t GetDataFromBuffer(const uint8_t *buffer, size_t num) 56 { 57 uint64_t data = 0; 58 for (size_t i = 0; i < num; i++) { 59 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic, readability-magic-numbers) 60 data |= static_cast<uint64_t>(buffer[i]) << (i * 8U); 61 } 62 return data; 63 } 64 65 static void StartTracing(const char *traceFilename, size_t bufferSize); 66 67 static void TriggerTracing(); 68 69 void MethodEntry(ManagedThread *thread, Method *method) override; 70 void MethodExit(ManagedThread *thread, Method *method) override; 71 72 void SaveTracingData(); 73 74 static void StopTracing(); 75 76 static bool isTracing_; 77 78 ~Trace() override; 79 80 uint64_t GetAverageTime(); 81 82 protected: 83 explicit Trace(PandaUniquePtr<panda::os::unix::file::File> traceFile, size_t bufferSize); 84 uint32_t EncodeMethodToId(Method *method); 85 virtual PandaString GetThreadName(ManagedThread *thread) = 0; 86 virtual PandaString GetMethodDetailInfo(Method *method) = 0; 87 88 private: 89 static constexpr size_t TRACE_HEADER_REAL_LENGTH = 18U; 90 91 static const char TRACE_STAR_CHAR = '*'; 92 static const uint16_t TRACE_HEADER_LENGTH = 32; 93 static const uint32_t MAGIC_VALUE = 0x574f4c53; 94 static const uint16_t TRACE_VERSION = 3; 95 static const uint16_t TRACE_ITEM_SIZE = 14; 96 97 static const uint32_t FILE_SIZE = 8 * 1024 * 1024; 98 99 // used to define the number we need to right shift 100 static const uint8_t WRITE_LENGTH = 8; 101 102 // used to define the number of this item we have writed just now 103 const uint8_t numberOf2Bytes_ = 2; 104 const uint8_t numberOf4Bytes_ = 4; 105 const uint8_t numberOf8Bytes_ = 8; 106 107 const int32_t loopNumber_ = 10000; 108 const int32_t divideNumber_ = 10; 109 110 PandaUniquePtr<RuntimeListener> listener_; 111 112 os::memory::Mutex methodsLock_; 113 // all methods are encoded to id, and put method、id into this map 114 PandaMap<Method *, uint32_t> methodIdPandamap_ GUARDED_BY(methodsLock_); 115 PandaVector<Method *> methodsCalledVector_ GUARDED_BY(methodsLock_); 116 117 os::memory::Mutex threadInfoLock_; 118 PandaSet<PandaString> threadInfoSet_ GUARDED_BY(threadInfoLock_); 119 120 uint32_t EncodeMethodAndEventToId(Method *method, EventFlag flag); 121 Method *DecodeIdToMethod(uint32_t id); 122 123 void GetCalledMethods(size_t endOffset, PandaSet<Method *> *calledMethods); 124 125 void GetTimes(uint32_t *threadTime, uint32_t *realTime); 126 127 void WriteInfoToBuf(const ManagedThread *thread, Method *method, EventFlag event, uint32_t threadTime, 128 uint32_t realTime); 129 130 void RecordThreadsInfo(PandaOStringStream *os); 131 void RecordMethodsInfo(PandaOStringStream *os, const PandaSet<Method *> &calledMethods); 132 133 void GetUniqueMethods(size_t bufferLength, PandaSet<Method *> *calledMethodsSet); 134 135 static Trace *volatile singletonTrace_ GUARDED_BY(g_traceLock); 136 137 PandaUniquePtr<panda::os::unix::file::File> traceFile_; 138 const size_t bufferSize_; 139 140 PandaUniquePtr<uint8_t[]> buffer_; // NOLINT(modernize-avoid-c-arrays) 141 142 const uint64_t traceStartTime_; 143 144 const uint64_t baseCpuTime_; 145 146 std::atomic<int32_t> bufferOffset_; 147 148 bool overbrim_ {false}; 149 150 static LanguageContext ctx_; 151 152 NO_COPY_SEMANTIC(Trace); 153 NO_MOVE_SEMANTIC(Trace); 154 }; 155 156 } // namespace panda 157 158 #endif // PANDA_RUNTIME_DPROFILER_TRACE_H 159