optimize command line interface

Signed-off-by: anderskov <zangleizhen@huawei.com>
This commit is contained in:
anderskov 2022-01-19 14:11:17 +08:00
parent ed0aece3ed
commit f2c86ebb07
37 changed files with 515 additions and 394 deletions

View File

@ -62,6 +62,11 @@ Note:If the text contains special characters, please escape them according to th
<filteritem type="filepath" name="test/unittest/resource/testdata/dwarf/.*" desc="test resource file, no license header"/>
<filteritem type="filepath" name="test/unittest/resource/testdata/report/.*" desc="test resource file, no license header"/>
<filteritem type="filepath" name="test/fuzztest/resource/testdata/.*" desc="test resource file, no license header"/>
<filteritem type="filepath" name="test/fuzztest/ClientApi_fuzzer/corpus/init" desc="unified format file of fuzzy test architecture, no license header"/>
<filteritem type="filepath" name="test/fuzztest/CommandLine_fuzzer/corpus/init" desc="unified format file of fuzzy test architecture, no license header"/>
<filteritem type="filepath" name="test/fuzztest/ElfParser_fuzzer/corpus/init" desc="unified format file of fuzzy test architecture, no license header"/>
<filteritem type="filepath" name="test/fuzztest/LibReport_fuzzer/corpus/init" desc="unified format file of fuzzy test architecture, no license header"/>
<filteritem type="filepath" name="test/fuzztest/PerfFile_fuzzer/corpus/init" desc="unified format file of fuzzy test architecture, no license header"/>
</filefilter>
<filefilter name="copyrightPolicyFilter" desc="Filters for copyright header policies" >
<filteritem type="filepath" name="test/unittest/resource/testdata/.*" desc="test resource file, no copyright header"/>

View File

@ -28,7 +28,6 @@ declare_args() {
hiperf_debug = true
hiperf_code_analyze = false
hiperf_use_syspara = true
have_common_tools = true
}
code_check_flag = [

View File

@ -38,9 +38,9 @@
namespace OHOS {
namespace Developtools {
namespace HiPerf {
const int MAX_CALL_FRAME_EXPEND_CYCLE = 10;
const size_t MAX_CALL_FRAME_EXPEND_CACHE_SIZE = 10;
const size_t MAX_CALL_FRAME_UNWIND_SIZE = 30;
const int MAX_CALL_FRAME_EXPAND_CYCLE = 10;
const size_t MAX_CALL_FRAME_EXPAND_CACHE_SIZE = 10;
const size_t MAX_CALL_FRAME_UNWIND_SIZE = 256;
// if ip is 0 , 1 both not usefule
const uint64_t BAD_IP_ADDRESS = 2;
@ -55,7 +55,7 @@ public:
bool UnwindCallStack(const VirtualThread &thread, bool abi32, u64 *regs, u64 regsNum,
const u8 *stack, u64 stackSize, std::vector<CallFrame> &,
size_t maxStackLevel = MAX_CALL_FRAME_UNWIND_SIZE);
size_t ExpendCallStack(pid_t tid, std::vector<CallFrame> &callFrames, size_t expendLimit = 1u);
size_t ExpandCallStack(pid_t tid, std::vector<CallFrame> &callFrames, size_t expandLimit = 1u);
private:
uint64_t stackPoint_ = 0;
@ -66,8 +66,8 @@ private:
u64 stackSize_ = 0;
void LogFrame(const std::string msg, const std::vector<CallFrame> &frames);
size_t ExpendCallStack(std::vector<CallFrame> &newCallFrames,
const std::vector<CallFrame> &cachedCallFrames, size_t expendLimit);
size_t DoExpandCallStack(std::vector<CallFrame> &newCallFrames,
const std::vector<CallFrame> &cachedCallFrames, size_t expandLimit);
// we have a cache for all thread
std::map<pid_t, HashList<uint64_t, std::vector<CallFrame>>> cachedCallFramesMap_;

View File

@ -16,11 +16,14 @@
#ifndef MEMMAPITEM_H
#define MEMMAPITEM_H
#include <utilities.h>
#include <sstream>
#include <string>
#include <sys/types.h>
namespace OHOS {
namespace Developtools {
namespace HiPerf {
class MemMapItem {
public:
uint64_t begin_ = 0;
@ -32,10 +35,15 @@ public:
uint64_t minor_ = 0;
ino_t inode = 0;
std::string name_;
std::string_view nameHold_;
MemMapItem() {}
MemMapItem(uint64_t begin, uint64_t end, uint64_t offset, const std::string &name)
: begin_(begin), end_(end), pageoffset_(offset), name_(name)
: begin_(begin),
end_(end),
pageoffset_(offset),
name_(name),
nameHold_(MemoryHold::Get().HoldStringView(name))
{
}
@ -87,4 +95,7 @@ public:
return addr >= begin_ and addr < end_;
}
};
#endif
} // namespace HiPerf
} // namespace Developtools
} // namespace OHOS
#endif

View File

@ -245,7 +245,9 @@ public:
bool GetBinary(std::vector<uint8_t> &buf) const override;
virtual void DumpData(int indent = 0) const override;
virtual void DumpLog(const std::string &prefix) const override;
void ReplaceWithCallStack();
// originalSize is use for expand callstack
void ReplaceWithCallStack(size_t originalSize = 0);
pid_t GetPid() const override;
// only for UT

View File

@ -256,6 +256,7 @@ public:
void SetTimeOut(float timeOut);
void SetTimeReport(int);
void SetVerboseReport(bool);
bool AddOffCpuEvent();
inline void SetTrackedCommand(const std::vector<std::string> &trackedCommand)
{
@ -346,7 +347,6 @@ public:
};
static const std::string GetTypeName(perf_type_id type_id);
bool CheckPermissions(PerfEventParanoid request = KERNEL_USER_CPU);
bool ParseEventName(const std::string &nameStr, std::string &name, bool &excludeUser,
bool &excludeKernel, bool &isTracePoint);
@ -399,6 +399,16 @@ private:
bool HaveTargetsExit(const std::chrono::steady_clock::time_point &startTime);
void ExitReadRecordBufThread();
enum EventSpaceType {
UNKNOW = 0,
USER = 1,
KERNEL = 2,
USER_KERNEL = 3,
};
uint8_t eventSpaceType_ = EventSpaceType::UNKNOW;
PerfEventParanoid requestPermission_ = PerfEventParanoid::USER;
bool CheckPermissions(PerfEventParanoid request = KERNEL_USER_CPU);
bool CheckOhosPermissions();
static PerfEventParanoid perfEventParanoid_;

View File

@ -312,7 +312,7 @@ struct ReportConfigItem {
ReportConfigItem(int index, std::string eventName) : index_(index), eventName_(eventName) {}
};
using functionKey = std::tuple<int, std::string>;
using functionKey = std::tuple<int, std::string_view>;
static constexpr const int keyLibId = 0;
static constexpr const int keyfuncName = 1;

View File

@ -23,7 +23,7 @@
#define HIDEBUG_SKIP_MATCH_SYMBOLS 0
#define HIDEBUG_SKIP_LOAD_KERNEL_SYMBOLS 0
#define HIDEBUG_SKIP_SAVE_SYMBOLS 0
#define USE_COLLECT_SYMBOLIC
#define USE_COLLECT_SYMBOLIC 1
#include <thread>
#include <unordered_map>
@ -122,7 +122,7 @@ public:
" --disable-unwind\n"
" If '-s dwarf' is used, stack will be unwind while recording by default\n"
" use this option to disable unwinding.\n"
" --disable-callstack-expend\n"
" --disable-callstack-expand\n"
" If '-s dwarf' is used, to break the 64k stack limit, callstack is merged by default\n"
" to build more complete call stack. that may not be correct sometimes.\n"
" --clockid <clock_id>\n"
@ -191,7 +191,7 @@ private:
std::vector<pid_t> selectTids_ = {};
std::vector<std::string> selectEvents_ = {};
std::vector<std::vector<std::string>> selectGroups_ = {};
std::vector<std::string> sampleTypes_ = {};
std::vector<std::string> callStackType_ = {};
std::vector<std::string> vecBranchFilters_ = {};
std::vector<std::string> trackedCommand_ = {};
@ -201,9 +201,9 @@ private:
bool CheckSelectCpuPidOption();
bool GetOptionFrequencyAndPeriod(std::vector<std::string> &args);
bool dwarfCallchainSample_ = false;
bool fpCallchainSample_ = false;
uint32_t dwarfSampleStackSize_ = MAX_SAMPLE_STACK_SIZE;
bool isCallStackDwarf_ = false;
bool isCallStackFp_ = false;
uint32_t callStackDwarfSize_ = MAX_SAMPLE_STACK_SIZE;
uint64_t branchSampleType_ = 0;
uint64_t dataSizeLimit_ = 0;
bool isDataSizeLimitStop_ = false;
@ -228,22 +228,9 @@ private:
bool WaitFifoReply(int fd);
void CloseClientThread();
// just a debug test function
bool AddSelectEvent(std::vector<std::string> &events, bool groups = false);
enum EventSpaceType {
NONE = 0,
USER = 1,
KERNEL = 2,
USER_KERNEL = 3,
};
uint8_t eventSpaceType_ = EventSpaceType::NONE;
PerfEventParanoid request_ = PerfEventParanoid::USER;
bool ParseEventList(std::vector<std::string> &list);
bool ParseGroupList(std::vector<std::vector<std::string>> &list);
bool PreparePerfEvent();
bool PrepareSys();
bool PrepareVR();
bool PrepareSysKernel();
bool PrepareVirtualRuntime();
size_t recordSamples_ = 0;
size_t recordNoSamples_ = 0;
@ -277,7 +264,7 @@ private:
bool SetPerfMaxSampleRate();
bool TraceOffCpu();
bool ParseCallStackOption(const std::vector<std::string> &vecSampleTypes);
bool ParseCallStackOption(const std::vector<std::string> &callStackType);
bool ParseDataLimitOption(const std::string &str);
bool ParseBranchSampleType(const std::vector<std::string> &vecBranchSampleTypes);
bool ParseControlCmd(const std::string cmd);
@ -287,7 +274,7 @@ private:
pid_t GetAppPackagePid(const std::string &appPackge);
VirtualRuntime virtualRuntime_;
#ifdef USE_COLLECT_SYMBOLIC
#if USE_COLLECT_SYMBOLIC
std::unordered_set<uint64_t> kernelSymbolsHits_;
std::unordered_map<pid_t, std::unordered_set<uint64_t>> userSymbolsHits_;
void SymbolicHits();

View File

@ -88,7 +88,6 @@ private:
bool verboseReport_ {false};
std::vector<std::string> trackedCommand_ {};
bool helpOption_ {false};
PerfEventParanoid request_ = USER;
bool CheckOptionPid(std::vector<pid_t> pids);
static bool FindEventCount(
const std::map<std::string, std::unique_ptr<PerfEvents::CountEvent>> &countEvents,
@ -113,8 +112,6 @@ private:
bool PrepairEvents();
bool CheckOptions(const std::vector<pid_t> &pids);
bool CheckSelectCpuPidOption();
bool ParseEventList(std::vector<std::string> &list);
bool ParseGroupList(std::vector<std::vector<std::string>> &list);
};
bool RegisterSubCommandStat(void);

View File

@ -92,7 +92,12 @@ struct Symbol {
// Symbolic use this
Symbol(uint64_t taskVaddr = 0, const std::string &comm = "")
: taskVaddr_(taskVaddr), comm_(comm) {};
: taskVaddr_(taskVaddr), comm_(comm)
{
};
// copy
Symbol(const Symbol &other) = default;
static bool SameVaddr(const Symbol &a, const Symbol &b)
{
@ -142,7 +147,8 @@ struct Symbol {
} else {
sstream << comm_ << "@0x" << std::hex << taskVaddr_;
}
unknow_ = MemoryHold::Get().HoldStringView(sstream.str());
std::string hold = sstream.str();
unknow_ = MemoryHold::Get().HoldStringView(hold);
}
return unknow_;
}
@ -170,6 +176,11 @@ struct Symbol {
sstream << demangle_ << "|";
sstream << name_ << "|";
sstream << (matched_ ? "matched" : "");
sstream << " unknowname:" << unknow_.size();
sstream << " task:" << (comm_.size() > 0 ? comm_ : "");
sstream << "@" << taskVaddr_;
sstream << " file:" << (module_.size() > 0 ? module_ : "");
sstream << "@" << fileVaddr_;
return sstream.str();
};

View File

@ -195,7 +195,7 @@ std::string StringPrintf(const char *stringFormat, VA... args)
}
// print it to bytes
if (snprintf_s(bytes, DEFAULT_STRING_BUF_SIZE, DEFAULT_STRING_BUF_SIZE - 1, stringFormat,
if (snprintf_s(bytes, sizeof(bytes), sizeof(bytes) - 1, stringFormat,
args...) < 0) {
return EMPTY_STRING;
}

View File

@ -61,7 +61,7 @@ static const std::string ArgOffCPU = "--offcpu";
static const std::string ArgCallGraph = "--call-stack";
static const std::string ArgDelayUnwind = "--delay-unwind";
static const std::string ArgDisableUnwind = "--disable-unwind";
static const std::string ArgDisableCallstackMerge = "--disable-callstack-expend";
static const std::string ArgDisableCallstackMerge = "--disable-callstack-expand";
static const std::string ArgSymbolDir = "--symbol-dir";
static const std::string ArgOutputFilename = "-o";
static const std::string ArgDataLimit = "--data-limit";

View File

@ -19,7 +19,7 @@
}
],
"test_list": [
"//developtools/hiperf/test:hiperf_unittest"
"//developtools/hiperf/test:hiperf_test"
]
}
}

