mirror of
https://gitee.com/openharmony/developtools_hiperf
synced 2024-11-26 17:21:15 +00:00
optimize command line interface
Signed-off-by: anderskov <zangleizhen@huawei.com>
This commit is contained in:
parent
ed0aece3ed
commit
f2c86ebb07
5
OAT.xml
5
OAT.xml
@ -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"/>
|
||||
|
@ -28,7 +28,6 @@ declare_args() {
|
||||
hiperf_debug = true
|
||||
hiperf_code_analyze = false
|
||||
hiperf_use_syspara = true
|
||||
have_common_tools = true
|
||||
}
|
||||
|
||||
code_check_flag = [
|
||||
|
@ -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_;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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_;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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";
|
||||
|
@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"test_list": [
|
||||
"//developtools/hiperf/test:hiperf_unittest"
|
||||
"//developtools/hiperf/test:hiperf_test"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
//有子节点的 前面加上 + 图标 表示可以展开节点
|
||||
|
||||
|
@ -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) {
|
||||
//有子节点的 前面加上 + 图标 表示可以展开节点
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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()) {
|
||||
|
@ -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() {}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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())) {
|
||||
|
@ -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" ]
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -49,7 +49,6 @@ void HiperfClientTest::SetUp() {}
|
||||
|
||||
void HiperfClientTest::TearDown()
|
||||
{
|
||||
this_thread::sleep_for(1s);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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"/>
|
||||
|
Loading…
Reference in New Issue
Block a user