mirror of
https://gitee.com/openharmony/developtools_profiler
synced 2024-11-27 00:51:47 +00:00
ftrace支持小文件存储
Signed-off-by: 张建 <zhangjian22@huawei.com> #I6YX8A
This commit is contained in:
parent
483c263af2
commit
f2f6f92f91
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Copyright (c) 2021-2023 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
|
||||
@ -32,6 +32,7 @@ bool CheckApplicationPermission(int pid, const std::string& processName);
|
||||
bool VerifyPath(const std::string& filePath, const std::vector<std::string>& validPaths);
|
||||
bool ReadFile(const std::string& filePath, const std::vector<std::string>& validPaths, std::string& fileContent);
|
||||
std::string GetErrorMsg();
|
||||
std::string GetTimeStr();
|
||||
} // COMMON
|
||||
|
||||
#endif // COMMON_H
|
@ -401,4 +401,17 @@ std::string GetErrorMsg()
|
||||
std::string errorMsg(buffer);
|
||||
return errorMsg;
|
||||
}
|
||||
|
||||
std::string GetTimeStr()
|
||||
{
|
||||
time_t now = time(nullptr);
|
||||
struct tm tmTime;
|
||||
localtime_r(&now, &tmTime);
|
||||
|
||||
char buffer[32] = {0};
|
||||
(void)sprintf_s(buffer, sizeof(buffer), "%04d%02d%02d_%02d%02d%02d", tmTime.tm_year + 1900, tmTime.tm_mon + 1,
|
||||
tmTime.tm_mday, tmTime.tm_hour, tmTime.tm_min, tmTime.tm_sec);
|
||||
std::string timeStr(buffer);
|
||||
return timeStr;
|
||||
}
|
||||
} // namespace COMMON
|
||||
|
@ -139,6 +139,10 @@ std::unique_ptr<CreateSessionRequest> MakeCreateRequest(const std::string& confi
|
||||
printf("set %s plugin config failed\n", pluginConfig->name().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
if (sessionConfig->split_file() && pluginConfig->name() != "ftrace-plugin") {
|
||||
printf("only ftrace-plugin support split_file, please check session_config.\n");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
content.clear();
|
||||
@ -190,10 +194,10 @@ bool GetCapabilities(std::string& content, bool isCheck)
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t CreateSession(std::unique_ptr<IProfilerService::Stub>& profilerStub, const std::string& configFile,
|
||||
uint32_t CreateSession(std::unique_ptr<IProfilerService::Stub>& profilerStub, const std::string& config,
|
||||
const std::string& keepSecond, const std::string& outputFile)
|
||||
{
|
||||
auto request = MakeCreateRequest(configFile, keepSecond, outputFile);
|
||||
auto request = MakeCreateRequest(config, keepSecond, outputFile);
|
||||
if (!request) {
|
||||
printf("MakeCreateRequest failed!\n");
|
||||
return 0;
|
||||
@ -254,7 +258,7 @@ bool CheckDestroySession(std::unique_ptr<IProfilerService::Stub>& profilerStub,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DoCapture(const std::string& configFile, const std::string& keepSecond, const std::string& outputFile)
|
||||
bool DoCapture(const std::string& config, const std::string& keepSecond, const std::string& outputFile)
|
||||
{
|
||||
auto profilerStub = GetProfilerServiceStub();
|
||||
if (profilerStub == nullptr) {
|
||||
@ -262,7 +266,7 @@ bool DoCapture(const std::string& configFile, const std::string& keepSecond, con
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t sessionId = CreateSession(profilerStub, configFile, keepSecond, outputFile);
|
||||
uint32_t sessionId = CreateSession(profilerStub, config, keepSecond, outputFile);
|
||||
if (sessionId == 0) {
|
||||
printf("Create session returns Id 0\n");
|
||||
return false;
|
||||
|
@ -38,6 +38,7 @@ public:
|
||||
MOCKABLE std::string GetThreadComm(int pid, int tid);
|
||||
|
||||
// for ftrace status nodes
|
||||
bool SetSavedCmdLinesSize(uint32_t size);
|
||||
MOCKABLE std::string GetSavedCmdLines() const;
|
||||
MOCKABLE std::string GetSavedTgids() const;
|
||||
MOCKABLE std::string GetPerCpuStats(int cpu) const;
|
||||
|
@ -46,6 +46,10 @@ namespace {
|
||||
constexpr uint32_t MIN_BLOCK_SIZE_PAGES = 256; // 1 MB
|
||||
constexpr uint32_t PARSE_CMDLINE_COUNT = 1000;
|
||||
const std::set<std::string> g_availableClocks = { "boot", "global", "local", "mono" };
|
||||
constexpr uint32_t SAVED_CMDLINE_SIZE_SMALL = 1024; // save cmdline sizes for cpu num less than 8
|
||||
constexpr uint32_t SAVED_CMDLINE_SIZE_LARGE = 4096; // save cmdline sizes for cpu num no less than 8
|
||||
constexpr int OCTA_CORE_CPU = 8; // 8 core
|
||||
|
||||
} // namespace
|
||||
|
||||
FTRACE_NS_BEGIN
|
||||
@ -194,6 +198,11 @@ int FlowController::StartCapture(void)
|
||||
// clear old trace
|
||||
FtraceFsOps::GetInstance().ClearTraceBuffer();
|
||||
|
||||
uint32_t savedCmdlinesSize = platformCpuNum_ < OCTA_CORE_CPU ? SAVED_CMDLINE_SIZE_SMALL : SAVED_CMDLINE_SIZE_LARGE;
|
||||
if (!FtraceFsOps::GetInstance().SetSavedCmdLinesSize(savedCmdlinesSize)) {
|
||||
HILOG_ERROR(LOG_CORE, "SetSavedCmdLinesSize %u fail.", savedCmdlinesSize);
|
||||
}
|
||||
|
||||
// enable additional record options
|
||||
FtraceFsOps::GetInstance().SetRecordCmdOption(true);
|
||||
FtraceFsOps::GetInstance().SetRecordTgidOption(true);
|
||||
|
@ -87,6 +87,12 @@ std::string FtraceFsOps::GetKernelSymbols() const
|
||||
return result;
|
||||
}
|
||||
|
||||
bool FtraceFsOps::SetSavedCmdLinesSize(uint32_t size)
|
||||
{
|
||||
std::string path = ftraceRoot_ + "/saved_cmdlines_size";
|
||||
return FileUtils::WriteFile(path, std::to_string(static_cast<int>(size))) > 0;
|
||||
}
|
||||
|
||||
std::string FtraceFsOps::GetSavedCmdLines() const
|
||||
{
|
||||
return FileUtils::ReadFile(ftraceRoot_ + "/saved_cmdlines");
|
||||
|
@ -287,7 +287,7 @@ Status ProfilerService::CreateSession(ServerContext* context,
|
||||
auto resultFile = sessionConfig.result_file();
|
||||
CHECK_EXPRESSION_TRUE(resultFile.size() > 0, "result_file empty!");
|
||||
traceWriter = std::make_shared<TraceFileWriter>(resultFile, sessionConfig.split_file(),
|
||||
sessionConfig.single_file_max_size_mb());
|
||||
sessionConfig.split_file_max_size_mb(), sessionConfig.split_file_max_num());
|
||||
CHECK_POINTER_NOTNULL(traceWriter, "alloc TraceFileWriter failed!");
|
||||
pluginService_->SetTraceWriter(traceWriter);
|
||||
for (std::vector<ProfilerPluginConfig>::size_type i = 0; i < pluginConfigs.size(); i++) {
|
||||
@ -586,10 +586,6 @@ Status ProfilerService::StopSession(ServerContext* context,
|
||||
|
||||
auto ctx = GetSessionContext(sessionId);
|
||||
CHECK_POINTER_NOTNULL(ctx, "session_id invalid!");
|
||||
if (ctx->sessionConfig.session_mode() == ProfilerSessionConfig::OFFLINE) {
|
||||
CHECK_POINTER_NOTNULL(ctx->traceFileWriter, "traceFileWriter invalid!");
|
||||
ctx->traceFileWriter.get()->SetStopSplitFile(true);
|
||||
}
|
||||
CHECK_EXPRESSION_TRUE(ctx->StopPluginSessions(), "stop plugin sessions failed!");
|
||||
HILOG_INFO(LOG_CORE, "StopSession %d %u done!", request->request_id(), sessionId);
|
||||
return Status::OK;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Huawei Device Co., Ltd.
|
||||
* Copyright (c) 2021-2023 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
|
||||
@ -16,23 +16,28 @@
|
||||
|
||||
#include <cinttypes>
|
||||
#include <memory>
|
||||
#include <sys/statvfs.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "logging.h"
|
||||
|
||||
using CharPtr = std::unique_ptr<char>::pointer;
|
||||
using ConstCharPtr = std::unique_ptr<const char>::pointer;
|
||||
|
||||
namespace {
|
||||
const int MB_TO_BYTE = 1024 * 1024;
|
||||
const int MIN_BYTE = 200;
|
||||
constexpr int MB_TO_BYTE = (1024 * 1024);
|
||||
constexpr int GB_TO_BYTE = (1024 * 1024 * 1024);
|
||||
constexpr int SPLIT_FILE_MIN_SIZE = 2; // split file min size
|
||||
constexpr int SPLIT_FILE_DEFAULT_NUM = 10; // split file default num
|
||||
} // namespace
|
||||
|
||||
TraceFileWriter::TraceFileWriter(const std::string& path, bool splitFile, uint32_t singleFileMaxSizeMb)
|
||||
: path_(path), writeBytes_(0)
|
||||
TraceFileWriter::TraceFileWriter(const std::string& path, bool splitFile, uint32_t splitFileMaxSizeMb,
|
||||
uint32_t splitFileMaxNum) : path_(path), isSplitFile_(splitFile)
|
||||
{
|
||||
isSplitFile_ = splitFile;
|
||||
singleFileMaxSize_ = (singleFileMaxSizeMb < MIN_BYTE) ? (MIN_BYTE * MB_TO_BYTE) :
|
||||
(singleFileMaxSizeMb * MB_TO_BYTE);
|
||||
splitFileMaxSize_ = (splitFileMaxSizeMb < SPLIT_FILE_MIN_SIZE) ? (SPLIT_FILE_MIN_SIZE * MB_TO_BYTE) :
|
||||
(splitFileMaxSizeMb * MB_TO_BYTE);
|
||||
splitFileMaxNum_ = (splitFileMaxNum == 0) ? SPLIT_FILE_DEFAULT_NUM : splitFileMaxNum;
|
||||
oldPath_ = path;
|
||||
fileNum_ = 1;
|
||||
|
||||
@ -90,18 +95,11 @@ void TraceFileWriter::SetTimeStamp()
|
||||
static_cast<uint64_t>(ts.tv_nsec);
|
||||
}
|
||||
|
||||
static std::string GetCurrentTime()
|
||||
{
|
||||
const int usMs = 1000;
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return std::to_string(tv.tv_sec * usMs + tv.tv_usec / usMs);
|
||||
}
|
||||
|
||||
bool TraceFileWriter::WriteHeader()
|
||||
{
|
||||
LogDiskUsage();
|
||||
if (isSplitFile_) {
|
||||
std::string timeStr = GetCurrentTime();
|
||||
std::string timeStr = COMMON::GetTimeStr();
|
||||
int pos = static_cast<int>(oldPath_.find_last_of('.'));
|
||||
if (pos != 0) {
|
||||
path_ = oldPath_.substr(0, pos) + "_" + timeStr + "_" + std::to_string(fileNum_) +
|
||||
@ -109,6 +107,8 @@ bool TraceFileWriter::WriteHeader()
|
||||
} else {
|
||||
path_ = oldPath_ + "_" + timeStr + "_" + std::to_string(fileNum_);
|
||||
}
|
||||
splitFilePaths_.push(path_);
|
||||
DeleteOldSplitFile();
|
||||
}
|
||||
|
||||
stream_.open(path_, std::ios_base::out | std::ios_base::binary);
|
||||
@ -124,6 +124,21 @@ bool TraceFileWriter::WriteHeader()
|
||||
return true;
|
||||
}
|
||||
|
||||
// delete first split file if split file num over max
|
||||
void TraceFileWriter::DeleteOldSplitFile()
|
||||
{
|
||||
HILOG_INFO(LOG_CORE, "DeleteOldSplitFile in.");
|
||||
if (splitFilePaths_.empty() || (splitFilePaths_.size() <= splitFileMaxNum_)) {
|
||||
HILOG_INFO(LOG_CORE, "DeleteOldSplitFile %u.", splitFilePaths_.size());
|
||||
return;
|
||||
}
|
||||
|
||||
std::string splitFilePath = splitFilePaths_.front();
|
||||
int ret = unlink(splitFilePath.c_str());
|
||||
HILOG_INFO(LOG_CORE, "DeleteOldSplitFile remove %s return %d. ", splitFilePath.c_str(), ret);
|
||||
splitFilePaths_.pop();
|
||||
}
|
||||
|
||||
long TraceFileWriter::Write(const void* data, size_t size)
|
||||
{
|
||||
if (isSplitFile_ && !isStop_) {
|
||||
@ -156,9 +171,9 @@ long TraceFileWriter::Write(const void* data, size_t size)
|
||||
bool TraceFileWriter::IsSplitFile(uint32_t size)
|
||||
{
|
||||
dataSize_ += sizeof(uint32_t) + size;
|
||||
if (dataSize_ >= singleFileMaxSize_) {
|
||||
HILOG_INFO(LOG_CORE, "need to split the file(%s), data size:%d, size: %d, singleFileMaxSize_:%d",
|
||||
path_.c_str(), dataSize_, size, singleFileMaxSize_);
|
||||
if (dataSize_ >= splitFileMaxSize_) {
|
||||
HILOG_INFO(LOG_CORE, "need to split the file(%s), data size:%d, size: %d, splitFileMaxSize_:%d",
|
||||
path_.c_str(), dataSize_, size, splitFileMaxSize_);
|
||||
|
||||
// update old file header
|
||||
Finish();
|
||||
@ -168,7 +183,10 @@ bool TraceFileWriter::IsSplitFile(uint32_t size)
|
||||
fileNum_++;
|
||||
|
||||
// write header of the new file
|
||||
WriteHeader();
|
||||
if (!WriteHeader()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// write the plugin config of the new file
|
||||
for (size_t i = 0; i < pluginConfigsData_.size(); i++) {
|
||||
Write(pluginConfigsData_[i].data(), pluginConfigsData_[i].size());
|
||||
@ -225,4 +243,29 @@ bool TraceFileWriter::Flush()
|
||||
void TraceFileWriter::SetStopSplitFile(bool isStop)
|
||||
{
|
||||
isStop_ = isStop;
|
||||
}
|
||||
|
||||
void TraceFileWriter::LogDiskUsage()
|
||||
{
|
||||
std::string diskPath = "/data/local/tmp/";
|
||||
std::string::size_type pos = oldPath_.find_last_of('/');
|
||||
if (pos != std::string::npos) {
|
||||
diskPath = oldPath_.substr(0, pos);
|
||||
}
|
||||
|
||||
struct statvfs diskInfo;
|
||||
int ret = statvfs(diskPath.c_str(), &diskInfo);
|
||||
if (ret != 0) {
|
||||
std::string errorMsg = COMMON::GetErrorMsg();
|
||||
HILOG_ERROR(LOG_CORE, "LogDiskUsage() return %d, path:%s, msg:%s", ret, diskPath.c_str(), errorMsg.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long long freeSize = static_cast<unsigned long long>(diskInfo.f_bsize) *
|
||||
static_cast<unsigned long long>(diskInfo.f_bfree);
|
||||
unsigned long long totalSize = static_cast<unsigned long long>(diskInfo.f_bsize) *
|
||||
static_cast<unsigned long long>(diskInfo.f_blocks);
|
||||
float freePercent = static_cast<float>(freeSize) / static_cast<float>(totalSize);
|
||||
uint32_t freeSizeGb = freeSize / GB_TO_BYTE;
|
||||
HILOG_INFO(LOG_CORE, "LogDiskUsage() freePercent:%.1f, freeSizeGb:%u", freePercent * 100, freeSizeGb);
|
||||
}
|
@ -19,6 +19,7 @@
|
||||
#include <fstream>
|
||||
#include <google/protobuf/message_lite.h>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
|
||||
#include "logging.h"
|
||||
@ -30,7 +31,8 @@ using google::protobuf::MessageLite;
|
||||
|
||||
class TraceFileWriter : public Writer {
|
||||
public:
|
||||
explicit TraceFileWriter(const std::string& path, bool splitFile = false, uint32_t singleFileMaxSizeMb = 0);
|
||||
explicit TraceFileWriter(const std::string& path, bool splitFile, uint32_t splitFileMaxSizeMb,
|
||||
uint32_t splitFileMaxNum);
|
||||
|
||||
~TraceFileWriter();
|
||||
|
||||
@ -55,6 +57,10 @@ public:
|
||||
private:
|
||||
void SetTimeStamp();
|
||||
|
||||
void LogDiskUsage();
|
||||
|
||||
void DeleteOldSplitFile();
|
||||
|
||||
private:
|
||||
std::string path_ {};
|
||||
std::string oldPath_ {};
|
||||
@ -65,7 +71,9 @@ private:
|
||||
TraceFileHelper helper_ {};
|
||||
uint32_t dataSize_;
|
||||
bool isSplitFile_ = false;
|
||||
uint32_t singleFileMaxSize_;
|
||||
uint32_t splitFileMaxSize_;
|
||||
uint32_t splitFileMaxNum_;
|
||||
std::queue<std::string> splitFilePaths_;
|
||||
std::vector<std::vector<char>> pluginConfigsData_;
|
||||
bool isStop_ = false;
|
||||
int fileNum_;
|
||||
|
@ -57,7 +57,8 @@ message ProfilerSessionConfig {
|
||||
uint32 keep_alive_time = 6; // if set to non-zero value, session will auto-destroyed after CreateSession in ms
|
||||
bool discard_cache_data = 7; // if set true, session will stop immediately.(cache data will be lost)
|
||||
bool split_file = 8; // if set true, will split result_file
|
||||
uint32 single_file_max_size_mb = 9; // limit the maximum size of a single file
|
||||
uint32 split_file_max_size_mb = 9; // limit the maximum size of a single split file, min size is 200Mb
|
||||
uint32 split_file_max_num = 10; // limit the split file max num, default is 10
|
||||
}
|
||||
|
||||
message CreateSessionRequest {
|
||||
|
Loading…
Reference in New Issue
Block a user