1/* 2 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2023. All rights reserved. 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#include "stack_data_repeater.h" 16#include "hook_common.h" 17 18using namespace OHOS::Developtools::NativeDaemon; 19 20StackDataRepeater::StackDataRepeater(size_t maxSize) 21{ 22 maxSize_ = maxSize; 23 closed_ = false; 24 reducedStackCount_ = 0; 25 for (int index = 0; index < CACHE_DATA_SIZE; ++index) { 26 rawDataCacheQueue_.emplace_back(std::make_shared<RawStack>()); 27 } 28} 29 30StackDataRepeater::~StackDataRepeater() 31{ 32 Close(); 33} 34 35size_t StackDataRepeater::Size() 36{ 37 std::unique_lock<std::mutex> lock(mutex_); 38 return rawDataQueue_.size(); 39} 40 41void StackDataRepeater::Reset() 42{ 43 std::unique_lock<std::mutex> lock(mutex_); 44 closed_ = false; 45} 46 47void StackDataRepeater::Close() 48{ 49 { 50 std::unique_lock<std::mutex> lock(mutex_); 51 rawDataQueue_.clear(); 52 closed_ = true; 53 } 54 PROFILER_LOG_INFO(LOG_CORE, "StackDataRepeater Close, reducedStackCount_ : %" PRIx64 " ", reducedStackCount_); 55 slotCondVar_.notify_all(); 56 itemCondVar_.notify_all(); 57} 58 59RawStackPtr StackDataRepeater::GetRawStack() 60{ 61 std::unique_lock<std::mutex> lock(cacheMutex_); 62 if (!rawDataCacheQueue_.empty()) { 63 RawStackPtr rawStack = rawDataCacheQueue_.back(); 64 rawDataCacheQueue_.pop_back(); 65 return rawStack; 66 } 67 return std::make_shared<RawStack>(); 68} 69 70void StackDataRepeater::ReturnRawStack(RawStackPtr rawStack) 71{ 72 std::unique_lock<std::mutex> lock(cacheMutex_); 73 if (rawDataCacheQueue_.size() <= CACHE_DATA_SIZE) { 74 rawStack->Reset(); 75 rawDataCacheQueue_.push_back(rawStack); 76 } 77} 78 79bool StackDataRepeater::PutRawStackArray(std::array<std::shared_ptr<RawStack>, CACHE_ARRAY_SIZE>& rawDataArray, uint32_t batchCount) 80{ 81 std::unique_lock<std::mutex> lock(mutex_); 82 if ((rawDataArray.empty()) && (rawDataQueue_.size() > 0)) { 83 PROFILER_LOG_INFO(LOG_CORE, "PutRawStackArray: no need to put nullptr if queue has data"); 84 return true; 85 } 86 while (rawDataQueue_.size() >= maxSize_ && !closed_) { 87 slotCondVar_.wait(lock); 88 } 89 if (closed_) { 90 return false; 91 } 92 for (uint32_t i = 0; i < batchCount; i++) { 93 rawDataQueue_.push_back(rawDataArray[i]); 94 } 95 lock.unlock(); 96 itemCondVar_.notify_one(); 97 return true; 98} 99 100bool StackDataRepeater::PutRawStack(const RawStackPtr& rawData, bool isRecordAccurately) 101{ 102 bool needInsert = true; 103 std::unique_lock<std::mutex> lock(mutex_); 104 105 if ((rawData == nullptr) && (rawDataQueue_.size() > 0)) { 106 PROFILER_LOG_INFO(LOG_CORE, "no need put nullptr if queue has data, rawDataQueue_.size() = %zu", 107 rawDataQueue_.size()); 108 return true; 109 } 110 while (rawDataQueue_.size() >= maxSize_ && !closed_) { 111 slotCondVar_.wait(lock); 112 } 113 if (closed_) { 114 return false; 115 } 116 117 if (__builtin_expect((rawData != nullptr) && !isRecordAccurately, true)) { 118 if (rawData->stackConext->type == FREE_MSG) { 119 auto temp = mallocMap_.find(rawData->stackConext->addr); 120 // true : pair of malloc and free matched, both malloc and free will be ignored 121 // false : can not match, send free's data anyway 122 if (temp != mallocMap_.end()) { 123 temp->second->reportFlag = false; // will be ignore later 124 mallocMap_.erase(rawData->stackConext->addr); 125 needInsert = false; 126 } 127 } else if (rawData->stackConext->type == MALLOC_MSG) { 128 mallocMap_.insert(std::pair<void*, std::shared_ptr<RawStack>>(rawData->stackConext->addr, rawData)); 129 } 130 if (needInsert) { 131 rawDataQueue_.push_back(rawData); 132 } 133 } else { 134 rawDataQueue_.push_back(rawData); 135 } 136 137 lock.unlock(); 138 itemCondVar_.notify_one(); 139 return true; 140} 141 142RawStackPtr StackDataRepeater::TakeRawData(uint32_t during, clockid_t clockId, uint32_t batchCount, 143 RawStackPtr batchRawStack[], uint32_t statInterval, bool& isTimeOut) 144{ 145 uint32_t rawDataQueueSize = 0; 146 std::unique_lock<std::mutex> lock(mutex_); 147 if (statInterval > 0 && 148 !itemCondVar_.wait_for(lock, std::chrono::milliseconds(during), [&] { return !rawDataQueue_.empty(); })) { 149 if (rawDataQueue_.empty() && !closed_) { 150 isTimeOut = true; 151 lock.unlock(); 152 slotCondVar_.notify_one(); 153 return nullptr; 154 } 155 } else { 156 while (rawDataQueue_.empty() && !closed_) { 157 itemCondVar_.wait(lock); 158 } 159 } 160 if (closed_) { 161 return nullptr; 162 } 163 RawStackPtr result = nullptr; 164 rawDataQueueSize = rawDataQueue_.size(); 165 int resultSize = rawDataQueueSize > batchCount ? batchCount : rawDataQueueSize; 166 bool needReduceStack = rawDataQueueSize >= SPEED_UP_THRESHOLD; 167 for (int i = 0; i < resultSize; i++) { 168 result = rawDataQueue_.front(); 169 rawDataQueue_.pop_front(); 170 batchRawStack[i] = result; 171 if ((result != nullptr) && (result->stackConext != nullptr) && (result->stackConext->type == MALLOC_MSG)) { 172 mallocMap_.erase(result->stackConext->addr); 173 if (needReduceStack) { 174 result->reduceStackFlag = true; 175 reducedStackCount_++; 176 } 177 } 178 } 179 180 lock.unlock(); 181 slotCondVar_.notify_one(); 182 return result; 183}