/* * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "stack_data_repeater.h" #include "hook_common.h" constexpr static uint32_t DEFAULT_SLEEP_TIME_MS = 100; // milliseconds constexpr static uint32_t DEFAULT_SLEEP_TIME_US = DEFAULT_SLEEP_TIME_MS * 1000; using namespace OHOS::Developtools::NativeDaemon; StackDataRepeater::StackDataRepeater(size_t maxSize) { maxSize_ = maxSize; closed_ = false; reducedStackCount_ = 0; } StackDataRepeater::~StackDataRepeater() { Close(); } size_t StackDataRepeater::Size() { std::unique_lock lock(mutex_); return rawDataQueue_.size(); } void StackDataRepeater::Reset() { std::unique_lock lock(mutex_); closed_ = false; } void StackDataRepeater::Close() { { std::unique_lock lock(mutex_); rawDataQueue_.clear(); closed_ = true; } HILOG_INFO(LOG_CORE, "StackDataRepeater Close, reducedStackCount_ : %" PRIx64 " ", reducedStackCount_); slotCondVar_.notify_all(); itemCondVar_.notify_all(); } bool StackDataRepeater::PutRawStack(const RawStackPtr& rawData) { bool needInsert = true; std::unique_lock lock(mutex_); if ((rawData == nullptr) && (rawDataQueue_.size() > 0)) { HILOG_INFO(LOG_CORE, "no need put nullptr if queue has data, rawDataQueue_.size() = %zu", rawDataQueue_.size()); return true; } while (rawDataQueue_.size() >= maxSize_ && !closed_) { slotCondVar_.wait(lock); } if (closed_) { return false; } if (__builtin_expect(rawData != nullptr, true)) { if (rawData->stackConext.type == FREE_MSG) { auto temp = mallocMap_.find(rawData->stackConext.addr); // true : pair of malloc and free matched, both malloc and free will be ignored // false : can not match, send free's data anyway if (temp != mallocMap_.end()) { temp->second->reportFlag = false; // will be ignore later mallocMap_.erase(rawData->stackConext.addr); needInsert = false; } } else if (rawData->stackConext.type == MALLOC_MSG) { mallocMap_.insert(std::pair>(rawData->stackConext.addr, rawData)); } } if (needInsert) { rawDataQueue_.push_back(rawData); } lock.unlock(); itemCondVar_.notify_one(); return true; } RawStackPtr StackDataRepeater::TakeRawData(uint32_t during, uint32_t batchCount, RawStackPtr batchRawStack[]) { uint32_t rawDataQueueSize = 0; std::unique_lock lock(mutex_); while (rawDataQueue_.empty() && !closed_) { itemCondVar_.wait(lock); } if (closed_) { return nullptr; } RawStackPtr result = nullptr; rawDataQueueSize = rawDataQueue_.size(); int resultSize = rawDataQueueSize > batchCount ? batchCount : rawDataQueueSize; bool needReduceStack = rawDataQueueSize >= SPEED_UP_THRESHOLD; for (int i = 0; i < resultSize; i++) { result = rawDataQueue_.front(); rawDataQueue_.pop_front(); batchRawStack[i] = result; if ((result != nullptr) && (result->stackConext.type == MALLOC_MSG)) { mallocMap_.erase(result->stackConext.addr); if (needReduceStack) { result->reduceStackFlag = true; reducedStackCount_++; } } } lock.unlock(); slotCondVar_.notify_one(); if (result != nullptr && during > 0 && rawDataQueueSize < SLOW_DOWN_THRESHOLD) { struct timespec now = {}; clock_gettime(CLOCK_REALTIME, &now); uint64_t curDuring = (now.tv_sec - result->stackConext.ts.tv_sec) * 1000; int diff = during - curDuring; if (diff > 0) { HILOG_INFO(LOG_CORE, "TakeRawData sleep diff %d, rawDataQueueSize %d", diff, rawDataQueueSize); int cnt = diff / DEFAULT_SLEEP_TIME_MS; while (!closed_ && cnt-- > 0) { usleep(DEFAULT_SLEEP_TIME_US); } } } return result; }