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