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