diff --git a/include/perf_event_record.h b/include/perf_event_record.h index ae10c66..c394acd 100644 --- a/include/perf_event_record.h +++ b/include/perf_event_record.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -39,63 +40,34 @@ namespace OHOS { namespace Developtools { namespace HiPerf { using namespace OHOS::HiviewDFX; +using PerfRecordType = int32_t; static constexpr uint32_t RECORD_SIZE_LIMIT = 65535; static constexpr uint32_t RECORD_SIZE_LIMIT_SPE = 524288; // auxMmapPages_ * pageSize_ +static constexpr char PERF_RECORD_TYPE_AUXTRACE[] = "auxtrace"; +static constexpr char PERF_RECORD_TYPE_SAMPLE[] = "sample"; +static constexpr char PERF_RECORD_TYPE_MMAP[] = "mmap"; +static constexpr char PERF_RECORD_TYPE_MMAP2[] = "mmap2"; +static constexpr char PERF_RECORD_TYPE_LOST[] = "lost"; +static constexpr char PERF_RECORD_TYPE_COMM[] = "comm"; +static constexpr char PERF_RECORD_TYPE_EXIT[] = "exit"; +static constexpr char PERF_RECORD_TYPE_THROTTLE[] = "throttle"; +static constexpr char PERF_RECORD_TYPE_UNTHROTTLE[] = "unthrottle"; +static constexpr char PERF_RECORD_TYPE_FORK[] = "fork"; +static constexpr char PERF_RECORD_TYPE_READ[] = "read"; +static constexpr char PERF_RECORD_TYPE_AUX[] = "aux"; +static constexpr char PERF_RECORD_TYPE_ITRACESTART[] = "itraceStart"; +static constexpr char PERF_RECORD_TYPE_LOSTSAMPLE[] = "lostSamples"; +static constexpr char PERF_RECORD_TYPE_SWITCH[] = "switch"; +static constexpr char PERF_RECORD_TYPE_SWITCHCPUWIDE[] = "switchCpuWide"; +static constexpr char* PERF_RECORD_TYPE_NULL = nullptr; + enum perf_event_hiperf_ext_type { PERF_RECORD_AUXTRACE = 71, PERF_RECORD_HIPERF_CALLSTACK = UINT32_MAX / 2, }; -struct CallFrame { - uint64_t ip_ = 0; // pc - uint64_t sp_ = 0; // sp - int32_t symbolFileIndex_ = -1; // symbolFileIndex_, symbols file index, used to report protobuf file - uint64_t vaddrInFile_ = 0; // funcOffset, vaddr of symbol in file - uint64_t offsetToVaddr_ = 0; // mapOffset, offset of ip to vaddr - int32_t symbolIndex_ = -1; // index, symbols index , should update after sort - std::string_view symbolName_; // funcName - std::string_view filePath_; // mapName, lib path , elf path - - CallFrame(uint64_t ip, uint64_t sp = 0) : ip_(ip), sp_(sp) {} - - // this is for ut test - CallFrame(uint64_t ip, uint64_t vaddrInFile, const char *name, const char *filePath) - : ip_(ip), vaddrInFile_(vaddrInFile), symbolName_(name), filePath_(filePath) - { - } - bool operator==(const CallFrame &b) const - { - return (ip_ == b.ip_) && (sp_ == b.sp_); - } - bool operator!=(const CallFrame &b) const - { - return (ip_ != b.ip_) || (sp_ != b.sp_); - } - std::string ToString() const - { - return StringPrintf("ip: 0x%016llx sp: 0x%016llx", ip_, sp_); - } - std::string ToSymbolString() const - { - std::string output = StringPrintf(" 0x%016llx : ", ip_); - output.append(symbolName_); - if (vaddrInFile_ != 0) { - output += StringPrintf("[0x%016llx:0x%016llx][+0x%llx]", ip_ - offsetToVaddr_, - vaddrInFile_, offsetToVaddr_); - } - - output.append("@"); - output.append(filePath_); - if (symbolIndex_ != -1) { - output.append(":"); - output.append(std::to_string(symbolIndex_)); - } - return output; - } -}; - struct AttrWithId { perf_event_attr attr; std::vector ids; @@ -104,50 +76,39 @@ struct AttrWithId { class PerfEventRecord { public: - PerfEventRecord(const PerfEventRecord &) = delete; - PerfEventRecord &operator=(const PerfEventRecord &) = delete; + struct perf_event_header header_ = {}; - struct perf_event_header header; - const std::string name_ {}; + virtual const char* GetName() const = 0; + virtual void Init(uint8_t* data, const perf_event_attr& attr) = 0; - PerfEventRecord(perf_event_type type, bool inKernel, const std::string &name); - PerfEventRecord(perf_event_hiperf_ext_type type, const std::string &name); - - PerfEventRecord(uint8_t *p, const std::string &name); - - virtual ~PerfEventRecord() {} + virtual ~PerfEventRecord() = default; virtual size_t GetSize() const { - return header.size; + return header_.size; }; size_t GetHeaderSize() const { - return sizeof(header); + return sizeof(header_); }; void GetHeaderBinary(std::vector &buf) const; uint32_t GetType() const { - return header.type; + return header_.type; }; uint16_t GetMisc() const { - return header.misc; + return header_.misc; }; - bool inKernel() + bool InKernel() { - return header.misc & PERF_RECORD_MISC_KERNEL; + return header_.misc & PERF_RECORD_MISC_KERNEL; } - bool inUser() + bool InUser() { - return header.misc & PERF_RECORD_MISC_USER; + return header_.misc & PERF_RECORD_MISC_USER; } - const std::string &GetName() const - { - return name_; - }; - // to support --exclude-hiperf, return sample_id.pid to filter record, virtual pid_t GetPid() const { @@ -157,7 +118,42 @@ public: virtual bool GetBinary(std::vector &buf) const = 0; void Dump(int indent = 0, std::string outputFilename = "", FILE *outputDump = nullptr) const; virtual void DumpData(int indent) const = 0; - virtual void DumpLog(const std::string &prefix) const; + virtual void DumpLog(const std::string& prefix) const; + +protected: + void Init(perf_event_type type, bool inKernel); + void Init(perf_event_hiperf_ext_type type); + void InitHeader(uint8_t* p); +}; + +template +class PerfEventRecordTemplate : public PerfEventRecord { +public: + PerfEventRecordTemplate(const PerfEventRecordTemplate&) = delete; + PerfEventRecordTemplate& operator=(const PerfEventRecordTemplate&) = delete; + + DataType data_ = {}; + const char* GetName() const override final + { + return RECORD_TYPE_NAME; + } + + PerfEventRecordTemplate() = default; + virtual ~PerfEventRecordTemplate() = default; + void Init(uint8_t* p, const perf_event_attr& = {}) override + { + InitHeader(p); + + size_t dataSize = GetSize(); + if (dataSize >= sizeof(header_)) { + size_t copySize = dataSize - sizeof(header_); + if (memcpy_s(reinterpret_cast(&data_), sizeof(data_), p + sizeof(header_), copySize) != 0) { + HLOGE("init perf record memcpy_s failed!"); + } + } else { + HLOGE("init perf record failed!"); + } + }; }; // define convert from linux/perf_event.h @@ -171,12 +167,12 @@ constexpr __u64 SAMPLE_TYPE = PERF_SAMPLE_IP | SAMPLE_ID | PERF_SAMPLE_PERIOD; constexpr __u32 MIN_SAMPLE_STACK_SIZE = 8; constexpr __u32 MAX_SAMPLE_STACK_SIZE = 65528; -class PerfRecordAuxtrace : public PerfEventRecord { +class PerfRecordAuxtrace : public PerfEventRecordTemplate { public: - PerfRecordAuxtraceData data_; u8* rawData_ = nullptr; - explicit PerfRecordAuxtrace(uint8_t *p); + PerfRecordAuxtrace() = default; PerfRecordAuxtrace(u64 size, u64 offset, u64 reference, u32 idx, u32 tid, u32 cpu, u32 pid); + void Init(uint8_t* data, const perf_event_attr& attr) override; bool GetBinary1(std::vector &buf) const; bool GetBinary(std::vector &buf) const override; @@ -186,12 +182,9 @@ public: virtual size_t GetSize() const override; }; -class PerfRecordMmap : public PerfEventRecord { +class PerfRecordMmap : public PerfEventRecordTemplate { public: - PerfRecordMmapData data_; - - explicit PerfRecordMmap(uint8_t *p); - + PerfRecordMmap() = default; PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff, const std::string &filename); @@ -200,11 +193,10 @@ public: void DumpLog(const std::string &prefix) const override; }; -class PerfRecordMmap2 : public PerfEventRecord { +class PerfRecordMmap2 : public PerfEventRecordTemplate { public: - PerfRecordMmap2Data data_; - explicit PerfRecordMmap2(uint8_t *p); + PerfRecordMmap2() = default; PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff, u32 maj, u32 min, u64 ino, u32 prot, u32 flags, const std::string &filename); @@ -217,31 +209,28 @@ public: bool discard_ = false; }; -class PerfRecordLost : public PerfEventRecord { +class PerfRecordLost : public PerfEventRecordTemplate { public: - PerfRecordLostData data_; - explicit PerfRecordLost(uint8_t *p); + PerfRecordLost() = default; bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; // only for UT PerfRecordLost(bool inKernel, u64 id, u64 lost) - : PerfEventRecord(PERF_RECORD_LOST, inKernel, "lost") { + PerfEventRecord::Init(PERF_RECORD_LOST, inKernel); data_.id = id; data_.lost = lost; - header.size = sizeof(header) + sizeof(data_); + header_.size = sizeof(header_) + sizeof(data_); } }; -class PerfRecordComm : public PerfEventRecord { +class PerfRecordComm : public PerfEventRecordTemplate { public: - PerfRecordCommData data_; - - explicit PerfRecordComm(uint8_t *p); + PerfRecordComm() = default; PerfRecordComm(bool inKernel, u32 pid, u32 tid, const std::string &comm); bool GetBinary(std::vector &buf) const override; @@ -249,9 +238,8 @@ public: void DumpLog(const std::string &prefix) const override; }; -class PerfRecordSample : public PerfEventRecord { +class PerfRecordSample : public PerfEventRecordTemplate { public: - PerfRecordSampleData data_ = {}; uint64_t sampleType_ = SAMPLE_TYPE; uint64_t skipKernel_ = 0; uint64_t skipPid_ = 0; @@ -262,11 +250,15 @@ public: static std::vector callFrames_; static std::vector serverPidMap_; + PerfRecordSample() = default; + PerfRecordSample(const PerfRecordSample& sample); + // referenced input(p) in PerfRecordSample, require caller keep input(p) together + void Init(uint8_t* data, const perf_event_attr& attr) override; + StackId stackId_ {0}; bool removeStack_ {false}; - inline static bool dumpRemoveStack_ {false}; - // referenced input(p) in PerfRecordSample, require caller keep input(p) together - PerfRecordSample(uint8_t *p, const perf_event_attr &attr); + static void SetDumpRemoveStack(bool dumpRemoveStack); + static bool IsDumpRemoveStack(); bool GetBinary(std::vector &buf) const override; void DumpData(int indent = 0) const override; void DumpLog(const std::string &prefix) const override; @@ -279,56 +271,50 @@ public: // only for UT PerfRecordSample(bool inKernel, u32 pid, u32 tid, u64 period = 0, u64 time = 0, u64 id = 0) - : PerfEventRecord(PERF_RECORD_SAMPLE, inKernel, "sample") { + PerfEventRecord::Init(PERF_RECORD_SAMPLE, inKernel); Clean(); data_.pid = pid; data_.tid = tid; data_.period = period; data_.time = time; data_.id = 0; - header.size = sizeof(header) + sizeof(data_); - }; + header_.size = sizeof(header_) + sizeof(data_); + } pid_t GetUstackServerPid(); pid_t GetServerPidof(unsigned int ipNr); +private: + static bool dumpRemoveStack_; }; -class PerfRecordExit : public PerfEventRecord { +class PerfRecordExit : public PerfEventRecordTemplate { public: - PerfRecordExitData data_; - - explicit PerfRecordExit(uint8_t *p); + PerfRecordExit() = default; bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; }; -class PerfRecordThrottle : public PerfEventRecord { +class PerfRecordThrottle : public PerfEventRecordTemplate { public: - PerfRecordThrottleData data_; - - PerfRecordThrottle(uint8_t *p); + PerfRecordThrottle() = default; bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; }; -class PerfRecordUnthrottle : public PerfEventRecord { +class PerfRecordUnthrottle : public PerfEventRecordTemplate { public: - PerfRecordThrottleData data_; - - explicit PerfRecordUnthrottle(uint8_t *p); + PerfRecordUnthrottle() = default; bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; }; -class PerfRecordFork : public PerfEventRecord { +class PerfRecordFork : public PerfEventRecordTemplate { public: - PerfRecordForkData data_; - - explicit PerfRecordFork(uint8_t *p); + PerfRecordFork() = default; bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; @@ -337,11 +323,10 @@ public: /* This record indicates a read event. */ -class PerfRecordRead : public PerfEventRecord { +class PerfRecordRead : public PerfEventRecordTemplate { public: - PerfRecordReadData data_; + PerfRecordRead() = default; - explicit PerfRecordRead(uint8_t *p); bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; }; @@ -365,12 +350,11 @@ public: if set, then the data returned has overwritten previous data. */ -class PerfRecordAux : public PerfEventRecord { +class PerfRecordAux : public PerfEventRecordTemplate { public: uint64_t sampleType_ = SAMPLE_ID; - PerfRecordAuxData data_; + PerfRecordAux() = default; - explicit PerfRecordAux(uint8_t *p); bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; }; @@ -386,11 +370,10 @@ public: tid thread ID of the thread starting an instruction trace. */ -class PerfRecordItraceStart : public PerfEventRecord { +class PerfRecordItraceStart : public PerfEventRecordTemplate { public: - PerfRecordItraceStartData data_; + PerfRecordItraceStart() = default; - explicit PerfRecordItraceStart(uint8_t *p); bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; }; @@ -400,11 +383,10 @@ public: record indicates some number of samples that may have been lost. */ -class PerfRecordLostSamples : public PerfEventRecord { +class PerfRecordLostSamples : public PerfEventRecordTemplate { public: - PerfRecordLostSamplesData data_; + PerfRecordLostSamples() = default; - explicit PerfRecordLostSamples(uint8_t *p); bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; }; @@ -415,12 +397,12 @@ public: indicates whether it was a context switch into or away from the current process. */ -class PerfRecordSwitch : public PerfEventRecord { +class PerfRecordSwitch : public PerfEventRecordTemplate { public: - PerfRecordSwitchData data_; - explicit PerfRecordSwitch(uint8_t *p); + PerfRecordSwitch() = default; + bool GetBinary(std::vector &buf) const override; - void DumpData([[maybe_unused]] int indent) const override {}; + void DumpData(int) const override {}; }; /* @@ -441,20 +423,30 @@ public: The thread ID of the previous (if switching in) or next (if switching out) thread on the CPU. */ -class PerfRecordSwitchCpuWide : public PerfEventRecord { +class PerfRecordSwitchCpuWide + : public PerfEventRecordTemplate { public: - PerfRecordSwitchCpuWideData data_; - explicit PerfRecordSwitchCpuWide(uint8_t *p); + PerfRecordSwitchCpuWide() = default; + bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; }; -std::unique_ptr GetPerfEventRecord(const int type, uint8_t *p, - const perf_event_attr &attr); -std::unique_ptr GetPerfSampleFromCache(const int type, uint8_t *p, - const perf_event_attr &attr); -std::unique_ptr GetPerfSampleFromCacheMain(const int type, uint8_t *p, - const perf_event_attr &attr); +class PerfRecordNull : public PerfEventRecordTemplate { +public: + PerfRecordNull() = default; + + bool GetBinary(std::vector&) const override { return false; }; + void DumpData(int indent) const override {}; +}; + +class PerfEventRecordFactory { +public: + static PerfEventRecord& GetPerfEventRecord(PerfRecordType type, uint8_t* data, + const perf_event_attr& attr); +private: + static thread_local std::unordered_map recordMap_; +}; template void PushToBinary(bool condition, uint8_t *&p, const T &v); diff --git a/include/perf_events.h b/include/perf_events.h index f2daaa4..b5eaa3d 100644 --- a/include/perf_events.h +++ b/include/perf_events.h @@ -443,7 +443,7 @@ public: }; using StatCallBack = std::function> &)>; - using RecordCallBack = std::function)>; + using RecordCallBack = std::function; void SetStatCallBack(StatCallBack reportCallBack); void SetRecordCallBack(RecordCallBack recordCallBack); diff --git a/include/perf_file_reader.h b/include/perf_file_reader.h index cec2a29..6f9b11b 100644 --- a/include/perf_file_reader.h +++ b/include/perf_file_reader.h @@ -26,7 +26,7 @@ namespace OHOS { namespace Developtools { namespace HiPerf { -using ProcessRecordCB = const std::function record)>; +using ProcessRecordCB = const std::function; // read record from data file, like perf.data. // format of file follow // tools/perf/Documentation/perf.data-file-format.txt diff --git a/include/perf_file_writer.h b/include/perf_file_writer.h index a392788..f027c94 100644 --- a/include/perf_file_writer.h +++ b/include/perf_file_writer.h @@ -61,10 +61,11 @@ public: uint GetRecordCount() const; std::chrono::microseconds writeTimes_ = std::chrono::microseconds::zero(); - using ProcessRecordCB = const std::function record)>; + using ProcessRecordCB = const std::function; bool ReadDataSection(ProcessRecordCB &callback); bool ReadRecords(ProcessRecordCB &callback); bool Read(void *buf, size_t len); + void SetWriteRecordStat(bool isWrite); private: std::string fileBuffer_; diff --git a/include/spe_decoder.h b/include/spe_decoder.h index 30e81cc..653bdba 100644 --- a/include/spe_decoder.h +++ b/include/spe_decoder.h @@ -284,7 +284,6 @@ struct SpeDecoder { struct SpePkt packet; }; -struct SpeDecoder *SpeDecoderNew(struct SpeParams *params); struct SpeDecoder *SpeDecoderDataNew(const unsigned char *speBuf, size_t speLen); void SpeDecoderFree(struct SpeDecoder *decoder); diff --git a/include/subcommand.h b/include/subcommand.h index 1f2b194..9f2f01f 100644 --- a/include/subcommand.h +++ b/include/subcommand.h @@ -80,7 +80,7 @@ public: }; // called from main - static bool RegisterSubCommand(std::string, std::unique_ptr); + static bool RegisterSubCommand(const std::string&, std::unique_ptr); // get some cmd static const std::map> &GetSubCommands(); diff --git a/include/subcommand_dump.h b/include/subcommand_dump.h index 176bb14..2e7ddcc 100644 --- a/include/subcommand_dump.h +++ b/include/subcommand_dump.h @@ -107,10 +107,10 @@ private: void DumpPrintFileHeader(int indent = 0); void DumpAttrPortion(int indent = 0); void DumpDataPortion(int indent = 0); - void DumpCallChain(int indent, std::unique_ptr &sample); + void DumpCallChain(int indent, const PerfRecordSample& sample); void DumpFeaturePortion(int indent = 0); void DumpUniqueStackTableNode(int indent, const PerfFileSectionUniStackTable &uniStackTable); - void ExprotUserData(std::unique_ptr &record); + void ExprotUserData(PerfEventRecord& record); void ExprotUserStack(const PerfRecordSample &recordSample); void PrintHeaderInfo(const int &indent); void PrintSymbolFile(const int &indent, const SymbolFileStruct &symbolFileStruct); diff --git a/include/subcommand_record.h b/include/subcommand_record.h index 877369a..81f1b18 100644 --- a/include/subcommand_record.h +++ b/include/subcommand_record.h @@ -303,8 +303,8 @@ private: bool isSpe_ = false; // callback to process record - bool ProcessRecord(std::unique_ptr); - bool SaveRecord(std::unique_ptr, bool ptrReleaseFlag = false); + bool ProcessRecord(PerfEventRecord& record); + bool SaveRecord(const PerfEventRecord& record, bool ptrReleaseFlag = false); // file format like as 0,1-3,4-6,7,8 uint32_t GetCountFromFile(const std::string &fileName); @@ -327,7 +327,7 @@ private: void ReportTime(); #endif - bool CollectionSymbol(std::unique_ptr record); + bool CollectionSymbol(PerfEventRecord& record); void CollectSymbol(PerfRecordSample *sample); bool SetPerfLimit(const std::string& file, int value, std::function const& cmd, const std::string& param); diff --git a/include/subcommand_report.h b/include/subcommand_report.h index e7cfbd1..91c7b94 100644 --- a/include/subcommand_report.h +++ b/include/subcommand_report.h @@ -107,7 +107,7 @@ public: bool ParseOption(std::vector &args) override; void DumpOptions(void) const override; static bool RegisterSubCommandReport(void); - bool RecordCallBack(std::unique_ptr record); + bool RecordCallBack(PerfEventRecord& record); ~SubCommandReport(); diff --git a/include/utilities.h b/include/utilities.h index 0783de1..bad5069 100644 --- a/include/utilities.h +++ b/include/utilities.h @@ -310,6 +310,7 @@ bool IsBeta(); bool IsAllowProfilingUid(); bool IsHiviewCall(); bool PowerOfTwo(uint64_t n); +bool IsNumeric(const std::string& str); const std::string HMKERNEL = "HongMeng"; @@ -344,29 +345,6 @@ bool IsArkJsFile(const std::string& filepath); std::string GetProcessName(int pid); bool NeedAdaptSandboxPath(char *filename, int pid, u16 &headerSize); bool NeedAdaptHMBundlePath(std::string& filename, const std::string& threadname); - -template -class ScopeGuard { -public: - explicit ScopeGuard(Func&& fn) - : fn_(fn) {} - ~ScopeGuard() - { - fn_(); - } -private: - Func fn_; -}; - -struct ScopeGuardOnExit {}; -template -static inline ScopeGuard operator+(ScopeGuardOnExit, Func&& fn) -{ - return ScopeGuard(std::forward(fn)); -} - -#define ON_SCOPE_EXIT \ - auto __onGuardExit__ = ScopeGuardOnExit{} + [&] } // namespace HiPerf } // namespace Developtools } // namespace OHOS diff --git a/include/virtual_runtime.h b/include/virtual_runtime.h index 39fe3a3..0224989 100644 --- a/include/virtual_runtime.h +++ b/include/virtual_runtime.h @@ -51,7 +51,7 @@ public: // from the record , it will call back to write some Simulated Record // case 1. some mmap will be create when it read mmaps for each new process (from record sample) - using RecordCallBack = std::function)>; + using RecordCallBack = std::function; using CollectSymbolCallBack = std::function; void SetRecordMode(RecordCallBack recordCallBack); diff --git a/interfaces/kits/js/napi/hiperf_client_napi.cpp b/interfaces/kits/js/napi/hiperf_client_napi.cpp index c348be9..88c7fba 100644 --- a/interfaces/kits/js/napi/hiperf_client_napi.cpp +++ b/interfaces/kits/js/napi/hiperf_client_napi.cpp @@ -14,6 +14,7 @@ */ #include "hiperf_client_napi.h" #include +#include #include #include "hiperf_hilog.h" #include "hiperf_client.h" @@ -30,46 +31,44 @@ static std::unique_ptr g_hiperfClient = static std::unique_ptr g_hiperfRecordOption = std::make_unique(); -static std::vector StringSplit(std::string source, const std::string &split = ",") +static std::vector StringSplit(const std::string& text, char delimiter = ',') { - size_t pos = 0; - std::vector result; - - // find - while ((pos = source.find(split)) != std::string::npos) { - // split - std::string token = source.substr(0, pos); + std::vector tokens; + std::string token; + std::istringstream tokenStream(text); + while (std::getline(tokenStream, token, delimiter)) { if (!token.empty()) { - result.push_back(token); + tokens.push_back(token); } - source.erase(0, pos + split.length()); } - // add last token - if (!source.empty()) { - result.push_back(source); - } - return result; + return tokens; } -static std::vector StringSplitToInt(std::string source, const std::string &split = ",") +static bool IsNumeric(const std::string& str) { - size_t pos = 0; - std::vector result; + std::istringstream iss(str); + int number; + char trailingCharacter; + if (!(iss >> number)) { + return false; + } + if (iss >> trailingCharacter) { + return false; + } + return true; +} - // find - while ((pos = source.find(split)) != std::string::npos) { - // split - std::string token = source.substr(0, pos); - if (!token.empty()) { - result.push_back(std::stoi(token)); +static std::vector StringSplitToInt(const std::string& text, char delimiter = ',') +{ + std::vector tokens; + std::string token; + std::istringstream tokenStream(text); + while (std::getline(tokenStream, token, delimiter)) { + if (IsNumeric(token)) { + tokens.push_back(std::stoi(token)); } - source.erase(0, pos + split.length()); } - // add last token - if (!source.empty()) { - result.push_back(std::stoi(source)); - } - return result; + return tokens; } static std::string GetJsStringFromOption(const napi_env &env, const napi_callback_info &info) @@ -85,7 +84,10 @@ static std::string GetJsStringFromOption(const napi_env &env, const napi_callbac char value[PATH_MAX] = {0}; size_t valueLen = 0; - napi_get_value_string_utf8(env, args[0], value, sizeof(value), &valueLen); + if (napi_get_value_string_utf8(env, args[0], value, sizeof(value), &valueLen) != napi_ok) { + HIPERF_HILOGE(MODULE_JS_NAPI, "napi_get_value_string_utf8 failed."); + return ""; + } HIPERF_HILOGD(MODULE_JS_NAPI, "%{public}s", value); return std::string(value); } diff --git a/script/report.html b/script/report.html index c171fec..846e03e 100644 --- a/script/report.html +++ b/script/report.html @@ -4021,7 +4021,6 @@ input{ if (this.data) { if (this.reverse) { this.drawCReverse( - 0, this.c, 1, { @@ -4120,18 +4119,14 @@ input{ return heatColor; } - drawCReverse = (parentEvents, c, dept, rect) => { + drawCReverse = (c, dept, rect) => { let ctx = this.context; let offset = 0; - if (parentEvents === 0) { - parentEvents = c.reduce((acc, cur) => acc + cur.subEvents, 0); - } for (let i = 0; i < c.length; i++) { let funName = this.getFunctionName(c[i].symbol); let funcId = c[i].symbol; - let percent = c[i].subEvents * 100 / parentEvents; + let percent = c[i].subEvents * 100 / (c.reduce((acc, cur) => acc + cur.subEvents, 0)); let percent2 = c[i].subEvents * 100 / this.sumCount; - if (percent2 < 0.1) continue // 过滤掉 百分比为0.1一下的节点 let heatColor = this.getColor(percent2, funName); let w = rect.w * (percent / 100.0); if (w < 1) { @@ -4164,13 +4159,8 @@ input{ ctx.strokeStyle = `#000000`; ctx.strokeRect(_x, rect.y + 1, w - 1, rect.h); let statisticNum = this.getStatistics(c[i]); - let count = this.getCount(c[i]); this.funcNameSpan.textContent = funName; - if (this.type === 1 || this.type === 2 || this.type === 3) { - this.panel.title = funName + ': [' + count + ' ' + statisticNum + ']'; - } else { - this.panel.title = funName + ': [' + statisticNum + ']'; - } + this.panel.title = funName + ': [' + statisticNum + ']'; this.percentSpan.textContent = statisticNum; } else { if (this.mouseState === 'mouseUp') { @@ -4187,7 +4177,7 @@ input{ // 递归绘制子节点 if (c[i].callStack && c[i].callStack.length > 0) { _rect.y = _rect.y + _rect.h; - this.drawCReverse(c[i].subEvents, [i].callStack, dept + 1, _rect); + this.drawCReverse(c[i].callStack, dept + 1, _rect); } } } @@ -4202,7 +4192,6 @@ input{ let funcId = c[i].symbol; let percent = c[i].subEvents * 100 / parentEvents;// sumCount; let percent2 = c[i].subEvents * 100 / this.sumCount; - if (percent2 < 0.1) continue // 过滤掉 百分比为0.1一下的节点 let heatColor = this.getColor(percent2, funName); let w = rect.w * (percent / 100.0); if (w < 1) { @@ -4420,7 +4409,7 @@ input{ if (json.osVersion) { rows.push({key: 'OS Version', value: json.osVersion,time:''}); } - rows.push({key: 'Script Version', value: '1.0.0.240604',time:''}); + rows.push({key: 'Script Version', value: '1.0.0.241031',time:''}); if (json.deviceCommandLine) { rows.push({key:'Record cmdline',value: json.deviceCommandLine,time:''}); } diff --git a/src/callstack.cpp b/src/callstack.cpp index 452c682..c9cef55 100644 --- a/src/callstack.cpp +++ b/src/callstack.cpp @@ -79,7 +79,7 @@ const std::map UNW_ERROR_MAP = { }; const std::string CallStack::GetUnwErrorName(int error) { - if (UNW_ERROR_MAP.count(static_cast(-error)) > 0) { + if (UNW_ERROR_MAP.find(static_cast(-error)) != UNW_ERROR_MAP.end()) { return UNW_ERROR_MAP.at(static_cast(-error)); } else { return "UNKNOW_UNW_ERROR"; @@ -292,7 +292,7 @@ int CallStack::AccessMem([[maybe_unused]] unw_addr_space_t as, unw_word_t addr, return -UNW_EUNSPEC; } - if (addr < unwindInfoPtr->callStack.stackPoint_ or + if (addr < unwindInfoPtr->callStack.stackPoint_ || addr + sizeof(unw_word_t) >= unwindInfoPtr->callStack.stackEnd_) { if (ReadVirtualThreadMemory(*unwindInfoPtr, addr, valuePoint)) { HLOGM("access_mem addr get val 0x%" UNW_WORD_PFLAG ", from mmap", *valuePoint); @@ -540,8 +540,8 @@ size_t CallStack::DoExpandCallStack(std::vector &newCallFrames, { int maxCycle = 0; - if (expandLimit == 0 or newCallFrames.size() < expandLimit or - cachedCallFrames.size() < expandLimit or + if (expandLimit == 0 || newCallFrames.size() < expandLimit || + cachedCallFrames.size() < expandLimit || cachedCallFrames.size() >= MAX_CALL_FRAME_UNWIND_SIZE) { HLOGM("expandLimit %zu not match new %zu cache %zu", expandLimit, newCallFrames.size(), cachedCallFrames.size()); @@ -777,7 +777,7 @@ int CallStack::AccessMem2(uintptr_t addr, uintptr_t *val, void *arg) "unwindInfoPtr is null or address overflow at 0x%" UNW_WORD_PFLAG " increase 0x%zu", addr, sizeof(uintptr_t)); - if (addr < unwindInfoPtr->callStack.stackPoint_ or + if (addr < unwindInfoPtr->callStack.stackPoint_ || addr + sizeof(uintptr_t) >= unwindInfoPtr->callStack.stackEnd_) { if (ReadVirtualThreadMemory(*unwindInfoPtr, addr, val)) { HLOGM("access_mem addr get val 0x%" UNW_WORD_PFLAG ", from mmap", *val); diff --git a/src/debug_logger.cpp b/src/debug_logger.cpp index 04b73b4..4932274 100644 --- a/src/debug_logger.cpp +++ b/src/debug_logger.cpp @@ -15,19 +15,15 @@ #include "debug_logger.h" -#include - #include "option.h" #if defined(is_ohos) && is_ohos #include "hiperf_hilog.h" #endif -using namespace std::literals::chrono_literals; -using namespace std::chrono; namespace OHOS { namespace Developtools { namespace HiPerf { -DebugLogger::DebugLogger() : timeStamp_(steady_clock::now()), logPath_(DEFAULT_LOG_PATH) +DebugLogger::DebugLogger() : timeStamp_(std::chrono::steady_clock::now()), logPath_(DEFAULT_LOG_PATH) { OpenLog(); } @@ -82,12 +78,12 @@ int DebugLogger::Log(DebugLevel level, const std::string &logTag, const char *fm { constexpr const int DEFAULT_STRING_BUF_SIZE = 4096; #ifdef HIPERF_DEBUG_TIME - const auto startSprintf = steady_clock::now(); + const auto startSprintf = std::chrono::steady_clock::now(); #endif - const auto startTime = steady_clock::now(); - if (!ShouldLog(level, logTag) or logDisabled_ or fmt == nullptr) { + const auto startTime = std::chrono::steady_clock::now(); + if (!ShouldLog(level, logTag) || logDisabled_ || fmt == nullptr) { #ifdef HIPERF_DEBUG_TIME - logTimes_ += duration_cast(steady_clock::now() - startSprintf); + logTimes_ += duration_cast(std::chrono::steady_clock::now() - startSprintf); #endif return 0; } @@ -99,9 +95,9 @@ int DebugLogger::Log(DebugLevel level, const std::string &logTag, const char *fm ret = vsnprintf_s(buffer.data(), buffer.size(), buffer.size() >= 1 ? buffer.size() - 1 : 0, fmt, va); va_end(va); #ifdef HIPERF_DEBUG_TIME - logSprintfTimes_ += duration_cast(steady_clock::now() - startSprintf); + logSprintfTimes_ += duration_cast(std::chrono::steady_clock::now() - startSprintf); #endif - if ((mixLogOutput_ and level < LEVEL_FATAL) or level == LEVEL_FATAL) { + if ((mixLogOutput_ && level < LEVEL_FATAL) || level == LEVEL_FATAL) { ret = fprintf(stdout, "%s", buffer.data()); // to the stdout } @@ -113,17 +109,17 @@ int DebugLogger::Log(DebugLevel level, const std::string &logTag, const char *fm } else if (file_ != nullptr) { std::lock_guard lock(logMutex_); #ifdef HIPERF_DEBUG_TIME - const auto startWriteTime = steady_clock::now(); + const auto startWriteTime = std::chrono::steady_clock::now(); #endif - milliseconds timeStamp = duration_cast(startTime - timeStamp_); + auto timeStamp = startTime - timeStamp_; 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); + logWriteTimes_ += duration_cast(std::chrono::steady_clock::now() - startWriteTime); #endif } #ifdef HIPERF_DEBUG_TIME - logTimes_ += duration_cast(steady_clock::now() - startTime); + logTimes_ += duration_cast(std::chrono::steady_clock::now() - startTime); logCount_++; #endif if (level == LEVEL_FATAL && exitOnFatal_) { @@ -170,7 +166,7 @@ bool DebugLogger::SetLogPath(const std::string &newLogPath) { // make sure not write happend when rename std::lock_guard lock(logMutex_); - if (newLogPath.empty() and newLogPath != logPath_) { + if (newLogPath.empty() && newLogPath != logPath_) { return false; } if (file_ != nullptr) { diff --git a/src/hiperf_libreport.cpp b/src/hiperf_libreport.cpp index 2fb19a8..688acdc 100644 --- a/src/hiperf_libreport.cpp +++ b/src/hiperf_libreport.cpp @@ -47,7 +47,7 @@ int Report(const char *perfFile, const char *reportFile, const char *reportOptio { std::unique_ptr report = std::make_unique(); HLOGD("report the file %s to %s\n", perfFile, reportFile); - if (perfFile != nullptr and reportFile != nullptr) { + if (perfFile != nullptr && reportFile != nullptr) { std::vector args; args.emplace_back("-i"); args.emplace_back(perfFile); @@ -77,7 +77,7 @@ int ReportUnwindJson(const char *perfFile, const char *reportFile, const char *s { std::unique_ptr report = std::make_unique(); HLOGD("report the file %s to json file %s symbols from %s\n", perfFile, reportFile, symbolsDir); - if (perfFile != nullptr and reportFile != nullptr) { + if (perfFile != nullptr && reportFile != nullptr) { std::vector args; args.emplace_back("-i"); args.emplace_back(perfFile); @@ -119,11 +119,13 @@ const char *ReportGetSymbolFiles(const char *perfFile) static std::string result; // static for hold the c_str buffer result.clear(); if (perfFile == nullptr) { + HLOGW("perfFile is nullptr."); return result.c_str(); } auto reader = GetReader(perfFile); if (reader == nullptr) { + HLOGW("reader is nullptr."); return result.c_str(); } // found symbols in file diff --git a/src/main.cpp b/src/main.cpp index b7c827f..ed218ac 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -47,7 +47,7 @@ int main(const int argc, const char *argv[]) return -1; } - if (argc < 0 || argc > 128) { // 128 : max input argument counts + if (argc > 128) { // 128 : max input argument counts printf("The number of input arguments exceeds the upper limit.\n"); return -1; } @@ -55,9 +55,6 @@ int main(const int argc, const char *argv[]) cin.tie(nullptr); #if defined(is_ohos) && is_ohos - if (IsRoot() && setgid(2000) != 0) { // 2000 is shell group - printf("setgid failed errno: %d.\n", errno); - } WriteStringToFile("/proc/self/oom_score_adj", "0"); if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { HIPERF_HILOGI(MODULE_DEFAULT, "ignore SIGPIPE failed."); diff --git a/src/option.cpp b/src/option.cpp index 67736b0..980fdd6 100644 --- a/src/option.cpp +++ b/src/option.cpp @@ -63,7 +63,7 @@ std::vector::iterator FindOption(argsVector &args, const std::strin break; } } - auto it = find(args.begin(), args.end(), optionName); + auto it = std::find(args.begin(), args.end(), optionName); if (it != args.end()) { if (tmpit != args.end() && it > tmpit) { it = args.end(); diff --git a/src/perf_event_record.cpp b/src/perf_event_record.cpp index 6322c3f..51d9218 100644 --- a/src/perf_event_record.cpp +++ b/src/perf_event_record.cpp @@ -20,100 +20,54 @@ #include "utilities.h" -using namespace OHOS::HiviewDFX; -using namespace std; namespace OHOS { namespace Developtools { namespace HiPerf { -void *g_sampleMemCache = nullptr; // for read record from buf thread -void *g_sampleMemCacheMain = nullptr; // for main thread:collecttionsymbol -constexpr size_t SAMPLE_CACHE_SIZE = 4 * 1024; +bool PerfRecordSample::dumpRemoveStack_ = false; +thread_local std::unordered_map PerfEventRecordFactory::recordMap_ = {}; -std::unique_ptr GetPerfEventRecord(const int type, uint8_t *p, - const perf_event_attr &attr) +static PerfEventRecord* CreatePerfEventRecord(PerfRecordType type) { - HLOG_ASSERT(p); - uint8_t *data = p; - - // check kernel switch (type) { case PERF_RECORD_SAMPLE: - return std::make_unique(data, attr); + return new PerfRecordSample(); case PERF_RECORD_MMAP: - return std::make_unique(data); + return new PerfRecordMmap(); case PERF_RECORD_MMAP2: - return std::make_unique(data); + return new PerfRecordMmap2(); case PERF_RECORD_LOST: - return std::make_unique(data); + return new PerfRecordLost(); case PERF_RECORD_COMM: - return std::make_unique(data); + return new PerfRecordComm(); case PERF_RECORD_EXIT: - return std::make_unique(data); + return new PerfRecordExit(); case PERF_RECORD_THROTTLE: - return std::make_unique(data); + return new PerfRecordThrottle(); case PERF_RECORD_UNTHROTTLE: - return std::make_unique(data); + return new PerfRecordUnthrottle(); case PERF_RECORD_FORK: - return std::make_unique(data); + return new PerfRecordFork(); case PERF_RECORD_READ: - return std::make_unique(data); + return new PerfRecordRead(); case PERF_RECORD_AUX: - return std::make_unique(data); + return new PerfRecordAux(); case PERF_RECORD_AUXTRACE: - return std::make_unique(data); + return new PerfRecordAuxtrace(); case PERF_RECORD_ITRACE_START: - return std::make_unique(data); + return new PerfRecordItraceStart(); case PERF_RECORD_LOST_SAMPLES: - return std::make_unique(data); + return new PerfRecordLostSamples(); case PERF_RECORD_SWITCH: - return std::make_unique(data); + return new PerfRecordSwitch(); case PERF_RECORD_SWITCH_CPU_WIDE: - return std::make_unique(data); + return new PerfRecordSwitchCpuWide(); default: HLOGE("unknown record type %d\n", type); - return nullptr; + return new PerfRecordNull(); } } -std::unique_ptr GetPerfSampleFromCache(const int type, uint8_t *p, - const perf_event_attr &attr) -{ - HLOG_ASSERT(p); - uint8_t *data = p; - - if (type == PERF_RECORD_SAMPLE) { - if (g_sampleMemCache != nullptr) { - memset_s(g_sampleMemCache, SAMPLE_CACHE_SIZE, 0, SAMPLE_CACHE_SIZE); - return std::unique_ptr(new (g_sampleMemCache) PerfRecordSample(data, attr)); - } else { - g_sampleMemCache = std::malloc(SAMPLE_CACHE_SIZE); - memset_s(g_sampleMemCache, SAMPLE_CACHE_SIZE, 0, SAMPLE_CACHE_SIZE); - return std::unique_ptr(new (g_sampleMemCache) PerfRecordSample(data, attr)); - } - } - return GetPerfEventRecord(type, p, attr); -} - -std::unique_ptr GetPerfSampleFromCacheMain(const int type, uint8_t *p, - const perf_event_attr &attr) -{ - HLOG_ASSERT(p); - uint8_t *data = p; - - if (type == PERF_RECORD_SAMPLE) { - if (g_sampleMemCacheMain != nullptr) { - memset_s(g_sampleMemCacheMain, SAMPLE_CACHE_SIZE, 0, SAMPLE_CACHE_SIZE); - return std::unique_ptr(new (g_sampleMemCacheMain) PerfRecordSample(data, attr)); - } else { - g_sampleMemCacheMain = std::malloc(SAMPLE_CACHE_SIZE); - memset_s(g_sampleMemCacheMain, SAMPLE_CACHE_SIZE, 0, SAMPLE_CACHE_SIZE); - return std::unique_ptr(new (g_sampleMemCacheMain) PerfRecordSample(data, attr)); - } - } - return GetPerfEventRecord(type, p, attr); -} - template inline void PushToBinary(bool condition, uint8_t *&p, const T &v) { @@ -155,31 +109,29 @@ inline void PopFromBinary2(bool condition, uint8_t *&p, T1 &v1, T2 &v2) } // PerfEventRecord -PerfEventRecord::PerfEventRecord(perf_event_type type, bool inKernel, const std::string &name) - : name_(name) +void PerfEventRecord::Init(perf_event_type type, bool inKernel) { - header.type = type; - header.misc = inKernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER; - header.size = sizeof(header); + header_.type = type; + header_.misc = inKernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER; + header_.size = sizeof(header_); +}; + +void PerfEventRecord::Init(perf_event_hiperf_ext_type type) +{ + header_.type = type; + header_.misc = PERF_RECORD_MISC_USER; + header_.size = sizeof(header_); } -PerfEventRecord::PerfEventRecord(perf_event_hiperf_ext_type type, const std::string &name) - : name_(name) -{ - header.type = type; - header.misc = PERF_RECORD_MISC_USER; - header.size = sizeof(header); -} - -PerfEventRecord::PerfEventRecord(uint8_t *p, const std::string &name) : name_(name) +void PerfEventRecord::InitHeader(uint8_t* p) { if (p == nullptr) { - header.type = PERF_RECORD_MMAP; - header.misc = PERF_RECORD_MISC_USER; - header.size = 0; + header_.type = PERF_RECORD_MMAP; + header_.misc = PERF_RECORD_MISC_USER; + header_.size = 0; return; } - header = *(reinterpret_cast(p)); + header_ = *(reinterpret_cast(p)); } void PerfEventRecord::GetHeaderBinary(std::vector &buf) const @@ -188,7 +140,7 @@ void PerfEventRecord::GetHeaderBinary(std::vector &buf) const buf.resize(GetHeaderSize()); } uint8_t *p = buf.data(); - *(reinterpret_cast(p)) = header; + *(reinterpret_cast(p)) = header_; } void PerfEventRecord::Dump(int indent, std::string outputFilename, FILE *outputDump) const @@ -204,14 +156,14 @@ void PerfEventRecord::Dump(int indent, std::string outputFilename, FILE *outputD } } PRINT_INDENT(indent, "\n"); - PRINT_INDENT(indent, "record %s: type %u, misc %u, size %zu\n", GetName().c_str(), GetType(), + PRINT_INDENT(indent, "record %s: type %u, misc %u, size %zu\n", GetName(), GetType(), GetMisc(), GetSize()); DumpData(indent + 1); } void PerfEventRecord::DumpLog(const std::string &prefix) const { - HLOGV("%s: record %s: type %u, misc %u, size %zu\n", prefix.c_str(), GetName().c_str(), + HLOGV("%s: record %s: type %u, misc %u, size %zu\n", prefix.c_str(), GetName(), GetType(), GetMisc(), GetSize()); } @@ -219,22 +171,15 @@ std::vector PerfRecordSample::ips_ = {}; std::vector PerfRecordSample::callFrames_ = {}; std::vector PerfRecordSample::serverPidMap_ = {}; -PerfRecordAuxtrace::PerfRecordAuxtrace(uint8_t *p) : PerfEventRecord(p, "auxtrace") +void PerfRecordAuxtrace::Init(uint8_t* data, const perf_event_attr& attr) { - if (header.size >= sizeof(header)) { - size_t copySize = header.size - sizeof(header); - if (memcpy_s(reinterpret_cast(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) { - HLOGE("memcpy_s retren failed !!!"); - } - } else { - HLOGE("PerfRecordAuxtrace retren failed !!!"); - } - rawData_ = p + header.size; + PerfEventRecordTemplate::Init(data); + rawData_ = data + header_.size; } PerfRecordAuxtrace::PerfRecordAuxtrace(u64 size, u64 offset, u64 reference, u32 idx, u32 tid, u32 cpu, u32 pid) - : PerfEventRecord(PERF_RECORD_AUXTRACE, "auxtrace") { + PerfEventRecord::Init(PERF_RECORD_AUXTRACE); data_.size = size; data_.offset = offset; data_.reference = reference; @@ -243,19 +188,19 @@ PerfRecordAuxtrace::PerfRecordAuxtrace(u64 size, u64 offset, u64 reference, u32 data_.cpu = cpu; data_.reserved__ = pid; - header.size = sizeof(header) + sizeof(data_); + header_.size = sizeof(header_) + sizeof(data_); } bool PerfRecordAuxtrace::GetBinary1(std::vector &buf) const { - if (buf.size() < header.size) { - buf.resize(header.size); + if (buf.size() < header_.size) { + buf.resize(header_.size); } GetHeaderBinary(buf); uint8_t *p = buf.data() + GetHeaderSize(); - size_t copySize = header.size - GetHeaderSize(); + size_t copySize = header_.size - GetHeaderSize(); if (memcpy_s(p, sizeof(data_), reinterpret_cast(&data_), copySize) != 0) { HLOGE("memcpy_s return failed"); return false; @@ -272,12 +217,12 @@ bool PerfRecordAuxtrace::GetBinary(std::vector &buf) const GetHeaderBinary(buf); uint8_t *p = buf.data() + GetHeaderSize(); - size_t copySize = header.size - GetHeaderSize(); + size_t copySize = header_.size - GetHeaderSize(); if (memcpy_s(p, sizeof(data_), reinterpret_cast(&data_), copySize) != 0) { HLOGE("memcpy_s return failed"); return false; } - p += header.size - GetHeaderSize(); + p += header_.size - GetHeaderSize(); if (memcpy_s(p, data_.size, static_cast(rawData_), data_.size) != 0) { HLOGE("memcpy_s return failed"); return false; @@ -304,13 +249,13 @@ void PerfRecordAuxtrace::DumpLog(const std::string &prefix) const size_t PerfRecordAuxtrace::GetSize() const { - return header.size + data_.size; + return header_.size + data_.size; } void PerfRecordSample::DumpLog(const std::string &prefix) const { HLOGV("%s: SAMPLE: id= %llu size %d pid %u tid %u ips %llu regs %llu, stacks %llu time %llu", - prefix.c_str(), data_.sample_id, header.size, data_.pid, data_.tid, data_.nr, + prefix.c_str(), data_.sample_id, header_.size, data_.pid, data_.tid, data_.nr, data_.reg_nr, data_.dyn_size, data_.time); } @@ -339,7 +284,7 @@ void PerfRecordSample::ReplaceWithCallStack(size_t originalSize) const size_t beginIpsSize = ips_.size(); bool ret = std::all_of(callFrames_.begin(), callFrames_.end(), [&](const DfxFrame &frame) { ips_.emplace_back(frame.pc); - if (originalSize != 0 and (originalSize != callFrames_.size()) and + if (originalSize != 0 && (originalSize != callFrames_.size()) && ips_.size() == (originalSize + beginIpsSize)) { // just for debug // so we can see which frame begin is expand call frames @@ -354,15 +299,15 @@ void PerfRecordSample::ReplaceWithCallStack(size_t originalSize) } if (sampleType_ & PERF_SAMPLE_REGS_USER) { - header.size -= data_.reg_nr * sizeof(u64); + header_.size -= data_.reg_nr * sizeof(u64); data_.reg_nr = 0; data_.user_abi = 0; } if (sampleType_ & PERF_SAMPLE_STACK_USER) { // 1. remove the user stack - header.size -= data_.stack_size; - header.size -= sizeof(data_.dyn_size); + header_.size -= data_.stack_size; + header_.size -= sizeof(data_.dyn_size); // 2. clean the size data_.stack_size = 0; @@ -373,11 +318,11 @@ void PerfRecordSample::ReplaceWithCallStack(size_t originalSize) HLOGV("ips change from %llu -> %zu", data_.nr, ips_.size()); // 3. remove the nr size - header.size -= data_.nr * sizeof(u64); + header_.size -= data_.nr * sizeof(u64); // 4. add new nr size data_.nr = ips_.size(); - header.size += data_.nr * sizeof(u64); + header_.size += data_.nr * sizeof(u64); // 5. change ips potin to our ips array and hold it. data_.ips = ips_.data(); @@ -388,20 +333,21 @@ void PerfRecordSample::ReplaceWithCallStack(size_t originalSize) } } -PerfRecordSample::PerfRecordSample(uint8_t *p, const perf_event_attr &attr) - : PerfEventRecord(p, "sample") +void PerfRecordSample::Init(uint8_t *p, const perf_event_attr &attr) { - if (p == nullptr) { - HLOG_ASSERT(p); - return; - } - // clear the static vector data + PerfEventRecord::InitHeader(p); + + HLOG_ASSERT(p != nullptr); + // clear the vector data Clean(); sampleType_ = attr.sample_type; - + skipKernel_ = 0; + skipPid_ = 0; + stackId_ = {0}; + removeStack_ = false; + data_ = {}; uint8_t *start = p; - - p += sizeof(header); + p += sizeof(header_); // parse record according SAMPLE_TYPE PopFromBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id); @@ -448,7 +394,7 @@ PerfRecordSample::PerfRecordSample(uint8_t *p, const perf_event_attr &attr) p += data_.stack_size; PopFromBinary(true, p, data_.dyn_size); } - uint32_t remain = header.size - (p - start); + uint32_t remain = header_.size - (p - start); if (data_.nr == 0 && dumpRemoveStack_ && remain == sizeof(stackId_)) { PopFromBinary(true, p, stackId_.value); } @@ -605,23 +551,11 @@ void PerfRecordSample::Clean() serverPidMap_.clear(); } -PerfRecordMmap::PerfRecordMmap(uint8_t *p) : PerfEventRecord(p, "mmap") -{ - size_t dataSize = GetSize(); - if (dataSize >= sizeof(header)) { - size_t copySize = dataSize - sizeof(header); - if (memcpy_s(reinterpret_cast(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) { - HLOGE("memcpy_s retren failed !!!"); - } - } else { - HLOGE("PerfRecordMmap retren failed !!!"); - } -} - PerfRecordMmap::PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff, const std::string &filename) - : PerfEventRecord(PERF_RECORD_MMAP, inKernel, "mmap") { + PerfEventRecord::Init(PERF_RECORD_MMAP, inKernel); + data_.pid = pid; data_.tid = tid; data_.addr = addr; @@ -631,7 +565,7 @@ PerfRecordMmap::PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 le HLOGE("strncpy_s failed"); } - header.size = sizeof(header) + sizeof(data_) - KILO + filename.size() + 1; + header_.size = sizeof(header_) + sizeof(data_) - KILO + filename.size() + 1; } bool PerfRecordMmap::GetBinary(std::vector &buf) const @@ -663,27 +597,14 @@ void PerfRecordMmap::DumpData(int indent) const void PerfRecordMmap::DumpLog(const std::string &prefix) const { HLOGV("%s: MMAP: size %d pid %u tid %u dso '%s' (0x%llx-0x%llx)@0x%llx", prefix.c_str(), - header.size, data_.pid, data_.tid, data_.filename, data_.addr, data_.addr + data_.len, data_.pgoff); -} - -PerfRecordMmap2::PerfRecordMmap2(uint8_t *p) : PerfEventRecord(p, "mmap2") -{ - size_t dataSize = GetSize(); - if (dataSize >= sizeof(header)) { - size_t copySize = dataSize - sizeof(header); - if (memcpy_s(reinterpret_cast(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) { - HLOGE("memcpy_s retren failed !!!"); - } - } else { - HLOGE("PerfRecordMmap2 retren failed !!!"); - } + header_.size, data_.pid, data_.tid, data_.filename, data_.addr, data_.addr + data_.len, data_.pgoff); } PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff, u32 maj, u32 min, u64 ino, u32 prot, u32 flags, const std::string &filename) - : PerfEventRecord(PERF_RECORD_MMAP2, inKernel, "mmap2") { + PerfEventRecord::Init(PERF_RECORD_MMAP2, inKernel); data_.pid = pid; data_.tid = tid; data_.addr = addr; @@ -699,12 +620,12 @@ PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, u64 addr, u64 HLOGE("strncpy_s failed"); } - header.size = sizeof(header) + sizeof(data_) - KILO + filename.size() + 1; + header_.size = sizeof(header_) + sizeof(data_) - KILO + filename.size() + 1; } PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, std::shared_ptr item) - : PerfEventRecord(PERF_RECORD_MMAP2, inKernel, "mmap2") { + PerfEventRecord::Init(PERF_RECORD_MMAP2, inKernel); data_.pid = pid; data_.tid = tid; if (item != nullptr) { @@ -722,7 +643,7 @@ PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, std::shared_pt HLOGE("strncpy_s failed"); } - header.size = sizeof(header) + sizeof(data_) - KILO + item->name.size() + 1; + header_.size = sizeof(header_) + sizeof(data_) - KILO + item->name.size() + 1; } else { data_.addr = 0; data_.len = 0; @@ -765,26 +686,14 @@ void PerfRecordMmap2::DumpData(int indent) const } #endif } + void PerfRecordMmap2::DumpLog(const std::string &prefix) const { HLOGV("%s: MMAP2: size %d pid %u tid %u dso '%s' (0x%llx-0x%llx)@0x%llx", prefix.c_str(), - header.size, data_.pid, data_.tid, data_.filename, data_.addr, data_.addr + data_.len, + header_.size, data_.pid, data_.tid, data_.filename, data_.addr, data_.addr + data_.len, data_.pgoff); } -PerfRecordLost::PerfRecordLost(uint8_t *p) : PerfEventRecord(p, "lost") -{ - size_t dataSize = GetSize(); - if (dataSize >= sizeof(header)) { - size_t copySize = dataSize - sizeof(header); - if (memcpy_s(reinterpret_cast(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) { - HLOGE("memcpy_s retren failed !!!"); - } - } else { - HLOGE("PerfRecordLost retren failed !!!"); - } -} - bool PerfRecordLost::GetBinary(std::vector &buf) const { if (buf.size() < GetSize()) { @@ -805,29 +714,17 @@ void PerfRecordLost::DumpData(int indent) const PRINT_INDENT(indent, "id %llu, lost %llu\n", data_.id, data_.lost); } -PerfRecordComm::PerfRecordComm(uint8_t *p) : PerfEventRecord(p, "comm") -{ - size_t dataSize = GetSize(); - if (dataSize >= sizeof(header)) { - size_t copySize = dataSize - sizeof(header); - if (memcpy_s(reinterpret_cast(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) { - HLOGE("memcpy_s retren failed !!!"); - } - } else { - HLOGE("PerfRecordComm retren failed !!!"); - } -} PerfRecordComm::PerfRecordComm(bool inKernel, u32 pid, u32 tid, const std::string &comm) - : PerfEventRecord(PERF_RECORD_COMM, inKernel, "comm") { + PerfEventRecord::Init(PERF_RECORD_COMM, inKernel); data_.pid = pid; data_.tid = tid; if (strncpy_s(data_.comm, KILO, comm.c_str(), comm.size()) != 0) { HLOGE("strncpy_s failed !!!"); } - header.size = sizeof(header) + sizeof(data_) - KILO + comm.size() + 1; + header_.size = sizeof(header_) + sizeof(data_) - KILO + comm.size() + 1; } bool PerfRecordComm::GetBinary(std::vector &buf) const @@ -856,17 +753,31 @@ void PerfRecordComm::DumpLog(const std::string &prefix) const HLOGV("pid %u, tid %u, comm %s\n", data_.pid, data_.tid, data_.comm); } -PerfRecordExit::PerfRecordExit(uint8_t *p) : PerfEventRecord(p, "exit") +PerfRecordSample::PerfRecordSample(const PerfRecordSample& sample) { - size_t dataSize = GetSize(); - if (dataSize >= sizeof(header)) { - size_t copySize = dataSize - sizeof(header); - if (memcpy_s(reinterpret_cast(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) { - HLOGE("memcpy_s retren failed !!!"); - } - } else { - HLOGE("PerfRecordExit retren failed !!!"); - } + header_ = sample.header_; + data_ = sample.data_; + + sampleType_ = sample.sampleType_; + skipKernel_ = sample.skipKernel_; + skipPid_ = sample.skipPid_; + + ips_ = sample.ips_; + callFrames_ = sample.callFrames_; + serverPidMap_ = sample.serverPidMap_; + + stackId_ = sample.stackId_; + removeStack_ = sample.removeStack_; +} + +void PerfRecordSample::SetDumpRemoveStack(bool dumpRemoveStack) +{ + dumpRemoveStack_ = dumpRemoveStack; +} + +bool PerfRecordSample::IsDumpRemoveStack() +{ + return dumpRemoveStack_; } bool PerfRecordExit::GetBinary(std::vector &buf) const @@ -889,19 +800,6 @@ void PerfRecordExit::DumpData(int indent) const data_.tid, data_.ptid, data_.time); } -PerfRecordThrottle::PerfRecordThrottle(uint8_t *p) : PerfEventRecord(p, "throttle") -{ - size_t dataSize = GetSize(); - if (dataSize >= sizeof(header)) { - size_t copySize = dataSize - sizeof(header); - if (memcpy_s(reinterpret_cast(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) { - HLOGE("memcpy_s retren failed !!!"); - } - } else { - HLOGE("PerfRecordThrottle retren failed !!!"); - } -} - bool PerfRecordThrottle::GetBinary(std::vector &buf) const { if (buf.size() < GetSize()) { @@ -922,19 +820,6 @@ void PerfRecordThrottle::DumpData(int indent) const data_.stream_id); } -PerfRecordUnthrottle::PerfRecordUnthrottle(uint8_t *p) : PerfEventRecord(p, "unthrottle") -{ - size_t dataSize = GetSize(); - if (dataSize >= sizeof(header)) { - size_t copySize = dataSize - sizeof(header); - if (memcpy_s(reinterpret_cast(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) { - HLOGE("memcpy_s retren failed !!!"); - } - } else { - HLOGE("PerfRecordUnthrottle retren failed !!!"); - } -} - bool PerfRecordUnthrottle::GetBinary(std::vector &buf) const { if (buf.size() < GetSize()) { @@ -948,25 +833,13 @@ bool PerfRecordUnthrottle::GetBinary(std::vector &buf) const *pDest = data_; return true; } + void PerfRecordUnthrottle::DumpData(int indent) const { PRINT_INDENT(indent, "time 0x%llx, id %llx, stream_id %llx\n", data_.time, data_.id, data_.stream_id); } -PerfRecordFork::PerfRecordFork(uint8_t *p) : PerfEventRecord(p, "fork") -{ - size_t dataSize = GetSize(); - if (dataSize >= sizeof(header)) { - size_t copySize = dataSize - sizeof(header); - if (memcpy_s(reinterpret_cast(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) { - HLOGE("memcpy_s retren failed !!!"); - } - } else { - HLOGE("PerfRecordFork retren failed !!!"); - } -} - bool PerfRecordFork::GetBinary(std::vector &buf) const { if (buf.size() < GetSize()) { @@ -987,19 +860,6 @@ void PerfRecordFork::DumpData(int indent) const data_.ptid); } -PerfRecordRead::PerfRecordRead(uint8_t *p) : PerfEventRecord(p, "read") -{ - size_t dataSize = GetSize(); - if (dataSize >= sizeof(header)) { - size_t copySize = dataSize - sizeof(header); - if (memcpy_s(reinterpret_cast(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) { - HLOGE("memcpy_s retren failed !!!"); - } - } else { - HLOGE("PerfRecordRead retren failed !!!"); - } -} - bool PerfRecordRead::GetBinary(std::vector &buf) const { if (buf.size() < GetSize()) { @@ -1021,19 +881,6 @@ void PerfRecordRead::DumpData(int indent) const data_.values.value, data_.values.timeEnabled, data_.values.timeRunning, data_.values.id); } -PerfRecordAux::PerfRecordAux(uint8_t *p) : PerfEventRecord(p, "aux") -{ - size_t dataSize = GetSize(); - if (dataSize >= sizeof(header)) { - size_t copySize = dataSize - sizeof(header); - if (memcpy_s(reinterpret_cast(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) { - HLOGE("memcpy_s retren failed !!!"); - } - } else { - HLOGE("PerfRecordAux retren failed !!!"); - } -} - bool PerfRecordAux::GetBinary(std::vector &buf) const { if (buf.size() < GetSize()) { @@ -1063,19 +910,6 @@ void PerfRecordAux::DumpData(int indent) const data_.sample_id.time); } -PerfRecordItraceStart::PerfRecordItraceStart(uint8_t *p) : PerfEventRecord(p, "itraceStart") -{ - size_t dataSize = GetSize(); - if (dataSize >= sizeof(header)) { - size_t copySize = dataSize - sizeof(header); - if (memcpy_s(reinterpret_cast(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) { - HLOGE("memcpy_s retren failed !!!"); - } - } else { - HLOGE("PerfRecordItraceStart retren failed !!!"); - } -} - bool PerfRecordItraceStart::GetBinary(std::vector &buf) const { if (buf.size() < GetSize()) { @@ -1095,19 +929,6 @@ void PerfRecordItraceStart::DumpData(int indent) const PRINT_INDENT(indent, "pid %u, tid %u\n", data_.pid, data_.tid); } -PerfRecordLostSamples::PerfRecordLostSamples(uint8_t *p) : PerfEventRecord(p, "lostSamples") -{ - size_t dataSize = GetSize(); - if (dataSize >= sizeof(header)) { - size_t copySize = dataSize - sizeof(header); - if (memcpy_s(reinterpret_cast(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) { - HLOGE("memcpy_s retren failed !!!"); - } - } else { - HLOGE("PerfRecordLostSamples retren failed !!!"); - } -} - bool PerfRecordLostSamples::GetBinary(std::vector &buf) const { if (buf.size() < GetSize()) { @@ -1127,19 +948,6 @@ void PerfRecordLostSamples::DumpData(int indent) const PRINT_INDENT(indent, "lost %llu\n", data_.lost); } -PerfRecordSwitch::PerfRecordSwitch(uint8_t *p) : PerfEventRecord(p, "switch") -{ - size_t dataSize = GetSize(); - if (dataSize >= sizeof(header)) { - size_t copySize = dataSize - sizeof(header); - if (memcpy_s(reinterpret_cast(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) { - HLOGE("memcpy_s retren failed !!!"); - } - } else { - HLOGE("PerfRecordSwitch retren failed !!!"); - } -} - bool PerfRecordSwitch::GetBinary(std::vector &buf) const { if (buf.size() < GetSize()) { @@ -1154,19 +962,6 @@ bool PerfRecordSwitch::GetBinary(std::vector &buf) const return true; } -PerfRecordSwitchCpuWide::PerfRecordSwitchCpuWide(uint8_t *p) : PerfEventRecord(p, "switchCpuWide") -{ - size_t dataSize = GetSize(); - if (dataSize >= sizeof(header)) { - size_t copySize = dataSize - sizeof(header); - if (memcpy_s(reinterpret_cast(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) { - HLOGE("memcpy_s retren failed !!!"); - } - } else { - HLOGE("PerfRecordSwitchCpuWide retren failed !!!"); - } -} - bool PerfRecordSwitchCpuWide::GetBinary(std::vector &buf) const { if (buf.size() < GetSize()) { @@ -1246,6 +1041,23 @@ pid_t PerfRecordSample::GetServerPidof(unsigned int ipNr) return serverPidMap_[ipNr]; } } + +PerfEventRecord& PerfEventRecordFactory::GetPerfEventRecord(PerfRecordType type, uint8_t* data, + const perf_event_attr &attr) +{ + HLOG_ASSERT(data != nullptr); + PerfEventRecord* record = nullptr; + auto it = recordMap_.find(type); + if (it == recordMap_.end()) { + record = CreatePerfEventRecord(type); + recordMap_.emplace(type, record); + } else { + record = it->second; + } + record->Init(data, attr); + return *record; +} + } // namespace HiPerf } // namespace Developtools } // namespace OHOS diff --git a/src/perf_events.cpp b/src/perf_events.cpp index 9440382..1650af4 100644 --- a/src/perf_events.cpp +++ b/src/perf_events.cpp @@ -117,16 +117,16 @@ void PerfEvents::ReadRecordsFromSpeMmaps(MmapFd& mmapFd, u64 auxOffset, u64 auxS arm_spe_reference(), cpu, tid, cpu, pid); static std::vector vbuf(RECORD_SIZE_LIMIT); uint8_t *buf; - if ((buf = recordBuf_->AllocForWrite(auxtraceRecord.header.size + auxSize)) == nullptr) { + if ((buf = recordBuf_->AllocForWrite(auxtraceRecord.header_.size + auxSize)) == nullptr) { HLOGD("alloc buffer failed: PerfRecordAuxtrace record, readSize: %llu", auxSize); return; } auxtraceRecord.GetBinary1(vbuf); - if (memcpy_s(buf, auxtraceRecord.header.size, vbuf.data(), auxtraceRecord.header.size) != 0) { + if (memcpy_s(buf, auxtraceRecord.header_.size, vbuf.data(), auxtraceRecord.header_.size) != 0) { HLOGE("memcpy_s return failed"); return; } - buf += auxtraceRecord.header.size; + buf += auxtraceRecord.header_.size; while (auxSize > 0) { u64 readSize = pageSize_; @@ -412,7 +412,7 @@ void PerfEvents::SetConfig(std::map &speO bool PerfEvents::AddEvent(perf_type_id type, __u64 config, bool excludeUser, bool excludeKernel, bool followGroup) { - HLOG_ASSERT(!excludeUser or !excludeKernel); + HLOG_ASSERT(!excludeUser || !excludeKernel); CHECK_TRUE(followGroup && eventGroupItem_.empty(), false, 1, "no group leader create before"); // found the event name CHECK_TRUE(!IsEventSupport(type, config), false, 0, ""); @@ -1624,7 +1624,7 @@ void PerfEvents::ReadRecordFromBuf() const auto readingStartTime_ = steady_clock::now(); #endif #if !HIDEBUG_SKIP_CALLBACK - recordCallBack_(GetPerfSampleFromCache(*type, p, *attr)); + recordCallBack_(PerfEventRecordFactory::GetPerfEventRecord(*type, p, *attr)); #endif recordEventCount_++; #ifdef HIPERF_DEBUG_TIME @@ -1643,7 +1643,7 @@ void PerfEvents::ReadRecordFromBuf() const auto readingStartTime_ = steady_clock::now(); #endif #if !HIDEBUG_SKIP_CALLBACK - recordCallBack_(GetPerfSampleFromCache(*type, p, *attr)); + recordCallBack_(PerfEventRecordFactory::GetPerfEventRecord(*type, p, *attr)); #endif recordEventCount_++; #ifdef HIPERF_DEBUG_TIME diff --git a/src/perf_file_format.cpp b/src/perf_file_format.cpp index b842223..41729df 100644 --- a/src/perf_file_format.cpp +++ b/src/perf_file_format.cpp @@ -134,12 +134,13 @@ bool PerfFileSection::Read(std::string &value) CHECK_TRUE(!Read(size), false, 0, ""); // if size large than buf size or 0 size ? // don't assert for fuzz test - CHECK_TRUE(size == 0 or size > maxSize_, false, 0, ""); - char buf[size]; + CHECK_TRUE(size == 0 || size > maxSize_, false, 0, ""); + char *buf = new char[size]; CHECK_TRUE(!Read(buf, size), false, 0, ""); CHECK_TRUE(buf[size - 1] != 0, false, 0, ""); value = buf; HLOGDUMMY("Read String size %u buf : %s", size, value.c_str()); + delete []buf; return true; } void PerfFileSection::Skip(size_t size) diff --git a/src/perf_file_reader.cpp b/src/perf_file_reader.cpp index c051b20..a053ee2 100644 --- a/src/perf_file_reader.cpp +++ b/src/perf_file_reader.cpp @@ -46,7 +46,9 @@ std::unique_ptr PerfFileReader::Instance(const std::string &file if (!reader->ReadFileHeader()) { // Fail to read header, maybe its compressed if (reader->IsGzipFile()) { - fclose(fp); + if (fp != nullptr) { + fclose(fp); + } reader->fp_ = nullptr; CHECK_TRUE(!UncompressFile(fileName, UNCOMPRESS_TMP_FILE), nullptr, 1, @@ -80,7 +82,7 @@ PerfFileReader::PerfFileReader(const std::string &fileName, FILE *fp) : fp_(fp), featureSectionOffset_ = 0; struct stat fileStat; if (fp != nullptr) { - if (fstat(fileno(fp), &fileStat) != -1 and fileStat.st_size > 0) { + if (fstat(fileno(fp), &fileStat) != -1 && fileStat.st_size > 0) { fileSize_ = fileStat.st_size; } } @@ -110,7 +112,7 @@ bool PerfFileReader::IsValidDataFile() bool PerfFileReader::IsGzipFile() { - return header_.magic[0] == '\x1f' and header_.magic[1] == '\x8b'; + return header_.magic[0] == '\x1f' && header_.magic[1] == '\x8b'; } bool PerfFileReader::ReadFileHeader() @@ -276,20 +278,20 @@ bool PerfFileReader::ReadRecord(ProcessRecordCB &callback) } } uint8_t *data = buf; - std::unique_ptr record = GetPerfEventRecord( + PerfEventRecord& record = PerfEventRecordFactory::GetPerfEventRecord( static_cast(header->type), data, *attr); // unknown record , break the process - if (!record) { + if (record.GetName() == nullptr) { return false; } else { - HLOGV("record type %u", record->GetType()); + HLOGV("record type %u", record.GetType()); } remainingSize = remainingSize - header->size - speSize; #ifdef HIPERF_DEBUG_TIME const auto startCallbackTime = steady_clock::now(); #endif // call callback to process, then destroy record - callback(std::move(record)); + callback(record); recordNumber++; #ifdef HIPERF_DEBUG_TIME readCallbackTime_ += @@ -404,7 +406,7 @@ bool PerfFileReader::ReadFeatureSection() HLOGV("process feature %d:%s", feature, PerfFileSection::GetFeatureName(feature).c_str()); HLOGV(" sectionHeader -> read offset '0x%" PRIx64 " size '0x%" PRIx64 "'", sectionHeader.offset, sectionHeader.size); - CHECK_TRUE(sectionHeader.size == 0 or sectionHeader.size > fileSize_, false, 1, + CHECK_TRUE(sectionHeader.size == 0 || sectionHeader.size > fileSize_, false, 1, "sectionHeader.size %" PRIu64 " is not correct", sectionHeader.size); std::vector buf(sectionHeader.size); @@ -423,7 +425,7 @@ bool PerfFileReader::ReadFeatureSection() } else if (feature == FEATURE::HIPERF_FILES_UNISTACK_TABLE) { perfFileSections_.emplace_back( std::make_unique(feature, (char *)&buf[0], buf.size())); - PerfRecordSample::dumpRemoveStack_ = true; + PerfRecordSample::SetDumpRemoveStack(true); } else { HLOGW("still not imp how to process with feature %d", feature); } diff --git a/src/perf_file_writer.cpp b/src/perf_file_writer.cpp index eab0bff..72913a4 100644 --- a/src/perf_file_writer.cpp +++ b/src/perf_file_writer.cpp @@ -125,10 +125,10 @@ bool PerfFileWriter::WriteRecord(const PerfEventRecord &record) return false; } - HLOGV("write '%s', size %zu", record.GetName().c_str(), record.GetSize()); + HLOGV("write '%s', size %zu", record.GetName(), record.GetSize()); CHECK_TRUE(record.GetSize() > RECORD_SIZE_LIMIT_SPE, false, 1, - "%s record size exceed limit", record.GetName().c_str()); + "%s record size exceed limit", record.GetName()); // signal 7 (SIGBUS), code 1 (BUS_ADRALN), fault addr 0xb64eb195 static std::vector buf(RECORD_SIZE_LIMIT_SPE); @@ -186,13 +186,13 @@ bool PerfFileWriter::ReadRecords(ProcessRecordCB &callback) } uint8_t *data = buf; // the record is allowed from a cache memory, does not free memory after use - auto record = GetPerfSampleFromCacheMain(static_cast(header->type), - data, defaultEventAttr_); + PerfEventRecord& record = PerfEventRecordFactory::GetPerfEventRecord( + static_cast(header->type), data, defaultEventAttr_); // skip unknown record - CHECK_TRUE(record == nullptr, true, 0, ""); + CHECK_TRUE(record.GetName() == nullptr, true, 0, ""); remainingSize = remainingSize - header->size - speSize; // call callback to process, do not destroy the record - callback(std::move(record)); + callback(record); recordNumber++; } } else { @@ -214,6 +214,11 @@ bool PerfFileWriter::Read(void *buf, size_t len) return true; } +void PerfFileWriter::SetWriteRecordStat(bool isWrite) +{ + isWritingRecord = isWrite; +} + uint64_t PerfFileWriter::GetDataSize() const { return dataSection_.size; diff --git a/src/register.cpp b/src/register.cpp index 79fb432..993bbd6 100644 --- a/src/register.cpp +++ b/src/register.cpp @@ -63,7 +63,7 @@ uint64_t GetSupportedRegMask(ArchType arch) break; default: result = std::numeric_limits::max(); - HLOGE("unsupport arch %d", arch); + HLOGE("unsupport arch %u", arch); break; } return result; @@ -272,7 +272,7 @@ ArchType GetDeviceArch() void UpdateRegForABI(ArchType arch, u64 *regs) { - if (g_deviceArchType == ArchType::ARCH_ARM64 and arch == ArchType::ARCH_ARM) { + if (g_deviceArchType == ArchType::ARCH_ARM64 && arch == ArchType::ARCH_ARM) { // arm in arm64 regs[PERF_REG_ARM_PC] = regs[PERF_REG_ARM64_PC]; } diff --git a/src/report.cpp b/src/report.cpp index a6c11a7..5c4f758 100644 --- a/src/report.cpp +++ b/src/report.cpp @@ -41,49 +41,47 @@ void Report::AddReportItem(const PerfRecordSample &sample, bool includeCallStack configIndex, sample.data_.id); VirtualThread &thread = virtualRuntime_.GetThread(sample.data_.pid, sample.data_.tid); HLOG_ASSERT(sample.callFrames_.size() > 0); - if (sample.callFrames_.size() > 0) { - // if we need callstack ? - if (includeCallStack) { - // we will use caller mode , from last to first - auto frameIt = sample.callFrames_.rbegin(); + // if we need callstack ? + if (includeCallStack) { + // we will use caller mode , from last to first + auto frameIt = sample.callFrames_.rbegin(); + ReportItem &item = configs_[configIndex].reportItems_.emplace_back( + sample.data_.pid, sample.data_.tid, thread.name_, frameIt->mapName, + frameIt->funcName, frameIt->funcOffset, sample.data_.period); + HLOGD("ReportItem: %s", item.ToDebugString().c_str()); + HLOG_ASSERT(!item.func_.empty()); + + std::vector *currentCallFrames = &item.callStacks_; + for (frameIt = sample.callFrames_.rbegin(); frameIt != sample.callFrames_.rend(); + frameIt++) { + HLOG_ASSERT(frameIt->pc < PERF_CONTEXT_MAX); + // in add items case , right one should only have 1 callstack + // so just new callfames and move to next level + ReportItemCallFrame &nextCallFrame = currentCallFrames->emplace_back( + frameIt->funcName, frameIt->funcOffset, frameIt->mapName, + sample.data_.period, + (std::next(frameIt) == sample.callFrames_.rend()) ? sample.data_.period : 0); + HLOGV("add callframe %s", nextCallFrame.ToDebugString().c_str()); + currentCallFrames = &nextCallFrame.childs; + } + HLOGV("callstack %zu", item.callStacks_.size()); + if (item.callStacks_.size() > 0) { + HLOGV("callstack 2nd level %zu", item.callStacks_[0].childs.size()); + } + } else { + auto frameIt = sample.callFrames_.begin(); + if (frameIt != sample.callFrames_.end()) { + HLOG_ASSERT(frameIt->pc < PERF_CONTEXT_MAX); + // for arkjs frame, skip the stub.an frame + if (StringEndsWith(frameIt->mapName, "stub.an") && sample.callFrames_.size() > 1) { + HLOGV("stub.an frame, go to next, mapname %s", frameIt->mapName.c_str()); + frameIt++; + } ReportItem &item = configs_[configIndex].reportItems_.emplace_back( sample.data_.pid, sample.data_.tid, thread.name_, frameIt->mapName, frameIt->funcName, frameIt->funcOffset, sample.data_.period); - HLOGD("ReportItem: %s", item.ToDebugString().c_str()); + HLOGV("%s", item.ToDebugString().c_str()); HLOG_ASSERT(!item.func_.empty()); - - std::vector *currentCallFrames = &item.callStacks_; - for (frameIt = sample.callFrames_.rbegin(); frameIt != sample.callFrames_.rend(); - frameIt++) { - HLOG_ASSERT(frameIt->pc < PERF_CONTEXT_MAX); - // in add items case , right one should only have 1 callstack - // so just new callfames and move to next level - ReportItemCallFrame &nextCallFrame = currentCallFrames->emplace_back( - frameIt->funcName, frameIt->funcOffset, frameIt->mapName, - sample.data_.period, - (std::next(frameIt) == sample.callFrames_.rend()) ? sample.data_.period : 0); - HLOGV("add callframe %s", nextCallFrame.ToDebugString().c_str()); - currentCallFrames = &nextCallFrame.childs; - } - HLOGV("callstack %zu", item.callStacks_.size()); - if (item.callStacks_.size() > 0) { - HLOGV("callstack 2nd level %zu", item.callStacks_[0].childs.size()); - } - } else { - auto frameIt = sample.callFrames_.begin(); - if (frameIt != sample.callFrames_.end()) { - HLOG_ASSERT(frameIt->pc < PERF_CONTEXT_MAX); - // for arkjs frame, skip the stub.an frame - if (StringEndsWith(frameIt->mapName, "stub.an") && sample.callFrames_.size() > 1) { - HLOGV("stub.an frame, go to next, mapname %s", frameIt->mapName.c_str()); - frameIt++; - } - ReportItem &item = configs_[configIndex].reportItems_.emplace_back( - sample.data_.pid, sample.data_.tid, thread.name_, frameIt->mapName, - frameIt->funcName, frameIt->funcOffset, sample.data_.period); - HLOGV("%s", item.ToDebugString().c_str()); - HLOG_ASSERT(!item.func_.empty()); - } } } configs_[configIndex].sampleCount_++; @@ -321,7 +319,7 @@ bool Report::MultiLevelSorting(const ReportItem &a, const ReportItem &b) #ifdef HIPERF_DEBUG if (DebugLogger::GetInstance()->GetLogLevel() <= LEVEL_VERBOSE) { bool result2 = MultiLevelCompare(b, a) > 0; - if (result and result == result2) { + if (result && result == result2) { HLOGE("MultiLevelSorting a->b %d vs b->a %d", result, result2); HLOGE("left %s", a.ToDebugString().c_str()); HLOGE("right %s", b.ToDebugString().c_str()); @@ -456,14 +454,14 @@ void Report::OutputStdCallFrames(int indent, const ReportItemCallFrame &callFram NO_RETVAL, 0, ""); // print it self - if (callFrame.selfEventCount_ != 0 and callFrame.selfEventCount_ != callFrame.eventCount_) { + if (callFrame.selfEventCount_ != 0 && callFrame.selfEventCount_ != callFrame.eventCount_) { OutputStdCallFrame(indent + CALLSTACK_INDENT, "[run in self function]", callFrame.selfEventCount_, callFrame.eventCount_); } // printf children // if only one children - if (callFrame.childs.size() == 1u and + if (callFrame.childs.size() == 1u && callFrame.childs[0].eventCount_ == callFrame.eventCount_) { HLOGV("childCallFream %*c %s", indent, ' ', callFrame.childs[0].func_.data()); // don't indent if same count (only one 100% children) @@ -519,7 +517,7 @@ void Report::OutputStdContentItem(const ReportItem &reportItem) void Report::OutputStdItemHeating(float heat, float heat2) { - if (heat == heat2 and heat == 0.0f) { + if (heat == heat2 && heat == 0.0f) { fprintf(output_, "something error , all it is end.\n"); } else if (heat2 == 0) { // only have first @@ -560,7 +558,7 @@ void Report::OutputStdContentDiff(ReportEventConfigItem &left, ReportEventConfig if (MultiLevelSame(*it, *it2)) { // we found the same item // output the diff heating - if (it->heat > option_.heatLimit_ and it2->heat > option_.heatLimit_) { + if (it->heat > option_.heatLimit_ && it2->heat > option_.heatLimit_) { OutputStdItemHeating(it->heat, it2->heat); OutputStdContentItem(*it); } diff --git a/src/report_protobuf_file.cpp b/src/report_protobuf_file.cpp index cc76d52..5aac1be 100644 --- a/src/report_protobuf_file.cpp +++ b/src/report_protobuf_file.cpp @@ -215,7 +215,7 @@ int ReportProtobufFileReader::Read(void *buffer, int size) return protobufFileStream_->gcount(); } - printf("read file %d bytes failed %s : %s\n", size, fileName_.c_str(), readErr.what()); + HLOGW("read file %d bytes failed %s : %s\n", size, fileName_.c_str(), readErr.what()); } } else { printf("no file open for read (request %d bytes).\n", size); diff --git a/src/ring_buffer.cpp b/src/ring_buffer.cpp index 1d78a0a..eb8ed95 100644 --- a/src/ring_buffer.cpp +++ b/src/ring_buffer.cpp @@ -41,7 +41,7 @@ size_t RingBuffer::GetFreeSize() const uint8_t *RingBuffer::AllocForWrite(size_t writeSize) { - if (buf_ == nullptr || buf_.get() == nullptr) { + if (buf_ == nullptr) { return nullptr; } size_t writeHead = head_.load(std::memory_order_relaxed); @@ -57,7 +57,7 @@ uint8_t *RingBuffer::AllocForWrite(size_t writeSize) if (writePos + writeSize > readPos) { return nullptr; } - } else if (writePos == readPos and writeHead != readHead) { + } else if (writePos == readPos && writeHead != readHead) { // writePos catch up with readPos, but buffer is full return nullptr; } else { diff --git a/src/spe_decoder.cpp b/src/spe_decoder.cpp index be7cef3..c334708 100644 --- a/src/spe_decoder.cpp +++ b/src/spe_decoder.cpp @@ -259,7 +259,9 @@ static int SpePktOutString(int *err, char **bufPtr, size_t *bufLen, if (err && *err) { return *err; } - + if (*bufLen - 1 < 0) { + HLOGW("SpePktOutString failed, bufLen: %d", static_cast(*bufLen)); + } va_start(args, fmt); ret = vsnprintf_s(*bufPtr, *bufLen, *bufLen - 1, fmt, args); va_end(args); @@ -268,6 +270,7 @@ static int SpePktOutString(int *err, char **bufPtr, size_t *bufLen, if (err && !*err) { *err = ret; } + HLOGW("vsnprintf_s failed: %d\n", ret); /* * If the return value is *bufLen or greater, the output was @@ -627,21 +630,6 @@ static u64 SpeCalcIp(int index, u64 payload) return payload; } -struct SpeDecoder *SpeDecoderNew(struct SpeParams *params) -{ - CHECK_TRUE(params == nullptr, nullptr, 1, "Invalid pointer!"); - struct SpeDecoder *decoder; - - decoder = static_cast(malloc(sizeof(struct SpeDecoder))); - if (!decoder) { - return NULL; - } - - decoder->data = params->data; - - return decoder; -} - void SpeDecoderFree(struct SpeDecoder *decoder) { CHECK_TRUE(decoder == nullptr, NO_RETVAL, 1, "Invalid pointer!"); @@ -1009,14 +997,32 @@ void DumpSpeReportData(int indent, FILE *outputDump) for (auto it = AuxRawDataMap_.begin(); it != AuxRawDataMap_.end(); it++) { u64 count = typeCount[it->first]; DumpSpeReportHead(indent, it->first, count); + std::vector auxRawData; for (auto& it2 : it->second) { - PRINT_INDENT(indent + 1, "%*.2f%% ", FULL_PERCENTAGE_LEN, it2.second.heating); - PRINT_INDENT(indent + 1, "%-*llu ", FULL_PERCENTAGE_LEN, it2.second.count); - PRINT_INDENT(indent + 1, "%-*s ", SPE_PERCENTAGE_COMM_LEN, it2.second.comm.c_str()); - PRINT_INDENT(indent + 1, "0x%-*llx ", SPE_PERCENTAGE_PC_LEN, it2.second.pc); - PRINT_INDENT(indent + 1, "%-*s ", SPE_PERCENTAGE_DSO_LEN, it2.second.SharedObject.c_str()); - PRINT_INDENT(indent + 1, "%-*s", SPE_PERCENTAGE_FUNC_LEN, it2.second.Symbol.c_str()); - PRINT_INDENT(indent + 1, "0x%llx\n", it2.second.offset); + struct ReportItemAuxRawData reportItem = { + it2.second.type, + it2.second.heating, + it2.second.count, + it2.second.comm, + it2.second.pc, + it2.second.SharedObject, + it2.second.Symbol, + it2.second.offset + }; + auxRawData.emplace_back(reportItem); + } + std::sort(auxRawData.begin(), auxRawData.end(), [](const ReportItemAuxRawData& lhs, + const ReportItemAuxRawData& rhs) { + return lhs.count > rhs.count; + }); + for (auto& it3 : auxRawData) { + PRINT_INDENT(indent + 1, "%*.2f%% ", FULL_PERCENTAGE_LEN, it3.heating); + PRINT_INDENT(indent + 1, "%-*llu ", FULL_PERCENTAGE_LEN, it3.count); + PRINT_INDENT(indent + 1, "%-*s ", SPE_PERCENTAGE_COMM_LEN, it3.comm.c_str()); + PRINT_INDENT(indent + 1, "0x%-*llx ", SPE_PERCENTAGE_PC_LEN, it3.pc); + PRINT_INDENT(indent + 1, "%-*s ", SPE_PERCENTAGE_DSO_LEN, it3.SharedObject.c_str()); + PRINT_INDENT(indent + 1, "%-*s", SPE_PERCENTAGE_FUNC_LEN, it3.Symbol.c_str()); + PRINT_INDENT(indent + 1, "0x%llx\n", it3.offset); } } } diff --git a/src/subcommand.cpp b/src/subcommand.cpp index 70d326d..1751415 100644 --- a/src/subcommand.cpp +++ b/src/subcommand.cpp @@ -18,7 +18,6 @@ #include "debug_logger.h" #include "option.h" -using namespace std; namespace OHOS { namespace Developtools { namespace HiPerf { @@ -146,7 +145,7 @@ void SubCommand::ExcludeThreadsFromSelectTids(const std::vector &ex } } -bool SubCommand::RegisterSubCommand(std::string cmdName, std::unique_ptr subCommand) +bool SubCommand::RegisterSubCommand(const std::string& cmdName, std::unique_ptr subCommand) { HLOGV("%s", cmdName.c_str()); if (cmdName.empty()) { @@ -158,7 +157,7 @@ bool SubCommand::RegisterSubCommand(std::string cmdName, std::unique_ptr lock(g_subCommandMutex); g_SubCommandsMap.insert(std::make_pair(cmdName, std::move(subCommand))); return true; diff --git a/src/subcommand_dump.cpp b/src/subcommand_dump.cpp index f5bf82b..069be66 100644 --- a/src/subcommand_dump.cpp +++ b/src/subcommand_dump.cpp @@ -381,13 +381,15 @@ void SubCommandDump::DumpAttrPortion(int indent) void SubCommandDump::ExprotUserStack(const PerfRecordSample &recordSample) { - if (recordSample.data_.reg_nr > 0 and recordSample.data_.dyn_size > 0) { + if (recordSample.data_.reg_nr > 0 && recordSample.data_.dyn_size > 0) { // __user_regs_