1 /*
2 * Copyright (c) 2021-2023 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 #include "stack_data_repeater.h"
16 #include "hook_common.h"
17
18 constexpr static uint32_t DEFAULT_SLEEP_TIME_MS = 100; // milliseconds
19 constexpr static uint32_t DEFAULT_SLEEP_TIME_US = DEFAULT_SLEEP_TIME_MS * 1000;
20 using namespace OHOS::Developtools::NativeDaemon;
21
StackDataRepeater(size_t maxSize)22 StackDataRepeater::StackDataRepeater(size_t maxSize)
23 {
24 maxSize_ = maxSize;
25 closed_ = false;
26 reducedStackCount_ = 0;
27 }
28
~StackDataRepeater()29 StackDataRepeater::~StackDataRepeater()
30 {
31 Close();
32 }
33
Size()34 size_t StackDataRepeater::Size()
35 {
36 std::unique_lock<std::mutex> lock(mutex_);
37 return rawDataQueue_.size();
38 }
39
Reset()40 void StackDataRepeater::Reset()
41 {
42 std::unique_lock<std::mutex> lock(mutex_);
43 closed_ = false;
44 }
45
Close()46 void StackDataRepeater::Close()
47 {
48 {
49 std::unique_lock<std::mutex> lock(mutex_);
50 rawDataQueue_.clear();
51 closed_ = true;
52 }
53 HILOG_INFO(LOG_CORE, "StackDataRepeater Close, reducedStackCount_ : %" PRIx64 " ", reducedStackCount_);
54 slotCondVar_.notify_all();
55 itemCondVar_.notify_all();
56 }
57
PutRawStack(const RawStackPtr & rawData,bool isRecordAccurately)58 bool StackDataRepeater::PutRawStack(const RawStackPtr& rawData, bool isRecordAccurately)
59 {
60 bool needInsert = true;
61 std::unique_lock<std::mutex> lock(mutex_);
62
63 if ((rawData == nullptr) && (rawDataQueue_.size() > 0)) {
64 HILOG_INFO(LOG_CORE, "no need put nullptr if queue has data, rawDataQueue_.size() = %zu", rawDataQueue_.size());
65 return true;
66 }
67 while (rawDataQueue_.size() >= maxSize_ && !closed_) {
68 slotCondVar_.wait(lock);
69 }
70 if (closed_) {
71 return false;
72 }
73
74 if (__builtin_expect((rawData != nullptr) && !isRecordAccurately, true)) {
75 if (rawData->stackConext->type == FREE_MSG) {
76 auto temp = mallocMap_.find(rawData->stackConext->addr);
77 // true : pair of malloc and free matched, both malloc and free will be ignored
78 // false : can not match, send free's data anyway
79 if (temp != mallocMap_.end()) {
80 temp->second->reportFlag = false; // will be ignore later
81 mallocMap_.erase(rawData->stackConext->addr);
82 needInsert = false;
83 }
84 } else if (rawData->stackConext->type == MALLOC_MSG) {
85 mallocMap_.insert(std::pair<void*, std::shared_ptr<RawStack>>(rawData->stackConext->addr, rawData));
86 }
87 if (needInsert) {
88 rawDataQueue_.push_back(rawData);
89 }
90 } else {
91 rawDataQueue_.push_back(rawData);
92 }
93
94 lock.unlock();
95 itemCondVar_.notify_one();
96 return true;
97 }
98
TakeRawData(uint32_t during,clockid_t clockId,uint32_t batchCount,RawStackPtr batchRawStack[])99 RawStackPtr StackDataRepeater::TakeRawData(uint32_t during, clockid_t clockId, uint32_t batchCount,
100 RawStackPtr batchRawStack[])
101 {
102 uint32_t rawDataQueueSize = 0;
103 std::unique_lock<std::mutex> lock(mutex_);
104 while (rawDataQueue_.empty() && !closed_) {
105 itemCondVar_.wait(lock);
106 }
107 if (closed_) {
108 return nullptr;
109 }
110 RawStackPtr result = nullptr;
111 rawDataQueueSize = rawDataQueue_.size();
112 int resultSize = rawDataQueueSize > batchCount ? batchCount : rawDataQueueSize;
113 bool needReduceStack = rawDataQueueSize >= SPEED_UP_THRESHOLD;
114 for (int i = 0; i < resultSize; i++) {
115 result = rawDataQueue_.front();
116 rawDataQueue_.pop_front();
117 batchRawStack[i] = result;
118 if ((result != nullptr) && (result->stackConext->type == MALLOC_MSG)) {
119 mallocMap_.erase(result->stackConext->addr);
120 if (needReduceStack) {
121 result->reduceStackFlag = true;
122 reducedStackCount_++;
123 }
124 }
125 }
126
127 lock.unlock();
128 slotCondVar_.notify_one();
129 return result;
130 }