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 <memory> 20 #include <string> 21 #include <unordered_set> 22 #include "macros.h" 23 #include "include/mem/panda_containers.h" 24 #include "include/mem/panda_string.h" 25 #include "include/mem/panda_smart_pointers.h" 26 #include "include/mem/panda_containers.h" 27 #include "include/runtime.h" 28 #include "include/runtime_notification.h" 29 #include "runtime/include/method.h" 30 #include "runtime/include/language_context.h" 31 #include "os/mutex.h" 32 33 namespace panda { 34 35 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects) 36 static os::memory::Mutex trace_lock; 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 *trace_filename, size_t buffer_size); 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 is_tracing; 77 78 ~Trace() override; 79 80 uint64_t GetAverageTime(); 81 82 protected: 83 explicit Trace(PandaUniquePtr<panda::os::unix::file::File> trace_file, size_t buffer_size); 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 NUMBER_OF_2BYTES = 2; 104 const uint8_t NUMBER_OF_4BYTES = 4; 105 const uint8_t NUMBER_OF_8BYTES = 8; 106 107 const int32_t LOOP_NUMBER = 10000; 108 const int32_t DIVIDE_NUMBER = 10; 109 110 PandaUniquePtr<RuntimeListener> listener_; 111 112 os::memory::Mutex methods_lock_; 113 // all methods are encoded to id, and put method、id into this map 114 PandaMap<Method *, uint32_t> method_id_pandamap_ GUARDED_BY(methods_lock_); 115 PandaVector<Method *> methods_called_vector_ GUARDED_BY(methods_lock_); 116 117 os::memory::Mutex thread_info_lock_; 118 PandaSet<PandaString> thread_info_set_ GUARDED_BY(thread_info_lock_); 119 120 uint32_t EncodeMethodAndEventToId(Method *method, EventFlag flag); 121 Method *DecodeIdToMethod(uint32_t id); 122 123 void GetCalledMethods(size_t end_offset, PandaSet<Method *> *called_methods); 124 125 void GetTimes(uint32_t *thread_time, uint32_t *real_time); 126 127 void WriteInfoToBuf(const ManagedThread *thread, Method *method, EventFlag event, uint32_t thread_time, 128 uint32_t real_time); 129 130 void RecordThreadsInfo(PandaOStringStream *os); 131 void RecordMethodsInfo(PandaOStringStream *os, const PandaSet<Method *> &called_methods); 132 133 void GetUniqueMethods(size_t buffer_length, PandaSet<Method *> *called_methods_set); 134 135 static Trace *volatile singleton_trace GUARDED_BY(trace_lock); 136 137 PandaUniquePtr<panda::os::unix::file::File> trace_file_; 138 const size_t BUFFER_SIZE; 139 140 PandaUniquePtr<uint8_t[]> buffer_; // NOLINT(modernize-avoid-c-arrays) 141 142 const uint64_t TRACE_START_TIME; 143 144 const uint64_t BASE_CPU_TIME; 145 146 std::atomic<int32_t> buffer_offset_; 147 148 bool overbrim_; 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