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 80 private: 81 bool InitRecordBuffer(); 82 void ReleaseRecordBuffer(); 83 bool InitUnwinder(); 84 void DestroyUnwinder(); 85 bool InitUniqueStackTable(); 86 void DeinitUniqueStackTable(); 87 void SendSampleRequest(); 88 void ProcessStackBuffer(); 89 int AccessElfMem(uintptr_t addr, uintptr_t *val); 90 91 static int FindUnwindTable(uintptr_t pc, UnwindTableInfo& outTableInfo, void *arg); 92 static int AccessMem(uintptr_t addr, uintptr_t *val, void *arg); 93 static int GetMapByPc(uintptr_t pc, std::shared_ptr<DfxMap>& map, void *arg); 94 95 ThreadUnwindContext* GetReadContext(); 96 ThreadUnwindContext* GetWriteContext(); 97 void WriteContext(void* context); 98 MAYBE_UNUSED void ResetConsumeInfo(); 99 100 bool init_ {false}; 101 uintptr_t stackBegin_ {0}; 102 uintptr_t stackEnd_ {0}; 103 int32_t pid_ {0}; 104 std::atomic<int32_t> writeIndex_ {0}; 105 std::atomic<int32_t> readIndex_ {0}; 106 void* mmapStart_ {MAP_FAILED}; 107 int32_t bufferSize_ {0}; 108 std::shared_ptr<Unwinder> unwinder_ {nullptr}; 109 std::unique_ptr<UniqueStackTable> uniqueStackTable_ {nullptr}; 110 std::shared_ptr<UnwindAccessors> accessors_ {nullptr}; 111 std::shared_ptr<DfxMaps> maps_ {nullptr}; 112 // size of the uniqueStackTableSize, default 128KB 113 uint32_t uniqueStackTableSize_ {DEFAULT_UNIQUE_STACK_TABLE_SIZE}; 114 // name of the mmap of uniqueStackTable 115 std::string uniTableMMapName_ {"hicollie_buf"}; 116 117 MAYBE_UNUSED uint64_t copyStackCount_ {0}; 118 MAYBE_UNUSED uint64_t copyStackTimeCost_ {0}; 119 MAYBE_UNUSED uint64_t unwindCount_ {0}; 120 MAYBE_UNUSED uint64_t unwindTimeCost_ {0}; 121 MAYBE_UNUSED uint64_t processTimeCost_ {0}; 122 MAYBE_UNUSED uint64_t sampleCount_ {0}; 123 MAYBE_UNUSED uint64_t requestCount_ {0}; 124 MAYBE_UNUSED uint64_t signalTimeCost_ {0}; 125 MAYBE_UNUSED uint64_t processCount_ {0}; 126 127 std::vector<TimeAndFrames> timeAndFrameList_; 128 std::vector<StackIdAndCount> stackIdCount_; 129 }; 130 } // end of namespace HiviewDFX 131 } // end of namespace OHOS 132 #endif 133