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 RELIABILITY_THREAD_SAMPLER_H 17 #define RELIABILITY_THREAD_SAMPLER_H 18 19 #include <atomic> 20 #include <condition_variable> 21 #include <memory> 22 #include <string> 23 #include <mutex> 24 25 #include <sys/mman.h> 26 27 #include "singleton.h" 28 29 #include "unwinder.h" 30 #include "unique_stack_table.h" 31 #include "dfx_accessors.h" 32 #include "dfx_maps.h" 33 #include "unwind_context.h" 34 35 namespace OHOS { 36 namespace HiviewDFX { 37 constexpr int STACK_BUFFER_SIZE = 16 * 1024; 38 constexpr uint32_t DEFAULT_UNIQUE_STACK_TABLE_SIZE = 128 * 1024; 39 40 struct ThreadUnwindContext { 41 uintptr_t pc {0}; 42 uintptr_t sp {0}; 43 uintptr_t fp {0}; 44 uintptr_t lr {0}; 45 std::atomic<uint64_t> requestTime {0}; // begin sample 46 std::atomic<uint64_t> snapshotTime {0}; // end of stack copy in signal handler 47 std::atomic<uint64_t> processTime {0}; // end of unwind and unique stack 48 uint8_t buffer[STACK_BUFFER_SIZE] {0}; // 16K stack buffer 49 }; 50 51 struct UnwindInfo { 52 ThreadUnwindContext* context; 53 DfxMaps* maps; 54 }; 55 56 struct TimeAndFrames { 57 uint64_t requestTime {0}; 58 uint64_t snapshotTime {0}; 59 std::vector<DfxFrame> frameList; 60 }; 61 62 struct StackIdAndCount { 63 uint64_t stackId {0}; 64 uint32_t count {0}; 65 }; 66 67 class ThreadSampler : public Singleton<ThreadSampler> { 68 DECLARE_SINGLETON(ThreadSampler); 69 public: 70 static const int32_t SAMPLER_MAX_BUFFER_SZ = 2; 71 static void ThreadSamplerSignalHandler(int sig, siginfo_t* si, void* context); 72 73 // Initial sampler, include uwinder, recorde buffer etc. 74 bool Init(int collectStackCount); 75 int32_t Sample(); // Interface of sample, to send sample request. 76 // Collect stack info, can be formed into tree format or not. Unsafe in multi-thread environments 77 bool CollectStack(std::string& stack, bool treeFormat = true); 78 bool Deinit(); // Release sampler 79 std::string GetHeaviestStack() const; 80 81 private: 82 bool InitRecordBuffer(); 83 void ReleaseRecordBuffer(); 84 bool InitUnwinder(); 85 void DestroyUnwinder(); 86 bool InitUniqueStackTable(); 87 void DeinitUniqueStackTable(); 88 void SendSampleRequest(); 89 void ProcessStackBuffer(); 90 int AccessElfMem(uintptr_t addr, uintptr_t *val); 91 92 static int FindUnwindTable(uintptr_t pc, UnwindTableInfo& outTableInfo, void *arg); 93 static int AccessMem(uintptr_t addr, uintptr_t *val, void *arg); 94 static int GetMapByPc(uintptr_t pc, std::shared_ptr<DfxMap>& map, void *arg); 95 96 ThreadUnwindContext* GetReadContext(); 97 ThreadUnwindContext* GetWriteContext(); 98 void WriteContext(void* context); 99 MAYBE_UNUSED void ResetConsumeInfo(); 100 101 bool init_ {false}; 102 uintptr_t stackBegin_ {0}; 103 uintptr_t stackEnd_ {0}; 104 int32_t pid_ {0}; 105 std::atomic<int32_t> writeIndex_ {0}; 106 std::atomic<int32_t> readIndex_ {0}; 107 void* mmapStart_ {MAP_FAILED}; 108 int32_t bufferSize_ {0}; 109 std::shared_ptr<Unwinder> unwinder_ {nullptr}; 110 std::unique_ptr<UniqueStackTable> uniqueStackTable_ {nullptr}; 111 std::shared_ptr<UnwindAccessors> accessors_ {nullptr}; 112 std::shared_ptr<DfxMaps> maps_ {nullptr}; 113 // size of the uniqueStackTableSize, default 128KB 114 uint32_t uniqueStackTableSize_ {DEFAULT_UNIQUE_STACK_TABLE_SIZE}; 115 // name of the mmap of uniqueStackTable 116 std::string uniTableMMapName_ {"hicollie_buf"}; 117 std::string heaviestStack_ {0}; 118 119 MAYBE_UNUSED uint64_t copyStackCount_ {0}; 120 MAYBE_UNUSED uint64_t copyStackTimeCost_ {0}; 121 MAYBE_UNUSED uint64_t unwindCount_ {0}; 122 MAYBE_UNUSED uint64_t unwindTimeCost_ {0}; 123 MAYBE_UNUSED uint64_t processTimeCost_ {0}; 124 MAYBE_UNUSED uint64_t sampleCount_ {0}; 125 MAYBE_UNUSED uint64_t requestCount_ {0}; 126 MAYBE_UNUSED uint64_t signalTimeCost_ {0}; 127 MAYBE_UNUSED uint64_t processCount_ {0}; 128 129 std::vector<TimeAndFrames> timeAndFrameList_; 130 std::vector<StackIdAndCount> stackIdCount_; 131 }; 132 } // end of namespace HiviewDFX 133 } // end of namespace OHOS 134 #endif 135