View File

@ -27,10 +27,9 @@ protoc_cmdline=$*
echo protoc_cmdline $protoc_cmdline
# search one by bone
PREBUILD_HOST_AOSP_RUNTIME=$BUILD_TOP/prebuilts/aosp_prebuilt_libs/host_tools/lib64
PREBUILD_HOST_CLANG_RUNTIME=$BUILD_TOP/prebuilts/clang/host/linux-x86/clang-r353983c/lib64
PREBUILD_OHOS_CLANG_RUNTIME=$BUILD_TOP/prebuilts/clang/ohos/linux-x86_64/llvm/lib
export LD_LIBRARY_PATH=$PREBUILD_HOST_AOSP_RUNTIME:$PREBUILD_HOST_CLANG_RUNTIME:$PREBUILD_OHOS_CLANG_RUNTIME:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH=$PREBUILD_HOST_CLANG_RUNTIME:$PREBUILD_OHOS_CLANG_RUNTIME:$LD_LIBRARY_PATH
cmd="$protoc_cmdline"
echo $cmd
$cmd

View File

@ -2539,7 +2539,7 @@ input{
if (rowElement.querySelector('.tree-icon')) {
rowElement.querySelector('.tree-icon').name = 'plus-square';
}
rowElement.removeAttribute('expend');
rowElement.removeAttribute('expand');
};
const expendNode = (rowElement) => {
let id = rowElement.getAttribute('id');
@ -2553,9 +2553,9 @@ input{
if (rowElement.querySelector('.tree-icon')) {
rowElement.querySelector('.tree-icon').name = 'minus-square';
}
rowElement.setAttribute('expend', '');
rowElement.setAttribute('expand', '');
}
if (rowElement.hasAttribute('expend')) {
if (rowElement.hasAttribute('expand')) {
foldNode(rowElement);
} else {
expendNode(rowElement);
@ -2580,7 +2580,7 @@ input{
parentNode.append(rowElement);
rowElement.setAttribute('id', rowData[ids[0]]);
rowElement.setAttribute('pid', rowData[ids[1]]);
rowElement.setAttribute('expend', '');
rowElement.setAttribute('expand', '');
if (rowData.children && rowData.children.length > 0) {
//有子节点的 前面加上 + 图标 表示可以展开节点

View File

@ -2901,7 +2901,7 @@ input{
if (rowElement.querySelector('.tree-icon')) {
rowElement.querySelector('.tree-icon').name = 'plus-square';
}
rowElement.removeAttribute('expend');
rowElement.removeAttribute('expand');
};
const expendNode = (rowElement) => {
let id = rowElement.getAttribute('id');
@ -2915,9 +2915,9 @@ input{
if (rowElement.querySelector('.tree-icon')) {
rowElement.querySelector('.tree-icon').name = 'minus-square';
}
rowElement.setAttribute('expend', '');
rowElement.setAttribute('expand', '');
}
if (rowElement.hasAttribute('expend')) {
if (rowElement.hasAttribute('expand')) {
foldNode(rowElement);
} else {
expendNode(rowElement);
@ -2942,7 +2942,7 @@ input{
parentNode.append(rowElement);
rowElement.setAttribute('id', rowData[ids[0]]);
rowElement.setAttribute('pid', rowData[ids[1]]);
rowElement.setAttribute('expend', '');
rowElement.setAttribute('expand', '');
if (rowData.children && rowData.children.length > 0) {
//有子节点的 前面加上 + 图标 表示可以展开节点

View File

@ -510,7 +510,7 @@ void CallStack::LogFrame(const std::string msg, const std::vector<CallFrame> &fr
/*
we should have CallStack cache for each thread
end begin
0. A -> B -> C -> E -> F
1. C -> E -> F
2. B -> C
@ -521,73 +521,90 @@ we should have CallStack cache for each thread
0 is our cache
1 2 3... is from record
use expendLimit to setup how may frame match is needs
use expandLimit to setup how may frame match is needs
*/
size_t CallStack::ExpendCallStack(std::vector<CallFrame> &newCallFrames,
const std::vector<CallFrame> &cachedCallFrames,
size_t expendLimit)
size_t CallStack::DoExpandCallStack(std::vector<CallFrame> &newCallFrames,
const std::vector<CallFrame> &cachedCallFrames,
size_t expandLimit)
{
int maxCycle = 0;
HLOG_ASSERT(expendLimit != 0u);
HLOG_ASSERT(newCallFrames.size() >= expendLimit);
// begin is ip (Bottom), this will change when compare
auto cachedIt = cachedCallFrames.begin(); // from begin
// end is caller (Top) , this will not change when compare
const auto newIt = std::prev(newCallFrames.end());
if (expandLimit == 0 or newCallFrames.size() < expandLimit or
cachedCallFrames.size() < expandLimit) {
HLOGM("expandLimit %zu not match new %zu cache %zu", expandLimit, newCallFrames.size(),
cachedCallFrames.size());
return 0; // size not enough
}
HLOGDUMMY("find %s + %zu", newIt->ToString().c_str(), expendLimit);
// called (Stack Buttom) , this will NOT change when compare
// in case1 newIt -> C
// in case2 newIt -> B
const auto newIt = newCallFrames.end() - expandLimit;
// first time earch
cachedIt = find(cachedIt, cachedCallFrames.end(), *newIt);
HLOGM("try find new call chain bottom %s for limit %zu", newIt->ToString().c_str(),
expandLimit);
// first frame earch, from called - > caller
// for case 2 it should found B
ssize_t distances = expandLimit - 1;
auto cachedIt = find(cachedCallFrames.begin(), cachedCallFrames.end(), *newIt);
if (cachedIt == cachedCallFrames.end()) {
HLOGM("not found in first search");
}
// cache frame found
while (std::distance(cachedIt, cachedCallFrames.end()) >=
std::distance(newIt, newCallFrames.end())) {
HLOG_ASSERT_MESSAGE(maxCycle++ < MAX_CALL_FRAME_EXPEND_CYCLE, "MAX_UNWIND_CYCLE = %d reach",
MAX_CALL_FRAME_EXPEND_CYCLE);
while (std::distance(cachedIt, cachedCallFrames.end()) >= signed(expandLimit)) {
HLOG_ASSERT_MESSAGE(maxCycle++ < MAX_CALL_FRAME_EXPAND_CYCLE, "MAX_UNWIND_CYCLE = %d reach",
MAX_CALL_FRAME_EXPAND_CYCLE);
if (std::equal(newIt, newIt + expendLimit - 1u, cachedIt)) {
HLOGM("match %s + %zu", newIt->ToString().c_str(), expendLimit);
cachedIt++;
if (std::equal(newIt, newIt + expandLimit, cachedIt)) {
HLOGM("match %s + %zu", newIt->ToString().c_str(), expandLimit);
cachedIt += expandLimit; // in while we check the boundary safe
if (cachedIt == cachedCallFrames.end()) {
HLOGM("nothing need copy , the rest of the frame is the same");
// same but no more need expand
break;
}
// expend the frame and make some log ?
// expand the frame and make some log ?
LogFrame("newCallStack:", newCallFrames);
LogFrame("cachedCallStack:", cachedCallFrames);
newCallFrames.insert(newCallFrames.end(), cachedIt, cachedCallFrames.end());
HLOGV("merge callstack increse to %zu (+%zu) ", newCallFrames.size(),
std::distance(cachedIt, cachedCallFrames.end()));
auto expands = std::distance(cachedIt, cachedCallFrames.end());
HLOGV("merge callstack increse to %zu (+%zd) ", newCallFrames.size(), expands);
// we done the deal
return std::distance(cachedIt, cachedCallFrames.end());
return expands;
} else {
// quick search again
cachedIt = find(cachedIt, cachedCallFrames.end(), *newIt);
// quick search next same farme again
cachedIt++;
if (cachedIt != cachedCallFrames.end()) {
HLOGM("search next");
cachedIt = find(cachedIt, cachedCallFrames.end(), *newIt);
}
}
}
return 0u; // nothing expend
HLOGM("cachedIt distance %zd , need %zd", std::distance(cachedCallFrames.begin(), cachedIt),
distances);
return 0u; // nothing expand
}
size_t CallStack::ExpendCallStack(pid_t tid, std::vector<CallFrame> &callFrames, size_t expendLimit)
size_t CallStack::ExpandCallStack(pid_t tid, std::vector<CallFrame> &callFrames, size_t expandLimit)
{
size_t expend = 0u;
if (expendLimit == 0) {
return expend; // nothing need to do
} else if (callFrames.size() < expendLimit) {
size_t expand = 0u;
if (expandLimit == 0) {
return expand; // nothing need to do
} else if (callFrames.size() < expandLimit) {
HLOGM("new callstack is too small, skip it");
return expend;
return expand;
}
if (!cachedCallFramesMap_.count(tid)) {
cachedCallFramesMap_[tid].reserve(MAX_CALL_FRAME_EXPEND_CACHE_SIZE);
cachedCallFramesMap_[tid].reserve(MAX_CALL_FRAME_EXPAND_CACHE_SIZE);
}
if (callFrames.size() >= 1u) {
// get top (Earliest caller)
HashList<uint64_t, std::vector<CallFrame>> &cachedCallFrames = cachedCallFramesMap_[tid];
HLOGV("find call stack frames in cahce %zu", cachedCallFrames.size());
HLOGV("find call stack frames in cahce size %zu", cachedCallFrames.size());
// compare
using namespace std::rel_ops; // enable complement comparing operators
for (auto itr = cachedCallFrames.begin(); itr < cachedCallFrames.end(); ++itr) {
@ -603,12 +620,12 @@ size_t CallStack::ExpendCallStack(pid_t tid, std::vector<CallFrame> &callFrames,
4 insert A after B in new stack
*/
const std::vector<CallFrame> &cachedCallStack = *itr;
if (cachedCallStack.size() < expendLimit) {
if (cachedCallStack.size() < expandLimit) {
HLOGM("cache callstack is too small, skip it");
break;
continue; // check next
}
expend = ExpendCallStack(callFrames, cachedCallStack, expendLimit);
if (expend > 0) {
expand = DoExpandCallStack(callFrames, cachedCallStack, expandLimit);
if (expand > 0) {
break;
}
}
@ -617,8 +634,8 @@ size_t CallStack::ExpendCallStack(pid_t tid, std::vector<CallFrame> &callFrames,
// vector
cachedCallFrames[callFrames[0].ip_] = callFrames;
}
HLOGM("expend %zu", expend);
return expend;
HLOGM("expand %zu", expand);
return expand;
}
CallStack::CallStack() {}
@ -633,4 +650,4 @@ CallStack::~CallStack()
}
} // namespace HiPerf
} // namespace Developtools
} // namespace OHOS
} // namespace OHOS

View File

@ -40,7 +40,7 @@ bool Command::DispatchCommands(std::vector<std::string> arguments)
arguments.erase(arguments.begin());
if (!commandOption->callBackFunction(arguments)) {
printf("unknown options: %s\n", arguments.front().c_str());
printf("unknown options: %s\nUse the help command to view help.\n", arguments.front().c_str());
return false;
}
// goto next args

View File

@ -116,7 +116,7 @@ int DebugLogger::Log(DebugLevel level, const std::string &logTag, const char *fm
const auto startWriteTime = steady_clock::now();
#endif
milliseconds timeStamp = duration_cast<milliseconds>(startTime - timeStamp_);
fprintf(file_, "%05" PRId64 "ms %s", (uint64_t)timeStamp.count(), buffer.data()); // to the file
fprintf(file_, "%05" PRId64 "ms %s", (int64_t)timeStamp.count(), buffer.data()); // to the file
#ifdef HIPERF_DEBUG_TIME
logWriteTimes_ += duration_cast<microseconds>(steady_clock::now() - startWriteTime);
#endif

View File

@ -19,6 +19,9 @@ namespace Developtools {
namespace HiPerf {
static bool OnVerboseLevel(const std::vector<std::string> &debugLevel)
{
if (debugLevel.size() <= 0) {
return false;
}
DebugLogger::GetInstance()->SetLogLevel(LEVEL_VERBOSE);
DebugLogger::GetInstance()->Disable(false);
return true;
@ -26,6 +29,9 @@ static bool OnVerboseLevel(const std::vector<std::string> &debugLevel)
static bool OnMuchLevel(const std::vector<std::string> &debugLevel)
{
if (debugLevel.size() <= 0) {
return false;
}
DebugLogger::GetInstance()->SetLogLevel(LEVEL_MUCH);
DebugLogger::GetInstance()->Disable(false);
return true;
@ -33,6 +39,9 @@ static bool OnMuchLevel(const std::vector<std::string> &debugLevel)
static bool OnDebugLevel(const std::vector<std::string> &debugLevel)
{
if (debugLevel.size() <= 0) {
return false;
}
DebugLogger::GetInstance()->SetLogLevel(LEVEL_DEBUG);
DebugLogger::GetInstance()->Disable(false);
return true;
@ -40,12 +49,18 @@ static bool OnDebugLevel(const std::vector<std::string> &debugLevel)
static bool OnNoDebug(const std::vector<std::string> &debugLevel)
{
if (debugLevel.size() <= 0) {
return false;
}
DebugLogger::GetInstance()->Disable();
return true;
}
static bool OnMixLogOutput(const std::vector<std::string> &debugLevel)
{
if (debugLevel.size() <= 0) {
return false;
}
DebugLogger::GetInstance()->SetMixLogOutput(true);
return true;
}
@ -55,6 +70,8 @@ static bool OnLogPath(std::vector<std::string> &args)
if (args.size() > 0) {
DebugLogger::GetInstance()->SetLogPath(args[0]);
args.erase(args.begin());
} else {
return false;
}
return true;
}
@ -64,6 +81,8 @@ static bool OnLogTag(std::vector<std::string> &args)
if (args.size() > 0) {
DebugLogger::GetInstance()->SetLogTags(args[0]);
args.erase(args.begin());
} else {
return false;
}
return true;
}
@ -76,19 +95,28 @@ static bool OnHiLog(const std::vector<std::string> &args)
#endif
void RegisterMainCommandDebug()
{
Option::RegisterMainOption("--nodebug", "disbale debug log", OnNoDebug);
Option::RegisterMainOption("--debug", "show debug log", OnDebugLevel);
Option::RegisterMainOption("--verbose", "show debug log", OnVerboseLevel);
Option::RegisterMainOption("--much", "show extremely much debug log", OnMuchLevel);
Option::RegisterMainOption("--mixlog", "mix the log in output", OnMixLogOutput);
Option::RegisterMainOption("--logpath", "log file name full path", OnLogPath);
Option::RegisterMainOption(
"--logtag", "enable log level for HILOG_TAG, usage format: <tag>[:level][,<tag>[:level]]",
OnLogTag);
Option::RegisterMainOption("--nodebug", "disbale debug log, usage format: --nodebug [command] [args]",
OnNoDebug);
Option::RegisterMainOption("--debug", "show debug log, usage format: --debug [command] [args]",
OnDebugLevel);
Option::RegisterMainOption("--verbose", "show debug log, usage format: --verbose [command] [args]",
OnVerboseLevel);
Option::RegisterMainOption("--much", "show extremely much debug log, usage format: --much [command] [args]",
OnMuchLevel);
Option::RegisterMainOption("--mixlog", "mix the log in output, usage format: --much [command] [args]",
OnMixLogOutput);
Option::RegisterMainOption("--logpath",
"log file name full path, usage format: --logpath [filepath] [command] [args]",
OnLogPath);
std::string tagUsage = StringPrintf("%s\t%-20s\t%s\t%-20s\t%s",
"enable log level for HILOG_TAG, usage format: --logtag <tag>[:level][,<tag>[:level]] [command] [args]\n", " ",
"tag: Dump, Report, Record, Stat... level: D, V, M...\n", " ",
"example: hiperf --verbose --logtag Record:D [command] [args]");
Option::RegisterMainOption("--logtag", tagUsage.c_str(), OnLogTag);
#if is_ohos && !is_double_framework
Option::RegisterMainOption("--hilog", "use hilog not file to record log", OnHiLog);
#endif
}
} // namespace HiPerf
} // namespace Developtools
} // namespace OHOS
} // namespace OHOS

View File

@ -159,20 +159,30 @@ void PerfRecordSample::DumpLog(const std::string &prefix) const
data_.reg_nr, data_.dyn_size, data_.time);
}
void PerfRecordSample::ReplaceWithCallStack()
void PerfRecordSample::ReplaceWithCallStack(size_t originalSize)
{
// first we check if we have some user unwind stack need to merge ?
if (callFrames_.size() != 0) {
// when we have some kernel ips , we cp it first
// new size is user call frames + kernel call frames + PERF_CONTEXT_USER(last +1)
ips_.reserve(callFrames_.size() + data_.nr + 1);
// new size is user call frames + kernel call frames
// + PERF_CONTEXT_USER(last + 1) + expand mark(also PERF_CONTEXT_USER)
const unsigned int perfContextSize = 2;
ips_.reserve(data_.nr + callFrames_.size() + perfContextSize);
if (data_.nr > 0) {
ips_.assign(data_.ips, data_.ips + data_.nr);
}
// add user context mark
ips_.emplace_back(PERF_CONTEXT_USER);
// we also need make a expand mark just for debug only
const size_t beginIpsSize = ips_.size();
bool ret = std::all_of(callFrames_.begin(), callFrames_.end(), [&](const CallFrame &frame) {
ips_.emplace_back(frame.ip_);
if (originalSize != 0 and (originalSize != callFrames_.size()) and
ips_.size() == (originalSize + beginIpsSize)) {
// just for debug
// so we can see which frame begin is expand call frames
ips_.emplace_back(PERF_CONTEXT_USER);
}
return true;
});
if (ret) {
@ -343,9 +353,22 @@ void PerfRecordSample::DumpData(int indent) const
PrintIndent(indent, "period %lld\n", data_.period);
}
if (sampleType_ & PERF_SAMPLE_CALLCHAIN) {
bool userContext = false;
PrintIndent(indent, "callchain nr=%lld\n", data_.nr);
for (uint64_t i = 0; i < data_.nr; ++i) {
PrintIndent(indent + 1, "0x%llx\n", data_.ips[i]);
std::string_view supplement = "";
if ((sampleType_ & PERF_SAMPLE_STACK_USER) == 0 || data_.ips[i] != PERF_CONTEXT_USER) {
PrintIndent(indent + 1, "0x%llx%s\n", data_.ips[i], supplement.data());
continue;
}
// is PERF_SAMPLE_STACK_USER type and is PERF_CONTEXT_USER
if (!userContext) {
userContext = true;
supplement = " <unwind callstack>";
} else {
supplement = " <expand callstack>";
}
PrintIndent(indent + 1, "0x%llx%s\n", data_.ips[i], supplement.data());
}
}
if (sampleType_ & PERF_SAMPLE_RAW) {
@ -855,4 +878,4 @@ void PerfRecordSwitchCpuWide::DumpData(int indent) const
}
} // namespace HiPerf
} // namespace Developtools
} // namespace OHOS
} // namespace OHOS

View File

@ -205,6 +205,17 @@ bool PerfEvents::AddDefaultEvent(perf_type_id type)
return true;
}
bool PerfEvents::AddOffCpuEvent()
{
std::string eventName = "sched:sched_switch";
if (eventSpaceType_ == EventSpaceType::USER) {
eventName += ":u";
} else if (eventSpaceType_ == EventSpaceType::KERNEL) {
eventName += ":k";
}
return AddEvent(eventName);
}
bool PerfEvents::AddEvents(const std::vector<std::string> &eventStrings, bool group)
{
bool followGroup = false;
@ -290,6 +301,17 @@ bool PerfEvents::AddEvent(const std::string &eventString, bool followGroup)
if (!ParseEventName(eventString, eventName, excludeUser, excludeKernel, isTracePointEvent)) {
return false;
}
if (excludeUser) {
if (requestPermission_ > PerfEventParanoid::KERNEL_USER) {
requestPermission_ = PerfEventParanoid::KERNEL_USER;
}
eventSpaceType_ |= EventSpaceType::KERNEL;
} else if (excludeKernel) {
eventSpaceType_ |= EventSpaceType::USER;
} else {
eventSpaceType_ |= EventSpaceType::USER_KERNEL;
}
if (isTracePointEvent) {
if (PERF_TRACEPOINT_CONFIGS.empty()) {
@ -471,6 +493,11 @@ static void RecoverCaptureSig()
bool PerfEvents::PrepareTracking(void)
{
HLOGV("enter");
if (!CheckPermissions(requestPermission_)) {
return false;
}
// 1. prepare cpu pid
if (!PrepareFdEvents()) {
HLOGE("PrepareFdEvents() failed");
@ -682,6 +709,12 @@ void PerfEvents::SetSystemTarget(bool systemTarget)
void PerfEvents::SetCpu(std::vector<pid_t> cpus)
{
cpus_ = cpus;
if (!cpus_.empty()) {
if (requestPermission_ > PerfEventParanoid::KERNEL_USER_CPU) {
requestPermission_ = PerfEventParanoid::KERNEL_USER_CPU;
}
}
}
void PerfEvents::SetPid(std::vector<pid_t> pids)

View File

@ -148,7 +148,7 @@ void ReportJsonFile::AddReportCallStackReverse(uint64_t eventCount, ReportCallNo
ReportCallNodeItem &grandchildren = GetOrCreateMapItem(*child, funcId);
if (debug_) {
grandchildren.nodeIndex_ = nodeIndex_++;
grandchildren.funcName_ = std::get<1>(functionList_.at(funcId));
grandchildren.funcName_ = std::get<keyfuncName>(functionList_.at(funcId));
}
// only the last one need count
if (it + 1 == frames.rend()) {

View File

@ -21,7 +21,12 @@
namespace OHOS {
namespace Developtools {
namespace HiPerf {
RingBuffer::RingBuffer(size_t size) : buf_(new uint8_t[size]), size_(size) {}
RingBuffer::RingBuffer(size_t size) : size_(size)
{
if (size > 0) {
buf_ = std::make_unique<uint8_t[]>(size);
}
}
RingBuffer::~RingBuffer() {}

View File

@ -242,6 +242,8 @@ void SubCommandDump::DumpPrintFileHeader(int indent)
// read here , because we need found symbols
reader_->ReadFeatureSection();
SetDeviceArch(GetArchTypeFromUname(reader_->GetFeatureString(FEATURE::ARCH)));
// found symbols in file
for (auto &featureSection : reader_->GetFeatureSections()) {
if (featureSection.get()->featureId_ == FEATURE::HIPERF_FILES_SYMBOL) {
@ -396,7 +398,8 @@ void SubCommandDump::DumpCallChain(int indent, std::unique_ptr<PerfRecordSample>
indent += LEVEL1;
for (auto frameIt = sample->callFrames_.begin(); frameIt != sample->callFrames_.end();
frameIt++) {
PrintIndent(indent, "%s\n", frameIt->ToSymbolString().c_str());
PrintIndent(indent, "%02zd:%s\n", std::distance(frameIt, sample->callFrames_.end()),
frameIt->ToSymbolString().c_str());
}
}
}

View File

@ -25,7 +25,7 @@ namespace HiPerf {
bool SubCommandHelp::OnSubCommand(std::vector<std::string> &args)
{
HLOGV("enter");
OnHelp(args);
return true;
}
@ -40,9 +40,9 @@ bool SubCommandHelp::OnHelp(std::vector<std::string> &args)
if (args.empty()) {
const auto &mainOptions = Option::GetMainOptions();
HLOGD("%zu options found:", mainOptions.size());
printf("Usage: hiperf [options] COMMAND [args for command]\n");
printf("Usage: hiperf [options] command [args for command]\n");
printf("Options:\n");
printf("options:\n");
for (const auto &commandOption : mainOptions) {
printf("\t%-20s\t%s\n", commandOption.first.c_str(),
commandOption.second->help.c_str());
@ -50,11 +50,11 @@ bool SubCommandHelp::OnHelp(std::vector<std::string> &args)
auto &commands = SubCommand::GetSubCommands();
HLOGD("%zu cmds found:", commands.size());
printf("Command:\n");
printf("command:\n");
for (const auto &command : commands) {
printf("\t%s:\t%s\n", command.second->Name().c_str(), command.second->Brief().c_str());
}
printf("\nSee 'hiperf help COMMAND' for more information on a specific command.\n\n");
printf("\nSee 'hiperf help [command]' for more information on a specific command.\n\n");
} else {
auto command = SubCommand::FindSubCommand(args.front());
if (command != nullptr) {

View File

@ -126,7 +126,7 @@ void SubCommandRecord::DumpOptions() const
printf(" clockId_:\t%s\n", clockId_.c_str());
printf(" mmapPages_:\t%d\n", mmapPages_);
printf(" dataLimit:\t%s\n", strLimit_.c_str());
printf(" callStack:\t%s\n", VectorToString(sampleTypes_).c_str());
printf(" callStack:\t%s\n", VectorToString(callStackType_).c_str());
printf(" branchSampleTypes:\t%s\n", VectorToString(vecBranchFilters_).c_str());
printf(" trackedCommand:\t%s\n", VectorToString(trackedCommand_).c_str());
printf(" pipe_input:\t%d\n", clientPipeInput_);
@ -156,7 +156,7 @@ bool SubCommandRecord::GetOptions(std::vector<std::string> &args)
if (!Option::GetOptionValue(args, "--disable-unwind", disableUnwind_)) {
return false;
}
if (!Option::GetOptionValue(args, "--disable-callstack-expend", disableCallstackExpend_)) {
if (!Option::GetOptionValue(args, "--disable-callstack-expand", disableCallstackExpend_)) {
return false;
}
if (!Option::GetOptionValue(args, "--verbose", verboseReport_)) {
@ -201,21 +201,21 @@ bool SubCommandRecord::GetOptions(std::vector<std::string> &args)
if (!Option::GetOptionValue(args, "-g", selectGroups_)) {
return false;
}
if (!Option::GetOptionValue(args, "-s", sampleTypes_)) {
if (!Option::GetOptionValue(args, "-s", callStackType_)) {
return false;
}
std::vector<std::string> sampleTypesB = {};
if (!Option::GetOptionValue(args, "--call-stack", sampleTypesB)) {
std::vector<std::string> callStackType = {};
if (!Option::GetOptionValue(args, "--call-stack", callStackType)) {
return false;
}
if (!sampleTypes_.empty()) {
if (!sampleTypesB.empty()) {
if (!callStackType_.empty()) {
if (!callStackType.empty()) {
printf("'-s %s --call-stack %s' option usage error, please check usage.\n",
VectorToString(sampleTypes_).c_str(), VectorToString(sampleTypesB).c_str());
VectorToString(callStackType_).c_str(), VectorToString(callStackType).c_str());
return false;
}
} else {
sampleTypes_ = sampleTypesB;
callStackType_ = callStackType;
}
if (!Option::GetOptionValue(args, "--data-limit", strLimit_)) {
@ -293,9 +293,6 @@ bool SubCommandRecord::CheckSelectCpuPidOption()
return false;
}
}
if (request_ > PerfEventParanoid::KERNEL_USER_CPU) {
request_ = PerfEventParanoid::KERNEL_USER_CPU;
}
}
if (!selectPids_.empty()) {
@ -346,15 +343,12 @@ bool SubCommandRecord::CheckOptions()
if (!CheckDataLimitOption()) {
return false;
}
if (!ParseCallStackOption(sampleTypes_)) {
if (!ParseCallStackOption(callStackType_)) {
return false;
}
if (!ParseBranchSampleType(vecBranchFilters_)) {
return false;
}
if (!ParseEventList(selectEvents_) || !ParseGroupList(selectGroups_)) {
return false;
}
if (!CheckSelectCpuPidOption()) {
return false;
}
@ -367,40 +361,6 @@ bool SubCommandRecord::CheckOptions()
return true;
}
bool SubCommandRecord::ParseEventList(std::vector<std::string> &list)
{
for (auto &nameStr : list) {
std::string name;
bool excludeUser = false;
bool excludeKernel = false;
bool isTracePoint = false;
if (!perfEvents_.ParseEventName(nameStr, name, excludeUser, excludeKernel, isTracePoint)) {
return false;
}
if (excludeUser) {
if (request_ > PerfEventParanoid::KERNEL_USER) {
request_ = PerfEventParanoid::KERNEL_USER;
}
eventSpaceType_ |= EventSpaceType::KERNEL;
} else if (excludeKernel) {
eventSpaceType_ |= EventSpaceType::USER;
} else {
eventSpaceType_ |= EventSpaceType::USER_KERNEL;
}
}
return true;
}
bool SubCommandRecord::ParseGroupList(std::vector<std::vector<std::string>> &list)
{
for (auto &evnetList : list) {
if (!ParseEventList(evnetList)) {
return false;
}
}
return true;
}
bool SubCommandRecord::ParseOption(std::vector<std::string> &args)
{
HLOGV("enter");
@ -543,47 +503,47 @@ bool SubCommandRecord::ParseDataLimitOption(const std::string &str)
return true;
}
bool SubCommandRecord::ParseCallStackOption(const std::vector<std::string> &vecSampleTypes)
bool SubCommandRecord::ParseCallStackOption(const std::vector<std::string> &callStackType)
{
if (vecSampleTypes.empty()) {
if (callStackType.empty()) {
return true;
} else if (vecSampleTypes[0] == "fp") {
if (vecSampleTypes.size() != 1) {
printf("Invalid -s value %s.\n", VectorToString(vecSampleTypes).c_str());
} else if (callStackType[0] == "fp") {
if (callStackType.size() != 1) {
printf("Invalid -s value %s.\n", VectorToString(callStackType).c_str());
return false;
}
fpCallchainSample_ = true;
} else if (vecSampleTypes[0] == "dwarf") {
if (vecSampleTypes.size() > MAX_DWARF_CALL_CHAIN) {
printf("Invalid -s value %s.\n", VectorToString(vecSampleTypes).c_str());
isCallStackFp_ = true;
} else if (callStackType[0] == "dwarf") {
if (callStackType.size() > MAX_DWARF_CALL_CHAIN) {
printf("Invalid -s value %s.\n", VectorToString(callStackType).c_str());
return false;
} else if (vecSampleTypes.size() == MAX_DWARF_CALL_CHAIN) {
} else if (callStackType.size() == MAX_DWARF_CALL_CHAIN) {
try {
dwarfSampleStackSize_ = std::stoul(vecSampleTypes.at(1));
callStackDwarfSize_ = std::stoul(callStackType.at(1));
} catch (...) {
printf("Invalid -s value, dwarf stack size, '%s' is illegal.\n",
vecSampleTypes.at(1).c_str());
callStackType.at(1).c_str());
return false;
}
if (dwarfSampleStackSize_ < MIN_SAMPLE_STACK_SIZE) {
if (callStackDwarfSize_ < MIN_SAMPLE_STACK_SIZE) {
printf("Invalid -s value, dwarf stack size, '%s' is too small.\n",
vecSampleTypes.at(1).c_str());
callStackType.at(1).c_str());
return false;
}
if (dwarfSampleStackSize_ > MAX_SAMPLE_STACK_SIZE) {
if (callStackDwarfSize_ > MAX_SAMPLE_STACK_SIZE) {
printf("Invalid -s value, dwarf stack size, '%s' is bigger than max value %d.\n",
vecSampleTypes.at(1).c_str(), MAX_SAMPLE_STACK_SIZE);
callStackType.at(1).c_str(), MAX_SAMPLE_STACK_SIZE);
return false;
}
if ((dwarfSampleStackSize_ & MASK_ALIGNED_8) != 0) {
if ((callStackDwarfSize_ & MASK_ALIGNED_8) != 0) {
printf("Invalid -s value, dwarf stack size, '%s' is not 8 byte aligned.\n",
vecSampleTypes.at(1).c_str());
callStackType.at(1).c_str());
return false;
}
}
dwarfCallchainSample_ = true;
isCallStackDwarf_ = true;
} else {
printf("Invalid -s value '%s'.\n", vecSampleTypes.at(0).c_str());
printf("Invalid -s value '%s'.\n", callStackType.at(0).c_str());
return false;
}
return true;
@ -675,9 +635,10 @@ bool SubCommandRecord::TraceOffCpu()
bool SubCommandRecord::PreparePerfEvent()
{
if (!perfEvents_.CheckPermissions(request_)) {
return false;
}
// we need to notify perfEvents_ sampling mode by SetRecordCallBack first
auto processRecord = std::bind(&SubCommandRecord::ProcessRecord, this, std::placeholders::_1);
perfEvents_.SetRecordCallBack(processRecord);
perfEvents_.SetCpu(selectCpus_);
perfEvents_.SetPid(selectPids_); // Tids has insert Pids in CheckTargetProcessOptions()
@ -685,11 +646,11 @@ bool SubCommandRecord::PreparePerfEvent()
perfEvents_.SetTimeOut(timeStopSec_);
perfEvents_.SetVerboseReport(verboseReport_);
perfEvents_.SetMmapPages(mmapPages_);
if (fpCallchainSample_) {
if (isCallStackFp_) {
perfEvents_.SetSampleStackType(PerfEvents::SampleStackType::FP);
} else if (dwarfCallchainSample_) {
} else if (isCallStackDwarf_) {
perfEvents_.SetSampleStackType(PerfEvents::SampleStackType::DWARF);
perfEvents_.SetDwarfSampleStackSize(dwarfSampleStackSize_);
perfEvents_.SetDwarfSampleStackSize(callStackDwarfSize_);
}
if (!perfEvents_.SetBranchSampleType(branchSampleType_)) {
printf("branch sample %s is not supported\n", VectorToString(vecBranchFilters_).c_str());
@ -714,24 +675,6 @@ bool SubCommandRecord::PreparePerfEvent()
selectEvents_.push_back("hw-cpu-cycles");
}
// cpu off add after default event (we need both sched_switch and user selected events)
if (offCPU_) {
if (std::find(selectEvents_.begin(), selectEvents_.end(), "sched_switch") ==
selectEvents_.end()) {
// insert a sched_switch event to trace offcpu event
if (eventSpaceType_ == EventSpaceType::USER_KERNEL) {
selectEvents_.push_back("sched:sched_switch");
} else if (eventSpaceType_ == EventSpaceType::KERNEL) {
selectEvents_.push_back("sched:sched_switch:k");
} else if (eventSpaceType_ == EventSpaceType::USER) {
selectEvents_.push_back("sched:sched_switch:u");
}
} else {
printf("--offcpu is not supported event sched_switch\n");
return false;
}
}
if (!perfEvents_.AddEvents(selectEvents_)) {
HLOGE("Fail to AddEvents events");
return false;
@ -742,11 +685,24 @@ bool SubCommandRecord::PreparePerfEvent()
return false;
}
}
// cpu off add after default event (we need both sched_switch and user selected events)
if (offCPU_) {
if (std::find(selectEvents_.begin(), selectEvents_.end(), "sched_switch") !=
selectEvents_.end()) {
printf("--offcpu is not supported event sched_switch\n");
return false;
}
// insert a sched_switch event to trace offcpu event
if (!perfEvents_.AddOffCpuEvent()) {
HLOGE("Fail to AddEOffCpuvent");
return false;
}
}
return true;
}
bool SubCommandRecord::PrepareSys()
bool SubCommandRecord::PrepareSysKernel()
{
if (!SetPerfMaxSampleRate()) {
HLOGE("Fail to call SetPerfMaxSampleRate(%d)", frequency_);
@ -764,8 +720,11 @@ bool SubCommandRecord::PrepareSys()
return true;
}
bool SubCommandRecord::PrepareVR()
bool SubCommandRecord::PrepareVirtualRuntime()
{
auto saveRecord = std::bind(&SubCommandRecord::SaveRecord, this, std::placeholders::_1);
virtualRuntime_.SetRecordMode(saveRecord);
// do some config for virtualRuntime_
virtualRuntime_.SetCallStackExpend(disableCallstackExpend_ ? 0 : 1);
// these is same for virtual runtime
@ -777,6 +736,12 @@ bool SubCommandRecord::PrepareVR()
}
}
// load vsdo first
virtualRuntime_.LoadVdso();
// prepare from kernel and ko
virtualRuntime_.UpdateKernelSpaceMaps();
virtualRuntime_.UpdateKernelModulesSpaceMaps();
return true;
}
@ -1025,18 +990,8 @@ bool SubCommandRecord::OnSubCommand(std::vector<std::string> &args)
return true;
}
// we need do some record in CreateInitRecordFile , so we need set callback before it
auto processRecord = std::bind(&SubCommandRecord::ProcessRecord, this, std::placeholders::_1);
auto saveRecord = std::bind(&SubCommandRecord::SaveRecord, this, std::placeholders::_1);
// two ways:
// perfEvents_ -> processRecord -> virtualRuntime_ -> saveRecord
// -> saveRecord
perfEvents_.SetRecordCallBack(processRecord);
virtualRuntime_.SetRecordMode(saveRecord);
// prepare PerfEvents
if (!PrepareSys() || !PreparePerfEvent() || !PrepareVR()) {
if (!PrepareSysKernel() or !PreparePerfEvent()) {
return false;
}
@ -1051,18 +1006,15 @@ bool SubCommandRecord::OnSubCommand(std::vector<std::string> &args)
return false;
}
if (!PrepareVirtualRuntime()) {
return false;
}
// make a thread wait the other command
if (clientPipeOutput_ != -1) {
clientCommandHanle_ = std::thread(&SubCommandRecord::ClientCommandHandle, this);
}
// load vsdo first
virtualRuntime_.LoadVdso();
// prepare from kernel and ko
virtualRuntime_.UpdateKernelSpaceMaps();
virtualRuntime_.UpdateKernelModulesSpaceMaps();
// start tracking
if (!perfEvents_.StartTracking(!isFifoServer_)) {
return false;
@ -1072,16 +1024,14 @@ bool SubCommandRecord::OnSubCommand(std::vector<std::string> &args)
if (!FinishWriteRecordFile()) {
HLOGE("Fail to finish record file %s", outputFilename_.c_str());
return false;
}
// post process record file
if (!PostProcessRecordFile()) {
} else if (!PostProcessRecordFile()) {
HLOGE("Fail to post process record file");
return false;
}
// finial report
RecordCompleted();
CloseClientThread();
return true;
}
@ -1405,8 +1355,8 @@ bool SubCommandRecord::PostProcessRecordFile()
}
return true;
}
#define USE_COLLECT_SYMBOLIC
#if USE_COLLECT_SYMBOLIC
void SubCommandRecord::SymbolicHits()
{
for (auto &vaddr : kernelSymbolsHits_) {
@ -1420,12 +1370,13 @@ void SubCommandRecord::SymbolicHits()
}
}
}
#endif
bool SubCommandRecord::CollectionSymbol(std::unique_ptr<PerfEventRecord> record)
{
if (record->GetType() == PERF_RECORD_SAMPLE) {
PerfRecordSample *sample = static_cast<PerfRecordSample *>(record.get());
#ifdef USE_COLLECT_SYMBOLIC
#if USE_COLLECT_SYMBOLIC
perf_callchain_context context = record->inKernel() ? PERF_CONTEXT_KERNEL
: PERF_CONTEXT_USER;
// if no nr use ip
@ -1475,7 +1426,7 @@ bool SubCommandRecord::FinishWriteRecordFile()
HLOGD("Load user symbols");
fileWriter_->ReadDataSection(
std::bind(&SubCommandRecord::CollectionSymbol, this, std::placeholders::_1));
#ifdef USE_COLLECT_SYMBOLIC
#if USE_COLLECT_SYMBOLIC
SymbolicHits();
#endif
HLOGD("Write the symbols to perf.data");

View File

@ -13,6 +13,8 @@
* limitations under the License.
*/
#define HILOG_TAG "Stat"
#include <csignal>
#include <iostream>
#include <memory>
@ -144,13 +146,14 @@ bool SubCommandStat::FindEventCount(
const std::string &configName, const __u64 group_id, __u64 &eventCount, double &scale)
{
auto itr = countEvents.find(configName);
if (itr != countEvents.end() && itr->second->id == group_id) {
if (itr->second->time_running < itr->second->time_enabled &&
itr->second->time_running != 0) {
scale = static_cast<double>(itr->second->time_enabled) / itr->second->time_running;
}
if (itr != countEvents.end()) {
eventCount = itr->second->eventCount;
return true;
if (itr->second->id == group_id
&& itr->second->time_running < itr->second->time_enabled
&& itr->second->time_running != 0) {
scale = static_cast<double>(itr->second->time_enabled) / itr->second->time_running;
return true;
}
}
return false;
}
@ -306,33 +309,6 @@ bool SubCommandStat::CheckOptionPid(std::vector<pid_t> pids)
return true;
}
bool SubCommandStat::ParseEventList(std::vector<std::string> &list)
{
for (auto &nameStr : list) {
std::string name;
bool isUser = false;
bool isKernel = false;
bool isTracePoint = false;
if (!perfEvents_.ParseEventName(nameStr, name, isKernel, isUser, isTracePoint)) {
return false;
}
if (isKernel) {
request_ = KERNEL_USER;
}
}
return true;
}
bool SubCommandStat::ParseGroupList(std::vector<std::vector<std::string>> &list)
{
for (auto &evnetList : list) {
if (!ParseEventList(evnetList)) {
return false;
}
}
return true;
}
bool SubCommandStat::OnSubCommand(std::vector<std::string> &args)
{
HLOGV("enter");
@ -367,10 +343,6 @@ bool SubCommandStat::OnSubCommand(std::vector<std::string> &args)
printf("-t <tid> stat events on existing thread id\n");
return false;
}
// check event
if (!ParseGroupList(selectEvents_) || !ParseGroupList(selectGroups_)) {
return false;
}
perfEvents_.SetSystemTarget(targetSystemWide_);
perfEvents_.SetTimeOut(timeStopSec_);
perfEvents_.SetTimeReport(timeReportMs_);
@ -401,9 +373,6 @@ bool RegisterSubCommandStat()
bool SubCommandStat::PrepairEvents()
{
if (!perfEvents_.CheckPermissions(request_)) {
return false;
}
if (selectEvents_.empty() && selectGroups_.empty()) {
perfEvents_.AddDefaultEvent(PERF_TYPE_HARDWARE);
perfEvents_.AddDefaultEvent(PERF_TYPE_SOFTWARE);
@ -436,7 +405,6 @@ bool SubCommandStat::CheckSelectCpuPidOption()
return false;
}
}
request_ = KERNEL_USER_CPU;
}
} else {
// the cpu default -1

View File

@ -981,7 +981,7 @@ public:
const auto thisTime = std::chrono::steady_clock::now();
const auto usedTimeMsTick =
std::chrono::duration_cast<std::chrono::milliseconds>(thisTime - startTime);
HLOGV("Load kernel symbols (total %" PRId64 " ms)\n", (uint64_t)usedTimeMsTick.count());
HLOGV("Load kernel symbols (total %" PRId64 " ms)\n", (int64_t)usedTimeMsTick.count());
// load complete
return true;
}

View File

@ -300,6 +300,7 @@ void VirtualRuntime::MakeCallFrame(Symbol &symbol, CallFrame &callFrame)
callFrame.symbolName_ = symbol.Name();
callFrame.symbolIndex_ = symbol.index_;
callFrame.filePath_ = symbol.module_.empty() ? symbol.comm_ : symbol.module_;
HLOG_ASSERT_MESSAGE(!callFrame.symbolName_.empty(), "%s", symbol.ToDebugString().c_str());
}
void VirtualRuntime::SymbolicCallFrame(PerfRecordSample &recordSample, uint64_t ip,
@ -362,11 +363,12 @@ void VirtualRuntime::UnwindFromRecord(PerfRecordSample &recordSample)
#endif
size_t oldSize = recordSample.callFrames_.size();
HLOGV("unwind %zu", recordSample.callFrames_.size());
callstack_.ExpendCallStack(thread.tid_, recordSample.callFrames_, callstackMergeLevel_);
HLOGV("expend %zu (+%zu)", recordSample.callFrames_.size(),
callstack_.ExpandCallStack(thread.tid_, recordSample.callFrames_, callstackMergeLevel_);
HLOGV("expand %zu (+%zu)", recordSample.callFrames_.size(),
recordSample.callFrames_.size() - oldSize);
recordSample.ReplaceWithCallStack(oldSize);
}
recordSample.ReplaceWithCallStack();
#ifdef HIPERF_DEBUG_TIME
unwindFromRecordTimes_ += duration_cast<microseconds>(steady_clock::now() - startTime);
@ -521,7 +523,7 @@ const Symbol VirtualRuntime::GetUserSymbol(uint64_t ip, const VirtualThread &thr
if (symbolsFile != nullptr) {
vaddrSymbol.fileVaddr_ =
symbolsFile->GetVaddrInSymbols(ip, mmap->begin_, mmap->pageoffset_);
vaddrSymbol.module_ = mmap->name_;
vaddrSymbol.module_ = mmap->nameHold_;
HLOGV("found symbol vaddr 0x%" PRIx64 " for runtime vaddr 0x%" PRIx64 " at '%s'",
vaddrSymbol.fileVaddr_, ip, mmap->name_.c_str());
if (!symbolsFile->SymbolsLoaded()) {
@ -557,13 +559,14 @@ bool VirtualRuntime::GetSymbolCache(uint64_t ip, pid_t pid, pid_t tid, Symbol &s
}
Symbol &foundSymbol = kernelSymbolCache_[ip];
foundSymbol.hit_++;
HLOGM("hit kernel cache 0x%" PRIx64 " %d", ip, foundSymbol.hit_);
HLOGV("hit kernel cache 0x%" PRIx64 " %d", ip, foundSymbol.hit_);
symbol = foundSymbol;
return true;
} else if (threadSymbolCache_[tid].count(ip)) {
} else if (threadSymbolCache_[tid].count(ip) != 0) {
Symbol &foundSymbol = threadSymbolCache_[tid][ip];
foundSymbol.hit_++;
HLOGM("hit user cache 0x%" PRIx64 " %d", ip, foundSymbol.hit_);
HLOGV("hit user cache 0x%" PRIx64 " %d %s", ip, foundSymbol.hit_,
foundSymbol.ToDebugString().c_str());
symbol = foundSymbol;
return true;
} else {
@ -575,9 +578,9 @@ bool VirtualRuntime::GetSymbolCache(uint64_t ip, pid_t pid, pid_t tid, Symbol &s
const Symbol VirtualRuntime::GetSymbol(uint64_t ip, pid_t pid, pid_t tid,
const perf_callchain_context &context)
{
HLOGM("try find tid %u ip 0x%" PRIx64 " in %zu symbolsFiles ", tid, ip, symbolsFiles_.size());
HLOGV("try find tid %u ip 0x%" PRIx64 " in %zu symbolsFiles ", tid, ip, symbolsFiles_.size());
Symbol symbol;
if (!threadSymbolCache_.count(tid)) {
if (threadSymbolCache_.find(tid) == threadSymbolCache_.end()) {
threadSymbolCache_[tid].reserve(THREAD_SYMBOL_CACHE_LIMIT);
}
if (GetSymbolCache(ip, pid, tid, symbol, context)) {
@ -587,6 +590,8 @@ const Symbol VirtualRuntime::GetSymbol(uint64_t ip, pid_t pid, pid_t tid,
// check userspace memmap
symbol = GetUserSymbol(ip, GetThread(pid, tid));
threadSymbolCache_[tid][ip] = symbol;
HLOGV("cache ip 0x%" PRIx64 " to %s", ip,
threadSymbolCache_[tid][ip].ToDebugString().c_str());
}
if (context == PERF_CONTEXT_KERNEL or (context == PERF_CONTEXT_MAX and !symbol.isValid())) {

View File

@ -180,14 +180,10 @@ group("hiperf_test") {
":hiperf_fuzztest(${host_toolchain})",
":hiperf_unittest(${host_toolchain})",
]
} else if (hiperf_test_fuzz){
deps = [
":hiperf_fuzztest",
":hiperf_unittest",
]
} else {
deps = [
":hiperf_unittest",
]
deps = [ ":hiperf_unittest" ]
}
if (hiperf_test_fuzz) {
deps += [ ":hiperf_fuzztest" ]
}
}

View File

@ -16,6 +16,7 @@
#include "callstack_test.h"
using namespace testing::ext;
using namespace testing;
using namespace std;
using namespace OHOS::HiviewDFX;
namespace OHOS {
@ -46,7 +47,7 @@ void CallStackTest::SetUp() {}
void CallStackTest::TearDown() {}
/**
* @tc.name: ExpendCallStack
* @tc.name: ExpandCallStack
* @tc.desc:
* @tc.type: FUNC
*/
@ -56,7 +57,7 @@ HWTEST_F(CallStackTest, ExpendCallStackEmpty, TestSize.Level1)
3 2 1
cache A -> B -> C
new C
expend A -> B -> C
expand A -> B -> C
*/
ScopeDebugLevel tempLogLevel(LEVEL_MUCH);
CallStack callStack;
@ -68,13 +69,13 @@ HWTEST_F(CallStackTest, ExpendCallStackEmpty, TestSize.Level1)
};
std::vector<CallFrame> stack2 = {};
ASSERT_EQ(callStack.ExpendCallStack(0, stack1), 0u);
ASSERT_EQ(callStack.ExpendCallStack(0, stack2), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 0u);
ASSERT_NE(stack1, stack2);
}
/**
* @tc.name: ExpendCallStack
* @tc.name: ExpandCallStack
* @tc.desc:
* @tc.type: FUNC
*/
@ -84,7 +85,7 @@ HWTEST_F(CallStackTest, ExpendCallStackC, TestSize.Level1)
3 2 1
cache A -> B -> C
new C
expend A -> B -> C
expand A -> B -> C
*/
ScopeDebugLevel tempLogLevel(LEVEL_MUCH);
CallStack callStack;
@ -98,13 +99,13 @@ HWTEST_F(CallStackTest, ExpendCallStackC, TestSize.Level1)
{0x1u, 0x1u},
};
ASSERT_EQ(callStack.ExpendCallStack(0, stack1), 0u);
ASSERT_EQ(callStack.ExpendCallStack(0, stack2), 2u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 2u);
ASSERT_EQ(stack1, stack2);
}
/**
* @tc.name: ExpendCallStack
* @tc.name: ExpandCallStack
* @tc.desc:
* @tc.type: FUNC
*/
@ -114,7 +115,7 @@ HWTEST_F(CallStackTest, ExpendCallStackBC, TestSize.Level1)
3 2 1
cache A -> B -> C
new B -> C
expend A -> B -> C
expand A -> B -> C
*/
ScopeDebugLevel tempLogLevel(LEVEL_MUCH);
CallStack callStack;
@ -129,13 +130,13 @@ HWTEST_F(CallStackTest, ExpendCallStackBC, TestSize.Level1)
{0x2u, 0x2u},
};
ASSERT_EQ(callStack.ExpendCallStack(0, stack1), 0u);
ASSERT_EQ(callStack.ExpendCallStack(0, stack2), 1u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 1u);
ASSERT_EQ(stack1, stack2);
}
/**
* @tc.name: ExpendCallStack
* @tc.name: ExpandCallStack
* @tc.desc:
* @tc.type: FUNC
*/
@ -145,7 +146,7 @@ HWTEST_F(CallStackTest, ExpendCallStackABC, TestSize.Level1)
3 2 1
cache A -> B -> C
new A -> B -> C
expend A -> B -> C
expand A -> B -> C
*/
ScopeDebugLevel tempLogLevel(LEVEL_MUCH);
CallStack callStack;
@ -161,13 +162,13 @@ HWTEST_F(CallStackTest, ExpendCallStackABC, TestSize.Level1)
{0x3u, 0x3u},
};
ASSERT_EQ(callStack.ExpendCallStack(0, stack1), 0u);
ASSERT_EQ(callStack.ExpendCallStack(0, stack2), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 0u);
ASSERT_EQ(stack1, stack2);
}
/**
* @tc.name: ExpendCallStack
* @tc.name: ExpandCallStack
* @tc.desc:
* @tc.type: FUNC
*/
@ -177,7 +178,7 @@ HWTEST_F(CallStackTest, ExpendCallStackAB, TestSize.Level1)
3 2 1
cache A -> B -> C
new A -> B
expend A -> B
expand A -> B
*/
ScopeDebugLevel tempLogLevel(LEVEL_MUCH);
CallStack callStack;
@ -192,13 +193,13 @@ HWTEST_F(CallStackTest, ExpendCallStackAB, TestSize.Level1)
{0x3u, 0x3u},
};
ASSERT_EQ(callStack.ExpendCallStack(0, stack1), 0u);
ASSERT_EQ(callStack.ExpendCallStack(0, stack2), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 0u);
ASSERT_NE(stack1, stack2);
}
/**
* @tc.name: ExpendCallStack
* @tc.name: ExpandCallStack
* @tc.desc:
* @tc.type: FUNC
*/
@ -208,7 +209,7 @@ HWTEST_F(CallStackTest, ExpendCallStackA, TestSize.Level1)
3 2 1
cache A -> B -> C
new A
expend A
expand A
*/
ScopeDebugLevel tempLogLevel(LEVEL_MUCH);
CallStack callStack;
@ -222,13 +223,13 @@ HWTEST_F(CallStackTest, ExpendCallStackA, TestSize.Level1)
{0x3u, 0x3u},
};
ASSERT_EQ(callStack.ExpendCallStack(0, stack1), 0u);
ASSERT_EQ(callStack.ExpendCallStack(0, stack2), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 0u);
ASSERT_NE(stack1, stack2);
}
/**
* @tc.name: ExpendCallStack
* @tc.name: ExpandCallStack
* @tc.desc:
* @tc.type: FUNC
*/
@ -238,7 +239,7 @@ HWTEST_F(CallStackTest, ExpendCallStackB, TestSize.Level1)
3 2 1
cache A -> B -> C
new B
expend A -> B
expand A -> B
*/
ScopeDebugLevel tempLogLevel(LEVEL_MUCH);
CallStack callStack;
@ -255,14 +256,14 @@ HWTEST_F(CallStackTest, ExpendCallStackB, TestSize.Level1)
{0x2u, 0x2u},
{0x3u, 0x3u},
};
ASSERT_EQ(callStack.ExpendCallStack(0, stack1), 0u);
ASSERT_EQ(callStack.ExpendCallStack(0, stack2), 1u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 1u);
ASSERT_NE(stack1, stack2);
ASSERT_EQ(stack3, stack2);
}
/**
* @tc.name: ExpendCallStack
* @tc.name: ExpandCallStack
* @tc.desc:
* @tc.type: FUNC
*/
@ -272,7 +273,7 @@ HWTEST_F(CallStackTest, ExpendCallStackB2, TestSize.Level1)
3 2 1
cache A -> B -> C
new B
expend A -> B
expand A -> B
*/
ScopeDebugLevel tempLogLevel(LEVEL_MUCH);
CallStack callStack;
@ -289,14 +290,14 @@ HWTEST_F(CallStackTest, ExpendCallStackB2, TestSize.Level1)
{0x2u, 0x2u},
{0x3u, 0x3u},
};
ASSERT_EQ(callStack.ExpendCallStack(0, stack1, 2), 0u);
ASSERT_EQ(callStack.ExpendCallStack(0, stack2, 2), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack1, 2), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack2, 2), 0u);
ASSERT_NE(stack1, stack2);
ASSERT_NE(stack3, stack2);
}
/**
* @tc.name: ExpendCallStack
* @tc.name: ExpandCallStack
* @tc.desc:
* @tc.type: FUNC
*/
@ -306,7 +307,7 @@ HWTEST_F(CallStackTest, ExpendCallStackB0, TestSize.Level1)
3 2 1
cache A -> B -> C
new B
expend A -> B
expand A -> B
*/
ScopeDebugLevel tempLogLevel(LEVEL_MUCH);
CallStack callStack;
@ -323,14 +324,14 @@ HWTEST_F(CallStackTest, ExpendCallStackB0, TestSize.Level1)
{0x2u, 0x2u},
{0x3u, 0x3u},
};
ASSERT_EQ(callStack.ExpendCallStack(0, stack1, 0), 0u);
ASSERT_EQ(callStack.ExpendCallStack(0, stack2, 0), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack1, 0), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack2, 0), 0u);
ASSERT_NE(stack1, stack2);
ASSERT_NE(stack3, stack2);
}
/**
* @tc.name: ExpendCallStack
* @tc.name: ExpandCallStack
* @tc.desc:
* @tc.type: FUNC
*/
@ -340,9 +341,9 @@ HWTEST_F(CallStackTest, ExpendCallStackBC2, TestSize.Level1)
3 2 1
cache A -> B -> C
new B -> C
expend A -> B -> C
expand A -> B -> C
*/
ScopeDebugLevel tempLogLevel(LEVEL_MUCH);
ScopeDebugLevel tempLogLevel(LEVEL_MUCH, true);
CallStack callStack;
std::vector<CallFrame> stack1 = {
@ -355,13 +356,13 @@ HWTEST_F(CallStackTest, ExpendCallStackBC2, TestSize.Level1)
{0x2u, 0x2u},
};
ASSERT_EQ(callStack.ExpendCallStack(0, stack1, 2), 0u);
ASSERT_EQ(callStack.ExpendCallStack(0, stack2, 2), 1u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack1, 2), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack2, 2), 1u);
ASSERT_EQ(stack1, stack2);
}
/**
* @tc.name: ExpendCallStack
* @tc.name: ExpandCallStack
* @tc.desc:
* @tc.type: FUNC
*/
@ -400,17 +401,17 @@ HWTEST_F(CallStackTest, ExpendCallStackABCDE, TestSize.Level1)
{0xB, 0xB},
};
ASSERT_EQ(callStack.ExpendCallStack(0, stackFull), 0u);
ASSERT_EQ(callStack.ExpendCallStack(0, stackBC), 1u);
ASSERT_EQ(callStack.ExpendCallStack(0, stackABC), 0u);
ASSERT_EQ(callStack.ExpendCallStack(0, stackBFF), 1u);
ASSERT_EQ(callStack.ExpandCallStack(0, stackFull), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stackBC), 1u);
ASSERT_EQ(callStack.ExpandCallStack(0, stackABC), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stackBFF), 1u);
// use stackBFF
ASSERT_EQ(callStack.ExpendCallStack(0, stackBFF2, 2), 1u);
ASSERT_EQ(callStack.ExpandCallStack(0, stackBFF2, 2), 1u);
}
/**
* @tc.name: ExpendCallStack
* @tc.name: ExpandCallStack
* @tc.desc:
* @tc.type: FUNC
*/
@ -436,12 +437,12 @@ HWTEST_F(CallStackTest, ExpendCallStackFailure, TestSize.Level1)
{0xD, 0xD},
};
ASSERT_EQ(callStack.ExpendCallStack(0, stackFull), 0u);
ASSERT_EQ(callStack.ExpendCallStack(0, stackDE), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stackFull), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stackDE), 0u);
}
/**
* @tc.name: ExpendCallStack
* @tc.name: ExpandCallStack
* @tc.desc:
* @tc.type: FUNC
*/
@ -471,28 +472,28 @@ HWTEST_F(CallStackTest, ExpendCallStackTwoChance, TestSize.Level1)
{0xC, 0xC},
{0x2, 0x2},
};
ASSERT_EQ(callStack.ExpendCallStack(0, stack0), 0u);
ASSERT_EQ(callStack.ExpendCallStack(0, stack1), 0u);
ASSERT_EQ(callStack.ExpendCallStack(0, stackC), 1u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack0), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stackC), 1u);
}
/**
* @tc.name: ExpendCallStack
* @tc.name: ExpandCallStack
* @tc.desc:
* @tc.type: FUNC
*/
HWTEST_F(CallStackTest, ExpendCallStackFullCache, TestSize.Level1)
{
CallStack callStack;
for (size_t i = 0; i < MAX_CALL_FRAME_EXPEND_CACHE_SIZE; i++) {
for (size_t i = 0; i < MAX_CALL_FRAME_EXPAND_CACHE_SIZE; i++) {
std::vector<CallFrame> stack = {{rnd_(), rnd_()}};
callStack.ExpendCallStack(0, stack);
callStack.ExpandCallStack(0, stack);
}
for (size_t i = 0; i < MAX_CALL_FRAME_EXPEND_CACHE_SIZE; i++) {
for (size_t i = 0; i < MAX_CALL_FRAME_EXPAND_CACHE_SIZE; i++) {
std::vector<CallFrame> stack = {{rnd_(), rnd_()}};
callStack.ExpendCallStack(0, stack);
callStack.ExpandCallStack(0, stack);
}
EXPECT_EQ(callStack.cachedCallFramesMap_[0].size(), MAX_CALL_FRAME_EXPEND_CACHE_SIZE);
EXPECT_EQ(callStack.cachedCallFramesMap_[0].size(), MAX_CALL_FRAME_EXPAND_CACHE_SIZE);
}
/**
@ -531,7 +532,7 @@ HWTEST_F(CallStackTest, GetUnwErrorName, TestSize.Level1)
}
/**
* @tc.name: ExpendCallStack
* @tc.name: ExpandCallStack
* @tc.desc:
* @tc.type: FUNC
*/
@ -541,10 +542,100 @@ HWTEST_F(CallStackTest, ExpendCallStackSmall, TestSize.Level1)
std::vector<CallFrame> stack0 = {};
std::vector<CallFrame> stack1 = {{0x1, 0x1}};
std::vector<CallFrame> stack2 = {{0x1, 0x1}, {0x2, 0x2}};
ASSERT_EQ(callStack.ExpendCallStack(0, stack0), 0u);
ASSERT_EQ(callStack.ExpendCallStack(0, stack1), 0u);
ASSERT_EQ(callStack.ExpendCallStack(0, stack1), 0u);
ASSERT_EQ(callStack.ExpendCallStack(0, stack2, 2), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack0), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack2, 2), 0u);
}
/**
* @tc.name: ExpandCallStack
* @tc.desc:
* @tc.type: FUNC
*/
HWTEST_F(CallStackTest, ExpendCallStackLimit, TestSize.Level1)
{
/*
3 2 1 0
cache A -> B -> C
stack2 C
expand C
stack3 B -> C
expand A -> B -> C
stack4 C -> D
expand C
*/
ScopeDebugLevel tempLogLevel(LEVEL_MUCH, true);
CallStack callStack;
std::vector<CallFrame> stack1 = {
{0x1u, 0x1u},
{0x2u, 0x2u},
{0x3u, 0x3u},
};
std::vector<CallFrame> stack2 = {
{0x1u, 0x1u},
};
std::vector<CallFrame> stack3 = {
{0x1u, 0x1u},
{0x2u, 0x2u},
};
std::vector<CallFrame> stack4 = {
{0x0u, 0x0u},
{0x1u, 0x1u},
};
ASSERT_EQ(callStack.ExpandCallStack(0, stack1, 2u), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack2, 2u), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack3, 2u), 1u);
EXPECT_THAT(stack1, ContainerEq(stack3));
ASSERT_EQ(callStack.ExpandCallStack(0, stack4, 2u), 0u);
}
/**
* @tc.name: ExpandCallStack
* @tc.desc:
* @tc.type: FUNC
*/
HWTEST_F(CallStackTest, ExpendCallStackABABAB, TestSize.Level1)
{
/*
Caller Called
cache A -> B -> C -> A -> B -> C -> A -> B
stack2 C
expand A -> B -> C -> A -> B -> C
stack3 B -> C
expand A -> B -> C -> A -> B -> C
stack4 C -> D
expand A -> B -> C -> A -> B -> C -> D
*/
ScopeDebugLevel tempLogLevel(LEVEL_MUCH, true);
CallStack callStack;
std::vector<CallFrame> stack1 = {
{0xb, 0xb}, {0xa, 0xa}, {0xc, 0xc}, {0xb, 0xb},
{0xa, 0xa}, {0xc, 0xc}, {0xb, 0xb}, {0xa, 0xa},
};
std::vector<CallFrame> stack2 = {
{0xc, 0xc},
};
std::vector<CallFrame> stack3 = {
{0xc, 0xc},
{0xb, 0xb},
};
std::vector<CallFrame> stack4 = {
{0xd, 0xd},
{0xc, 0xc},
};
ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 5u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack3), 4u);
ASSERT_EQ(callStack.ExpandCallStack(0, stack4), 5u);
}
/**
* @tc.name: UnwindCallStack

View File

@ -49,7 +49,6 @@ void HiperfClientTest::SetUp() {}
void HiperfClientTest::TearDown()
{
this_thread::sleep_for(1s);
}
/**

View File

@ -200,8 +200,6 @@ HWTEST_F(PerfEventsTest, RecordNormal, TestSize.Level1)
event.SetMmapPages(DEFAULT_SAMPLE_MMAPAGE);
event.SetRecordCallBack(RecordCount);
ASSERT_TRUE(event.CheckPermissions());
std::vector<pid_t> selectCpus_;
event.SetCpu(selectCpus_);
std::vector<pid_t> pids;
@ -254,7 +252,6 @@ HWTEST_F(PerfEventsTest, RecordSetAll, TestSize.Level1)
g_recordCount = 0;
event.SetMmapPages(DEFAULT_SAMPLE_MMAPAGE);
event.SetRecordCallBack(RecordCount);
ASSERT_TRUE(event.CheckPermissions());
SetAllConfig(event);
ASSERT_EQ(event.PrepareTracking(), true);
std::thread runThread(RunTrack, std::ref(event));

View File

@ -569,7 +569,7 @@ HWTEST_F(SubCommandRecordTest, DisableUnwind, TestSize.Level1)
HWTEST_F(SubCommandRecordTest, DisableCallstackMerge, TestSize.Level1)
{
TestRecordCommand("-d 2 -s dwarf,16 --disable-callstack-expend ");
TestRecordCommand("-d 2 -s dwarf,16 --disable-callstack-expand ");
}
// symbol dir

View File

@ -1574,27 +1574,11 @@ HWTEST_F(SubCommandStatTest, TestOnSubCommand_cmd, TestSize.Level1)
HWTEST_F(SubCommandStatTest, TestOnSubCommand_ni, TestSize.Level1)
{
StdoutRecord stdoutRecord;
stdoutRecord.Start();
std::string testCMD {"stat -c 0 -d 3 --dumpoptions -e "};
const std::string configName {"sw-cpu-clock"};
testCMD += configName;
const std::string cmdPath {" ./../../../../developtools/hiperf/hiperf_example_cmd"};
testCMD += cmdPath;
const auto tick1 = std::chrono::steady_clock::now();
EXPECT_EQ(Command::DispatchCommand(testCMD), true);
const auto tock1 = std::chrono::steady_clock::now();
const auto costMs1 = std::chrono::duration_cast<std::chrono::milliseconds>(tock1 - tick1);
EXPECT_LE(costMs1.count(), defaultRunTimeoutMs);
std::string stringOut = stdoutRecord.Stop();
if (HasFailure()) {
printf("output:\n%s", stringOut.c_str());
}
int counterValueWithInherit = CounterValue(stringOut, configName);
EXPECT_NE(counterValueWithInherit, 0);
HLOGD("%s %d", configName.c_str(), counterValueWithInherit);
const std::string cmdPath {" ls"};
stdoutRecord.Start();
testCMD = "stat --no-inherit -c 0 -d 3 --dumpoptions -e ";
std::string testCMD = "stat --no-inherit -c 0 -d 3 --dumpoptions -e ";
testCMD += configName;
testCMD += cmdPath;
const auto tick2 = std::chrono::steady_clock::now();
@ -1602,7 +1586,7 @@ HWTEST_F(SubCommandStatTest, TestOnSubCommand_ni, TestSize.Level1)
const auto tock2 = std::chrono::steady_clock::now();
const auto costMs2 = std::chrono::duration_cast<std::chrono::milliseconds>(tock2 - tick2);
EXPECT_LE(costMs2.count(), defaultRunTimeoutMs);
stringOut = stdoutRecord.Stop();
std::string stringOut = stdoutRecord.Stop();
if (HasFailure()) {
printf("output:\n%s", stringOut.c_str());
}

View File

@ -50,7 +50,7 @@
<option name="push" value="testdata/syms_from_readelf_32 -> /data/test/resource/testdata/" src="res"/>
<option name="push" value="testdata/syms_from_readelf_64 -> /data/test/resource/testdata/" src="res"/>
<option name="push" value="testdata/symbols_file_test_elf32 -> /data/test/resource/testdata/" src="res"/>
<option name="push" value="testdata/symbols_file_test_elf32 -> /data/test/resource/testdata/" src="res"/>
<option name="push" value="testdata/symbols_file_test_elf64 -> /data/test/resource/testdata/" src="res"/>
<!--dwarf-->
<option name="push" value="testdata/dwarf/user_regs.dump -> /data/test/resource/testdata/dwarf/" src="res"/>