From f2c86ebb07b7e7ad572a739b31bb6a5f936a4f88 Mon Sep 17 00:00:00 2001 From: anderskov Date: Wed, 19 Jan 2022 14:11:17 +0800 Subject: [PATCH] optimize command line interface Signed-off-by: anderskov --- OAT.xml | 5 + hiperf.gni | 1 - include/callstack.h | 12 +- include/mem_map_item.h | 19 +- include/perf_event_record.h | 4 +- include/perf_events.h | 12 +- include/report_json_file.h | 2 +- include/subcommand_record.h | 33 +-- include/subcommand_stat.h | 3 - include/symbols_file.h | 15 +- include/utilities.h | 2 +- .../innerkits/native/include/hiperf_client.h | 2 +- ohos.build | 2 +- proto/build_proto.sh | 3 +- script/report-diff.html | 8 +- script/report.html | 8 +- src/callstack.cpp | 105 +++++---- src/command.cpp | 2 +- src/debug_logger.cpp | 2 +- src/option_debug.cpp | 48 +++- src/perf_event_record.cpp | 33 ++- src/perf_events.cpp | 33 +++ src/report_json_file.cpp | 2 +- src/ring_buffer.cpp | 7 +- src/subcommand_dump.cpp | 5 +- src/subcommand_help.cpp | 10 +- src/subcommand_record.cpp | 193 ++++++--------- src/subcommand_stat.cpp | 48 +--- src/symbols_file.cpp | 2 +- src/virtual_runtime.cpp | 23 +- test/BUILD.gn | 12 +- .../unittest/common/native/callstack_test.cpp | 221 ++++++++++++------ .../common/native/hiperf_client_test.cpp | 1 - .../common/native/perf_events_test.cpp | 3 - .../common/native/subcommand_record_test.cpp | 2 +- .../common/native/subcommand_stat_test.cpp | 22 +- test/unittest/resource/ohos_test.xml | 2 +- 37 files changed, 514 insertions(+), 393 deletions(-) diff --git a/OAT.xml b/OAT.xml index 2880547..4045cec 100755 --- a/OAT.xml +++ b/OAT.xml @@ -62,6 +62,11 @@ Note:If the text contains special characters, please escape them according to th + + + + + diff --git a/hiperf.gni b/hiperf.gni index 2f7aac9..e578d0c 100644 --- a/hiperf.gni +++ b/hiperf.gni @@ -28,7 +28,6 @@ declare_args() { hiperf_debug = true hiperf_code_analyze = false hiperf_use_syspara = true - have_common_tools = true } code_check_flag = [ diff --git a/include/callstack.h b/include/callstack.h index 8e46cf7..a99c94a 100755 --- a/include/callstack.h +++ b/include/callstack.h @@ -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 &, size_t maxStackLevel = MAX_CALL_FRAME_UNWIND_SIZE); - size_t ExpendCallStack(pid_t tid, std::vector &callFrames, size_t expendLimit = 1u); + size_t ExpandCallStack(pid_t tid, std::vector &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 &frames); - size_t ExpendCallStack(std::vector &newCallFrames, - const std::vector &cachedCallFrames, size_t expendLimit); + size_t DoExpandCallStack(std::vector &newCallFrames, + const std::vector &cachedCallFrames, size_t expandLimit); // we have a cache for all thread std::map>> cachedCallFramesMap_; diff --git a/include/mem_map_item.h b/include/mem_map_item.h index f7f541b..a942ef1 100755 --- a/include/mem_map_item.h +++ b/include/mem_map_item.h @@ -16,11 +16,14 @@ #ifndef MEMMAPITEM_H #define MEMMAPITEM_H +#include + #include #include -#include - +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 \ No newline at end of file +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS +#endif diff --git a/include/perf_event_record.h b/include/perf_event_record.h index 1f7067f..09635d7 100755 --- a/include/perf_event_record.h +++ b/include/perf_event_record.h @@ -245,7 +245,9 @@ public: bool GetBinary(std::vector &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 diff --git a/include/perf_events.h b/include/perf_events.h index 174b9c1..5d25a42 100755 --- a/include/perf_events.h +++ b/include/perf_events.h @@ -256,6 +256,7 @@ public: void SetTimeOut(float timeOut); void SetTimeReport(int); void SetVerboseReport(bool); + bool AddOffCpuEvent(); inline void SetTrackedCommand(const std::vector &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_; diff --git a/include/report_json_file.h b/include/report_json_file.h index ec8a3ff..fa566a0 100755 --- a/include/report_json_file.h +++ b/include/report_json_file.h @@ -312,7 +312,7 @@ struct ReportConfigItem { ReportConfigItem(int index, std::string eventName) : index_(index), eventName_(eventName) {} }; -using functionKey = std::tuple; +using functionKey = std::tuple; static constexpr const int keyLibId = 0; static constexpr const int keyfuncName = 1; diff --git a/include/subcommand_record.h b/include/subcommand_record.h index b2185fa..ad5b685 100644 --- a/include/subcommand_record.h +++ b/include/subcommand_record.h @@ -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 #include @@ -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 \n" @@ -191,7 +191,7 @@ private: std::vector selectTids_ = {}; std::vector selectEvents_ = {}; std::vector> selectGroups_ = {}; - std::vector sampleTypes_ = {}; + std::vector callStackType_ = {}; std::vector vecBranchFilters_ = {}; std::vector trackedCommand_ = {}; @@ -201,9 +201,9 @@ private: bool CheckSelectCpuPidOption(); bool GetOptionFrequencyAndPeriod(std::vector &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 &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 &list); - bool ParseGroupList(std::vector> &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 &vecSampleTypes); + bool ParseCallStackOption(const std::vector &callStackType); bool ParseDataLimitOption(const std::string &str); bool ParseBranchSampleType(const std::vector &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 kernelSymbolsHits_; std::unordered_map> userSymbolsHits_; void SymbolicHits(); diff --git a/include/subcommand_stat.h b/include/subcommand_stat.h index 3cd805a..f08e72f 100644 --- a/include/subcommand_stat.h +++ b/include/subcommand_stat.h @@ -88,7 +88,6 @@ private: bool verboseReport_ {false}; std::vector trackedCommand_ {}; bool helpOption_ {false}; - PerfEventParanoid request_ = USER; bool CheckOptionPid(std::vector pids); static bool FindEventCount( const std::map> &countEvents, @@ -113,8 +112,6 @@ private: bool PrepairEvents(); bool CheckOptions(const std::vector &pids); bool CheckSelectCpuPidOption(); - bool ParseEventList(std::vector &list); - bool ParseGroupList(std::vector> &list); }; bool RegisterSubCommandStat(void); diff --git a/include/symbols_file.h b/include/symbols_file.h index bc9fee3..3c8f74a 100755 --- a/include/symbols_file.h +++ b/include/symbols_file.h @@ -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(); }; diff --git a/include/utilities.h b/include/utilities.h index 0458227..69fc4b1 100755 --- a/include/utilities.h +++ b/include/utilities.h @@ -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; } diff --git a/interfaces/innerkits/native/include/hiperf_client.h b/interfaces/innerkits/native/include/hiperf_client.h index 9f44c77..569dc5d 100644 --- a/interfaces/innerkits/native/include/hiperf_client.h +++ b/interfaces/innerkits/native/include/hiperf_client.h @@ -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"; diff --git a/ohos.build b/ohos.build index faec9de..87868c0 100644 --- a/ohos.build +++ b/ohos.build @@ -19,7 +19,7 @@ } ], "test_list": [ - "//developtools/hiperf/test:hiperf_unittest" + "//developtools/hiperf/test:hiperf_test" ] } } diff --git a/proto/build_proto.sh b/proto/build_proto.sh index c2e2886..407b54a 100755 --- a/proto/build_proto.sh +++ b/proto/build_proto.sh @@ -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 diff --git a/script/report-diff.html b/script/report-diff.html index 4c04270..9e2e40d 100755 --- a/script/report-diff.html +++ b/script/report-diff.html @@ -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) { //有子节点的 前面加上 + 图标 表示可以展开节点 diff --git a/script/report.html b/script/report.html index d1eab24..2bf535d 100755 --- a/script/report.html +++ b/script/report.html @@ -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) { //有子节点的 前面加上 + 图标 表示可以展开节点 diff --git a/src/callstack.cpp b/src/callstack.cpp index d6a8554..572a000 100755 --- a/src/callstack.cpp +++ b/src/callstack.cpp @@ -510,7 +510,7 @@ void CallStack::LogFrame(const std::string msg, const std::vector &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 &newCallFrames, - const std::vector &cachedCallFrames, - size_t expendLimit) +size_t CallStack::DoExpandCallStack(std::vector &newCallFrames, + const std::vector &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 &callFrames, size_t expendLimit) +size_t CallStack::ExpandCallStack(pid_t tid, std::vector &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> &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 &callFrames, 4 insert A after B in new stack */ const std::vector &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 &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 \ No newline at end of file +} // namespace OHOS diff --git a/src/command.cpp b/src/command.cpp index 5d5a42e..ec8a674 100755 --- a/src/command.cpp +++ b/src/command.cpp @@ -40,7 +40,7 @@ bool Command::DispatchCommands(std::vector 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 diff --git a/src/debug_logger.cpp b/src/debug_logger.cpp index e3679f3..4a844a2 100755 --- a/src/debug_logger.cpp +++ b/src/debug_logger.cpp @@ -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(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(steady_clock::now() - startWriteTime); #endif diff --git a/src/option_debug.cpp b/src/option_debug.cpp index 51cf254..7ed67a3 100755 --- a/src/option_debug.cpp +++ b/src/option_debug.cpp @@ -19,6 +19,9 @@ namespace Developtools { namespace HiPerf { static bool OnVerboseLevel(const std::vector &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 &debugLevel) static bool OnMuchLevel(const std::vector &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 &debugLevel) static bool OnDebugLevel(const std::vector &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 &debugLevel) static bool OnNoDebug(const std::vector &debugLevel) { + if (debugLevel.size() <= 0) { + return false; + } DebugLogger::GetInstance()->Disable(); return true; } static bool OnMixLogOutput(const std::vector &debugLevel) { + if (debugLevel.size() <= 0) { + return false; + } DebugLogger::GetInstance()->SetMixLogOutput(true); return true; } @@ -55,6 +70,8 @@ static bool OnLogPath(std::vector &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 &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 &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: [:level][,[: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 [:level][,[: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 \ No newline at end of file +} // namespace OHOS diff --git a/src/perf_event_record.cpp b/src/perf_event_record.cpp index f328e6d..f0fae6c 100755 --- a/src/perf_event_record.cpp +++ b/src/perf_event_record.cpp @@ -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 = " "; + } else { + supplement = " "; + } + 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 \ No newline at end of file +} // namespace OHOS diff --git a/src/perf_events.cpp b/src/perf_events.cpp index df333e8..ffafa55 100755 --- a/src/perf_events.cpp +++ b/src/perf_events.cpp @@ -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 &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 cpus) { cpus_ = cpus; + + if (!cpus_.empty()) { + if (requestPermission_ > PerfEventParanoid::KERNEL_USER_CPU) { + requestPermission_ = PerfEventParanoid::KERNEL_USER_CPU; + } + } } void PerfEvents::SetPid(std::vector pids) diff --git a/src/report_json_file.cpp b/src/report_json_file.cpp index 465d404..70a80d5 100755 --- a/src/report_json_file.cpp +++ b/src/report_json_file.cpp @@ -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(functionList_.at(funcId)); } // only the last one need count if (it + 1 == frames.rend()) { diff --git a/src/ring_buffer.cpp b/src/ring_buffer.cpp index 9cbdf6b..91a8343 100755 --- a/src/ring_buffer.cpp +++ b/src/ring_buffer.cpp @@ -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(size); + } +} RingBuffer::~RingBuffer() {} diff --git a/src/subcommand_dump.cpp b/src/subcommand_dump.cpp index 86d8031..cae2b0c 100644 --- a/src/subcommand_dump.cpp +++ b/src/subcommand_dump.cpp @@ -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 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()); } } } diff --git a/src/subcommand_help.cpp b/src/subcommand_help.cpp index b51be5f..d49f0bd 100644 --- a/src/subcommand_help.cpp +++ b/src/subcommand_help.cpp @@ -25,7 +25,7 @@ namespace HiPerf { bool SubCommandHelp::OnSubCommand(std::vector &args) { HLOGV("enter"); - + OnHelp(args); return true; } @@ -40,9 +40,9 @@ bool SubCommandHelp::OnHelp(std::vector &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 &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) { diff --git a/src/subcommand_record.cpp b/src/subcommand_record.cpp index f39dbdb..cfa270e 100644 --- a/src/subcommand_record.cpp +++ b/src/subcommand_record.cpp @@ -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 &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 &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 sampleTypesB = {}; - if (!Option::GetOptionValue(args, "--call-stack", sampleTypesB)) { + std::vector 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 &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> &list) -{ - for (auto &evnetList : list) { - if (!ParseEventList(evnetList)) { - return false; - } - } - return true; -} - bool SubCommandRecord::ParseOption(std::vector &args) { HLOGV("enter"); @@ -543,47 +503,47 @@ bool SubCommandRecord::ParseDataLimitOption(const std::string &str) return true; } -bool SubCommandRecord::ParseCallStackOption(const std::vector &vecSampleTypes) +bool SubCommandRecord::ParseCallStackOption(const std::vector &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 &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 &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 &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 record) { if (record->GetType() == PERF_RECORD_SAMPLE) { PerfRecordSample *sample = static_cast(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"); diff --git a/src/subcommand_stat.cpp b/src/subcommand_stat.cpp index 645250f..956cf05 100644 --- a/src/subcommand_stat.cpp +++ b/src/subcommand_stat.cpp @@ -13,6 +13,8 @@ * limitations under the License. */ +#define HILOG_TAG "Stat" + #include #include #include @@ -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) { + if (itr != countEvents.end()) { + eventCount = itr->second->eventCount; + if (itr->second->id == group_id + && itr->second->time_running < itr->second->time_enabled + && itr->second->time_running != 0) { scale = static_cast(itr->second->time_enabled) / itr->second->time_running; + return true; } - eventCount = itr->second->eventCount; - return true; } return false; } @@ -306,33 +309,6 @@ bool SubCommandStat::CheckOptionPid(std::vector pids) return true; } -bool SubCommandStat::ParseEventList(std::vector &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> &list) -{ - for (auto &evnetList : list) { - if (!ParseEventList(evnetList)) { - return false; - } - } - return true; -} - bool SubCommandStat::OnSubCommand(std::vector &args) { HLOGV("enter"); @@ -367,10 +343,6 @@ bool SubCommandStat::OnSubCommand(std::vector &args) printf("-t 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 diff --git a/src/symbols_file.cpp b/src/symbols_file.cpp index 0b0ef4d..ddcc531 100755 --- a/src/symbols_file.cpp +++ b/src/symbols_file.cpp @@ -981,7 +981,7 @@ public: const auto thisTime = std::chrono::steady_clock::now(); const auto usedTimeMsTick = std::chrono::duration_cast(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; } diff --git a/src/virtual_runtime.cpp b/src/virtual_runtime.cpp index 22928f8..48d2d12 100755 --- a/src/virtual_runtime.cpp +++ b/src/virtual_runtime.cpp @@ -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(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())) { diff --git a/test/BUILD.gn b/test/BUILD.gn index 67d749e..5334ee5 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -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" ] } } diff --git a/test/unittest/common/native/callstack_test.cpp b/test/unittest/common/native/callstack_test.cpp index a508efd..7fb0f9b 100755 --- a/test/unittest/common/native/callstack_test.cpp +++ b/test/unittest/common/native/callstack_test.cpp @@ -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 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 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 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 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 stack0 = {}; std::vector stack1 = {{0x1, 0x1}}; std::vector 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 stack1 = { + {0x1u, 0x1u}, + {0x2u, 0x2u}, + {0x3u, 0x3u}, + }; + std::vector stack2 = { + {0x1u, 0x1u}, + }; + std::vector stack3 = { + {0x1u, 0x1u}, + {0x2u, 0x2u}, + }; + std::vector 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 stack1 = { + {0xb, 0xb}, {0xa, 0xa}, {0xc, 0xc}, {0xb, 0xb}, + {0xa, 0xa}, {0xc, 0xc}, {0xb, 0xb}, {0xa, 0xa}, + }; + std::vector stack2 = { + {0xc, 0xc}, + }; + std::vector stack3 = { + {0xc, 0xc}, + {0xb, 0xb}, + }; + std::vector 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 diff --git a/test/unittest/common/native/hiperf_client_test.cpp b/test/unittest/common/native/hiperf_client_test.cpp index b702fc4..3b639f4 100644 --- a/test/unittest/common/native/hiperf_client_test.cpp +++ b/test/unittest/common/native/hiperf_client_test.cpp @@ -49,7 +49,6 @@ void HiperfClientTest::SetUp() {} void HiperfClientTest::TearDown() { - this_thread::sleep_for(1s); } /** diff --git a/test/unittest/common/native/perf_events_test.cpp b/test/unittest/common/native/perf_events_test.cpp index f7d2c49..eeb9d9d 100755 --- a/test/unittest/common/native/perf_events_test.cpp +++ b/test/unittest/common/native/perf_events_test.cpp @@ -200,8 +200,6 @@ HWTEST_F(PerfEventsTest, RecordNormal, TestSize.Level1) event.SetMmapPages(DEFAULT_SAMPLE_MMAPAGE); event.SetRecordCallBack(RecordCount); - ASSERT_TRUE(event.CheckPermissions()); - std::vector selectCpus_; event.SetCpu(selectCpus_); std::vector 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)); diff --git a/test/unittest/common/native/subcommand_record_test.cpp b/test/unittest/common/native/subcommand_record_test.cpp index 5d7fcc6..8085ec5 100644 --- a/test/unittest/common/native/subcommand_record_test.cpp +++ b/test/unittest/common/native/subcommand_record_test.cpp @@ -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 diff --git a/test/unittest/common/native/subcommand_stat_test.cpp b/test/unittest/common/native/subcommand_stat_test.cpp index 2849245..34e8b49 100644 --- a/test/unittest/common/native/subcommand_stat_test.cpp +++ b/test/unittest/common/native/subcommand_stat_test.cpp @@ -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(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(tock2 - tick2); EXPECT_LE(costMs2.count(), defaultRunTimeoutMs); - stringOut = stdoutRecord.Stop(); + std::string stringOut = stdoutRecord.Stop(); if (HasFailure()) { printf("output:\n%s", stringOut.c_str()); } diff --git a/test/unittest/resource/ohos_test.xml b/test/unittest/resource/ohos_test.xml index ef6d95f..217e100 100644 --- a/test/unittest/resource/ohos_test.xml +++ b/test/unittest/resource/ohos_test.xml @@ -50,7 +50,7 @@