ftrace支持小文件存储

Signed-off-by: 张建 <zhangjian22@huawei.com>
#I6YX8A
This commit is contained in:
zhangjian22 2023-04-26 09:30:03 +08:00
parent 483c263af2
commit f2f6f92f91
10 changed files with 116 additions and 34 deletions

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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");

View File

@ -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;

View File

@ -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);
}

View File

@ -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_;

View File

@ -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 {