From 45e403fdbffc4b6b07f524ae8ec6b21002af302d Mon Sep 17 00:00:00 2001 From: yuanye Date: Sat, 16 Nov 2024 18:23:09 +0800 Subject: [PATCH 01/13] =?UTF-8?q?=E5=AF=B9=E8=B1=A1=E5=A4=8D=E7=94=A8?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yuanye --- include/perf_event_record.h | 415 +++++----- include/perf_events.h | 2 +- include/perf_file_reader.h | 2 +- include/perf_file_writer.h | 2 +- include/subcommand_dump.h | 4 +- include/subcommand_record.h | 6 +- include/subcommand_report.h | 2 +- include/virtual_runtime.h | 2 +- src/perf_event_record.cpp | 1454 ++++++++++++++++------------------- src/perf_events.cpp | 10 +- src/perf_file_reader.cpp | 10 +- src/perf_file_writer.cpp | 10 +- src/subcommand_dump.cpp | 30 +- src/subcommand_record.cpp | 76 +- src/subcommand_report.cpp | 14 +- src/virtual_runtime.cpp | 52 +- 16 files changed, 987 insertions(+), 1104 deletions(-) diff --git a/include/perf_event_record.h b/include/perf_event_record.h index ae10c66..a553017 100644 --- a/include/perf_event_record.h +++ b/include/perf_event_record.h @@ -38,63 +38,39 @@ namespace OHOS { namespace Developtools { namespace HiPerf { -using namespace OHOS::HiviewDFX; +// 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 const char PERF_RECORD_TYPE_AUXTRACE[] = "auxtrace"; +static const char PERF_RECORD_TYPE_SAMPLE[] = "sample"; +static const char PERF_RECORD_TYPE_MMAP[] = "mmap"; +static const char PERF_RECORD_TYPE_MMAP2[] = "mmap2"; +static const char PERF_RECORD_TYPE_LOST[] = "lost"; +static const char PERF_RECORD_TYPE_COMM[] = "comm"; +static const char PERF_RECORD_TYPE_EXIT[] = "exit"; +static const char PERF_RECORD_TYPE_THROTTLE[] = "throttle"; +static const char PERF_RECORD_TYPE_UNTHROTTLE[] = "unthrottle"; +static const char PERF_RECORD_TYPE_FORK[] = "fork"; +static const char PERF_RECORD_TYPE_READ[] = "read"; +static const char PERF_RECORD_TYPE_AUX[] = "aux"; +static const char PERF_RECORD_TYPE_ITRACESTART[] = "itraceStart"; +static const char PERF_RECORD_TYPE_LOSTSAMPLE[] = "lostSamples"; +static const char PERF_RECORD_TYPE_SWITCH[] = "switch"; +static const char PERF_RECORD_TYPE_SWITCHCPUWIDE[] = "switchCpuWide"; + 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; - } -}; +// static inline const std::string RECORD_TYPE_NAME = type; +// const std::string& GetName() const override +// { +// return RECORD_TYPE_NAME; +// } struct AttrWithId { perf_event_attr attr; @@ -104,62 +80,162 @@ struct AttrWithId { class PerfEventRecord { public: - PerfEventRecord(const PerfEventRecord &) = delete; - PerfEventRecord &operator=(const PerfEventRecord &) = delete; + virtual const char* GetNameP() const; + virtual void Init(uint8_t *data, const perf_event_attr& attr) = 0; - struct perf_event_header header; - const std::string name_ {}; + virtual ~PerfEventRecord() = default; - PerfEventRecord(perf_event_type type, bool inKernel, const std::string &name); - PerfEventRecord(perf_event_hiperf_ext_type type, const std::string &name); + virtual size_t GetSize() const = 0; + virtual size_t GetHeaderSize() const = 0; + virtual void GetHeaderBinary(std::vector &buf) const = 0; - PerfEventRecord(uint8_t *p, const std::string &name); - - virtual ~PerfEventRecord() {} - - virtual size_t GetSize() const - { - return header.size; - }; - size_t GetHeaderSize() const - { - return sizeof(header); - }; - void GetHeaderBinary(std::vector &buf) const; - - uint32_t GetType() const - { - return header.type; - }; - uint16_t GetMisc() const - { - return header.misc; - }; - bool inKernel() - { - return header.misc & PERF_RECORD_MISC_KERNEL; - } - bool inUser() - { - return header.misc & PERF_RECORD_MISC_USER; - } - const std::string &GetName() const - { - return name_; - }; + virtual uint32_t GetType() const = 0; + virtual uint16_t GetMisc() const = 0; + virtual bool InKernel() = 0; + virtual bool InUser() = 0; // to support --exclude-hiperf, return sample_id.pid to filter record, - virtual pid_t GetPid() const + virtual pid_t GetPid() const = 0; + + virtual bool GetBinary(std::vector &buf) const = 0; + virtual void Dump(int indent = 0, std::string outputFilename = "", FILE *outputDump = nullptr) const = 0; + virtual void DumpData(int indent) const = 0; + virtual void DumpLog(const std::string &prefix) const = 0; +}; + + +template +class PerfEventRecordTemplate : public PerfEventRecord { +public: + PerfEventRecordTemplate(const PerfEventRecordTemplate &) = delete; + PerfEventRecordTemplate &operator=(const PerfEventRecordTemplate &) = delete; + + struct perf_event_header header_ = {}; + DataType data_ = {}; + const char* GetNameP() const override final + { + return RECORD_TYPE_NAME; + } + + PerfEventRecordTemplate() = default; + void Init(uint8_t *data, const perf_event_attr& = {}) override; + + virtual ~PerfEventRecordTemplate() {} + + virtual size_t GetSize() const override + { + return header_.size; + }; + size_t GetHeaderSize() const override + { + return sizeof(header_); + }; + void GetHeaderBinary(std::vector &buf) const override; + + uint32_t GetType() const override + { + return header_.type; + }; + uint16_t GetMisc() const override + { + return header_.misc; + }; + bool InKernel() override + { + return header_.misc & PERF_RECORD_MISC_KERNEL; + } + bool InUser() override + { + return header_.misc & PERF_RECORD_MISC_USER; + } + + // to support --exclude-hiperf, return sample_id.pid to filter record, + virtual pid_t GetPid() const override { return 0; }; - 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 bool GetBinary(std::vector &buf) const override = 0; + void Dump(int indent = 0, std::string outputFilename = "", FILE *outputDump = nullptr) const override; + virtual void DumpData(int indent) const override = 0; + virtual void DumpLog(const std::string &prefix) const override; + +protected: + void Init(perf_event_type type, bool inKernel); + void Init(perf_event_hiperf_ext_type type); + +private: + const char* RECORD_TYPE_NAME = NAME; }; + +// PerfEventRecord +template +void PerfEventRecordTemplate::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_); +} + +template +void PerfEventRecordTemplate::Init(perf_event_hiperf_ext_type type) +{ + header_.type = type; + header_.misc = PERF_RECORD_MISC_USER; + header_.size = sizeof(header_); +} + +template +void PerfEventRecordTemplate::Init(uint8_t *p, const perf_event_attr&) +{ + if (p == nullptr) { + header_.type = PERF_RECORD_MMAP; + header_.misc = PERF_RECORD_MISC_USER; + header_.size = 0; + return; + } + header_ = *(reinterpret_cast(p)); +} + + +template +void PerfEventRecordTemplate::GetHeaderBinary(std::vector &buf) const +{ + if (buf.size() < GetHeaderSize()) { + buf.resize(GetHeaderSize()); + } + uint8_t *p = buf.data(); + *(reinterpret_cast(p)) = header_; +} + + +template +void PerfEventRecordTemplate::Dump(int indent, std::string outputFilename, FILE *outputDump) const +{ + if (outputDump != nullptr) { + g_outputDump = outputDump; + } else if (!outputFilename.empty() && g_outputDump == nullptr) { + std::string resolvedPath = CanonicalizeSpecPath(outputFilename.c_str()); + g_outputDump = fopen(resolvedPath.c_str(), "w"); + if (g_outputDump == nullptr) { + printf("unable open file to '%s' because '%d'\n", outputFilename.c_str(), errno); + return; + } + } + PRINT_INDENT(indent, "\n"); + PRINT_INDENT(indent, "record %s: type %u, misc %u, size %zu\n", GetNameP(), GetType(), + GetMisc(), GetSize()); + DumpData(indent + 1); +} + +template +void PerfEventRecordTemplate::DumpLog(const std::string &prefix) const +{ + HLOGV("%s: record %s: type %u, misc %u, size %zu\n", prefix.c_str(), GetNameP(), + GetType(), GetMisc(), GetSize()); +} + // define convert from linux/perf_event.h // description from https://man7.org/linux/man-pages/man2/perf_event_open.2.html @@ -171,11 +247,11 @@ 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; + void Init(uint8_t *data, const perf_event_attr&) override; PerfRecordAuxtrace(u64 size, u64 offset, u64 reference, u32 idx, u32 tid, u32 cpu, u32 pid); bool GetBinary1(std::vector &buf) const; @@ -183,15 +259,13 @@ public: void DumpData(int indent) const override; void DumpLog(const std::string &prefix) const override; - virtual size_t GetSize() const override; + size_t GetSize() const override; }; -class PerfRecordMmap : public PerfEventRecord { +class PerfRecordMmap : public PerfEventRecordTemplate { public: - PerfRecordMmapData data_; - - explicit PerfRecordMmap(uint8_t *p); - + PerfRecordMmap() = default; + void Init(uint8_t *data, const perf_event_attr&) override; PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff, const std::string &filename); @@ -200,16 +274,16 @@ 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; + void Init(uint8_t *data, const perf_event_attr&) override; 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); - PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, std::shared_ptr item); + PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, std::shared_ptr item); bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; @@ -217,30 +291,25 @@ public: bool discard_ = false; }; -class PerfRecordLost : public PerfEventRecord { +class PerfRecordLost : public PerfEventRecordTemplate { public: - PerfRecordLostData data_; - explicit PerfRecordLost(uint8_t *p); + PerfRecordLost() = default; + void Init(uint8_t *data, const perf_event_attr&) override; 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") - { - data_.id = id; - data_.lost = lost; - header.size = sizeof(header) + sizeof(data_); - } + PerfRecordLost(bool inKernel, u64 id, u64 lost); }; -class PerfRecordComm : public PerfEventRecord { +class PerfRecordComm : public PerfEventRecordTemplate { public: - PerfRecordCommData data_; - explicit PerfRecordComm(uint8_t *p); + PerfRecordComm() = default; + void Init(uint8_t *data, const perf_event_attr&) override; + PerfRecordComm(bool inKernel, u32 pid, u32 tid, const std::string &comm); @@ -249,24 +318,27 @@ 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; // extend // hold the new ips memory (after unwind) // used for data_.ips replace (ReplaceWithCallStack) - static std::vector ips_; - static std::vector callFrames_; - static std::vector serverPidMap_; + std::vector ips_; + std::vector callFrames_; + 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; @@ -275,60 +347,52 @@ public: // originalSize is use for expand callstack void ReplaceWithCallStack(size_t originalSize = 0); pid_t GetPid() const override; - void Clean(); // 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") - { - Clean(); - data_.pid = pid; - data_.tid = tid; - data_.period = period; - data_.time = time; - data_.id = 0; - header.size = sizeof(header) + sizeof(data_); - }; + PerfRecordSample(bool inKernel, u32 pid, u32 tid, u64 period = 0, u64 time = 0, u64 id = 0); 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; + void Init(uint8_t *data, const perf_event_attr&) override; + 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() = default; + void Init(uint8_t *data, const perf_event_attr&) override; - PerfRecordThrottle(uint8_t *p); bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; }; -class PerfRecordUnthrottle : public PerfEventRecord { +class PerfRecordUnthrottle : public PerfEventRecordTemplate { public: - PerfRecordThrottleData data_; + PerfRecordUnthrottle() = default; + void Init(uint8_t *data, const perf_event_attr&) override; - explicit PerfRecordUnthrottle(uint8_t *p); bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; }; -class PerfRecordFork : public PerfEventRecord { +class PerfRecordFork : public PerfEventRecordTemplate { public: - PerfRecordForkData data_; + PerfRecordFork() = default; + void Init(uint8_t *data, const perf_event_attr&) override; - explicit PerfRecordFork(uint8_t *p); bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; @@ -337,11 +401,11 @@ public: /* This record indicates a read event. */ -class PerfRecordRead : public PerfEventRecord { +class PerfRecordRead : public PerfEventRecordTemplate { public: - PerfRecordReadData data_; + PerfRecordRead() = default; + void Init(uint8_t *data, const perf_event_attr&) override; - explicit PerfRecordRead(uint8_t *p); bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; }; @@ -365,12 +429,12 @@ 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; + void Init(uint8_t *data, const perf_event_attr&) override; - explicit PerfRecordAux(uint8_t *p); bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; }; @@ -386,11 +450,11 @@ public: tid thread ID of the thread starting an instruction trace. */ -class PerfRecordItraceStart : public PerfEventRecord { +class PerfRecordItraceStart : public PerfEventRecordTemplate { public: - PerfRecordItraceStartData data_; + PerfRecordItraceStart() = default; + void Init(uint8_t *data, const perf_event_attr&) override; - explicit PerfRecordItraceStart(uint8_t *p); bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; }; @@ -400,11 +464,11 @@ 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; + void Init(uint8_t *data, const perf_event_attr&) override; - explicit PerfRecordLostSamples(uint8_t *p); bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; }; @@ -415,10 +479,11 @@ 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; + void Init(uint8_t *data, const perf_event_attr&) override; + bool GetBinary(std::vector &buf) const override; void DumpData([[maybe_unused]] int indent) const override {}; }; @@ -441,20 +506,22 @@ 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; + void Init(uint8_t *data, const perf_event_attr&) override; + bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; }; -std::unique_ptr GetPerfEventRecord(const int type, uint8_t *p, +class PerfEventRecordFactory { +public: + static PerfEventRecord& GetPerfEventRecord(PerfRecordType 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); +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 ebcdbe4..f027c94 100644 --- a/include/perf_file_writer.h +++ b/include/perf_file_writer.h @@ -61,7 +61,7 @@ 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); diff --git a/include/subcommand_dump.h b/include/subcommand_dump.h index 176bb14..cb4e7b2 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, 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..e2ba4ef 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(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/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/src/perf_event_record.cpp b/src/perf_event_record.cpp index 6322c3f..a72950b 100644 --- a/src/perf_event_record.cpp +++ b/src/perf_event_record.cpp @@ -20,99 +20,72 @@ #include "utilities.h" -using namespace OHOS::HiviewDFX; -using namespace std; +// 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) +#define INIT_PERF_RECORD_DATA(PerfRecordType) \ +void PerfRecordType::Init(uint8_t* data, const perf_event_attr&) \ +{ \ + PerfEventRecordTemplate::Init(data); \ + size_t dataSize = GetSize(); \ + if (dataSize >= sizeof(header_)) { \ + size_t copySize = dataSize - sizeof(header_); \ + if (memcpy_s(reinterpret_cast(&data_), sizeof(data_), data + sizeof(header_), copySize) != 0) { \ + HLOGE("##PerfRecordType## memcpy_s return failed!"); \ + } \ + } else { \ + HLOGE("##PerfRecordType## return failed!"); \ + } \ +} \ + + +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; } } -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) @@ -154,87 +127,14 @@ 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) -{ - header.type = type; - header.misc = inKernel ? PERF_RECORD_MISC_KERNEL : 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) -{ - if (p == nullptr) { - header.type = PERF_RECORD_MMAP; - header.misc = PERF_RECORD_MISC_USER; - header.size = 0; - return; - } - header = *(reinterpret_cast(p)); -} +INIT_PERF_RECORD_DATA(PerfRecordAuxtrace) -void PerfEventRecord::GetHeaderBinary(std::vector &buf) const -{ - if (buf.size() < GetHeaderSize()) { - buf.resize(GetHeaderSize()); - } - uint8_t *p = buf.data(); - *(reinterpret_cast(p)) = header; -} - -void PerfEventRecord::Dump(int indent, std::string outputFilename, FILE *outputDump) const -{ - if (outputDump != nullptr) { - g_outputDump = outputDump; - } else if (!outputFilename.empty() && g_outputDump == nullptr) { - std::string resolvedPath = CanonicalizeSpecPath(outputFilename.c_str()); - g_outputDump = fopen(resolvedPath.c_str(), "w"); - if (g_outputDump == nullptr) { - printf("unable open file to '%s' because '%d'\n", outputFilename.c_str(), errno); - return; - } - } - PRINT_INDENT(indent, "\n"); - PRINT_INDENT(indent, "record %s: type %u, misc %u, size %zu\n", GetName().c_str(), 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(), - GetType(), GetMisc(), GetSize()); -} - -std::vector PerfRecordSample::ips_ = {}; -std::vector PerfRecordSample::callFrames_ = {}; -std::vector PerfRecordSample::serverPidMap_ = {}; - -PerfRecordAuxtrace::PerfRecordAuxtrace(uint8_t *p) : PerfEventRecord(p, "auxtrace") -{ - 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; -} PerfRecordAuxtrace::PerfRecordAuxtrace(u64 size, u64 offset, u64 reference, u32 idx, u32 tid, u32 cpu, u32 pid) - : PerfEventRecord(PERF_RECORD_AUXTRACE, "auxtrace") { + PerfEventRecordTemplate::Init(PERF_RECORD_AUXTRACE); data_.size = size; data_.offset = offset; data_.reference = reference; @@ -243,19 +143,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 +172,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,104 +204,258 @@ 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 + +INIT_PERF_RECORD_DATA(PerfRecordMmap) + +PerfRecordMmap::PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff, + const std::string &filename) { - 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, - data_.reg_nr, data_.dyn_size, data_.time); + PerfEventRecordTemplate::Init(PERF_RECORD_MMAP, inKernel); + + data_.pid = pid; + data_.tid = tid; + data_.addr = addr; + data_.len = len; + data_.pgoff = pgoff; + if (strncpy_s(data_.filename, KILO, filename.c_str(), filename.size()) != 0) { + HLOGE("strncpy_s failed"); + } + + header_.size = sizeof(header_) + sizeof(data_) - KILO + filename.size() + 1; } -void PerfRecordSample::RecoverCallStack() +bool PerfRecordMmap::GetBinary(std::vector &buf) const { - data_.ips = ips_.data(); - data_.nr = ips_.size(); - removeStack_ = true; + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + // data_.filename[] is variable-length + std::copy(reinterpret_cast(&data_), + reinterpret_cast(&data_) + GetSize() - GetHeaderSize(), p); + return true; } -void PerfRecordSample::ReplaceWithCallStack(size_t originalSize) +void PerfRecordMmap::DumpData(int indent) const { - // 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) + 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 DfxFrame &frame) { - ips_.emplace_back(frame.pc); - 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) { - HLOGV("combed %zu", callFrames_.size()); - } else { - HLOGV("failed to combed %zu", callFrames_.size()); +#if defined(is_ohos) && is_ohos + if (IsRoot()) { + PRINT_INDENT(indent, "pid %u, tid %u, addr 0x%llx, len 0x%llx\n", data_.pid, data_.tid, + data_.addr, data_.len); + PRINT_INDENT(indent, "pgoff 0x%llx, filename %s\n", data_.pgoff, data_.filename); + } +#endif +} + +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); +} + + +INIT_PERF_RECORD_DATA(PerfRecordMmap2) + + + +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) +{ + PerfEventRecordTemplate::Init(PERF_RECORD_MMAP2, inKernel); + data_.pid = pid; + data_.tid = tid; + data_.addr = addr; + data_.len = len; + data_.pgoff = pgoff; + data_.maj = maj; + data_.min = min; + data_.ino = ino; + data_.ino_generation = 0; + data_.prot = prot; + data_.flags = flags; + if (strncpy_s(data_.filename, KILO, filename.c_str(), filename.size()) != 0) { + HLOGE("strncpy_s failed"); + } + + header_.size = sizeof(header_) + sizeof(data_) - KILO + filename.size() + 1; +} + +PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, std::shared_ptr item) +{ + PerfEventRecordTemplate::Init(PERF_RECORD_MMAP2, inKernel); + data_.pid = pid; + data_.tid = tid; + if (item != nullptr) { + data_.addr = item->begin; + data_.len = item->end - item->begin; + data_.pgoff = item->offset; + data_.maj = item->major; + data_.min = item->minor; + data_.ino = item->inode; + data_.ino_generation = 0; + // r--p 00000000 103:3e 12307 /data/storage/el1/bundle/entry.hap + // why prot get from this is 7. rwxp + HiviewDFX::DfxMap::PermsToProts(item->perms, data_.prot, data_.flags); + if (strncpy_s(data_.filename, KILO, item->name.c_str(), item->name.size()) != 0) { + HLOGE("strncpy_s failed"); } - if (sampleType_ & PERF_SAMPLE_REGS_USER) { - 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); - - // 2. clean the size - data_.stack_size = 0; - data_.dyn_size = 0; - } - - if (sampleType_ & PERF_SAMPLE_CALLCHAIN) { - HLOGV("ips change from %llu -> %zu", data_.nr, ips_.size()); - - // 3. remove the nr size - header.size -= data_.nr * sizeof(u64); - - // 4. add new nr size - data_.nr = ips_.size(); - header.size += data_.nr * sizeof(u64); - - // 5. change ips potin to our ips array and hold it. - data_.ips = ips_.data(); - } + header_.size = sizeof(header_) + sizeof(data_) - KILO + item->name.size() + 1; } else { - // nothing need change - return; + data_.addr = 0; + data_.len = 0; + data_.pgoff = 0; + data_.maj = 0; + data_.min = 0; + data_.ino = 0; + data_.ino_generation = 0; + if (memset_s(data_.filename, KILO, 0, KILO) != EOK) { + HLOGE("memset_s failed"); + } } } -PerfRecordSample::PerfRecordSample(uint8_t *p, const perf_event_attr &attr) - : PerfEventRecord(p, "sample") +bool PerfRecordMmap2::GetBinary(std::vector &buf) const { - if (p == nullptr) { - HLOG_ASSERT(p); - return; + if (buf.size() < GetSize()) { + buf.resize(GetSize()); } - // clear the static vector data - Clean(); + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + // data_.filename[] is variable-length + std::copy(reinterpret_cast(&data_), + reinterpret_cast(&data_) + GetSize() - GetHeaderSize(), p); + return true; +} + +void PerfRecordMmap2::DumpData(int indent) const +{ +#if defined(is_ohos) && is_ohos + if (IsRoot()) { + PRINT_INDENT(indent, "pid %u, tid %u, addr 0x%llx, len 0x%llx\n", data_.pid, data_.tid, + data_.addr, data_.len); + PRINT_INDENT(indent, "pgoff 0x%llx, maj %u, min %u, ino %llu, ino_generation %llu\n", + data_.pgoff, data_.maj, data_.min, data_.ino, data_.ino_generation); + PRINT_INDENT(indent, "prot %u, flags %u, filename %s\n", data_.prot, data_.flags, + data_.filename); + } +#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, + data_.pgoff); +} + +INIT_PERF_RECORD_DATA(PerfRecordLost) + +bool PerfRecordLost::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + auto pDest = reinterpret_cast(p); + *pDest = data_; + + return true; +} + +void PerfRecordLost::DumpData(int indent) const +{ + PRINT_INDENT(indent, "id %llu, lost %llu\n", data_.id, data_.lost); +} + +PerfRecordLost::PerfRecordLost(bool inKernel, u64 id, u64 lost) +{ + PerfEventRecordTemplate::Init(PERF_RECORD_LOST, inKernel); + data_.id = id; + data_.lost = lost; + header_.size = sizeof(header_) + sizeof(data_); +} + + + +INIT_PERF_RECORD_DATA(PerfRecordComm) + +PerfRecordComm::PerfRecordComm(bool inKernel, u32 pid, u32 tid, const std::string &comm) +{ + + PerfEventRecordTemplate::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; +} + +bool PerfRecordComm::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + // data_.comm[] is variable-length + std::copy(reinterpret_cast(&data_), + reinterpret_cast(&data_) + GetSize() - GetHeaderSize(), p); + + return true; +} + +void PerfRecordComm::DumpData(int indent) const +{ + PRINT_INDENT(indent, "pid %u, tid %u, comm %s\n", data_.pid, data_.tid, data_.comm); +} + +void PerfRecordComm::DumpLog(const std::string &prefix) const +{ + HLOGV("pid %u, tid %u, comm %s\n", data_.pid, data_.tid, data_.comm); +} + +PerfRecordSample::PerfRecordSample(const PerfRecordSample& sample) +{ + 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::Init(uint8_t *p, const perf_event_attr &attr) +{ + PerfEventRecordTemplate::Init(p); + + HLOG_ASSERT(p == nullptr); sampleType_ = attr.sample_type; - 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,12 +502,24 @@ 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); } } + +void PerfRecordSample::SetDumpRemoveStack(bool dumpRemoveStack) +{ + dumpRemoveStack_ = dumpRemoveStack; +} + +bool PerfRecordSample::IsDumpRemoveStack() +{ + return dumpRemoveStack_; +} + + bool PerfRecordSample::GetBinary(std::vector &buf) const { if (buf.size() < GetSize()) { @@ -593,599 +659,102 @@ void PerfRecordSample::DumpData(int indent) const } } +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, + data_.reg_nr, data_.dyn_size, data_.time); +} + +void PerfRecordSample::RecoverCallStack() +{ + data_.ips = ips_.data(); + data_.nr = ips_.size(); + removeStack_ = true; +} + +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) + 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 HiviewDFX::DfxFrame &frame) { + ips_.emplace_back(frame.pc); + 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) { + HLOGV("combed %zu", callFrames_.size()); + } else { + HLOGV("failed to combed %zu", callFrames_.size()); + } + + if (sampleType_ & PERF_SAMPLE_REGS_USER) { + 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); + + // 2. clean the size + data_.stack_size = 0; + data_.dyn_size = 0; + } + + if (sampleType_ & PERF_SAMPLE_CALLCHAIN) { + HLOGV("ips change from %llu -> %zu", data_.nr, ips_.size()); + + // 3. remove the nr size + header_.size -= data_.nr * sizeof(u64); + + // 4. add new nr size + data_.nr = ips_.size(); + header_.size += data_.nr * sizeof(u64); + + // 5. change ips potin to our ips array and hold it. + data_.ips = ips_.data(); + } + } else { + // nothing need change + return; + } +} + inline pid_t PerfRecordSample::GetPid() const { return data_.pid; } -void PerfRecordSample::Clean() -{ - ips_.clear(); - callFrames_.clear(); - 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") +PerfRecordSample::PerfRecordSample(bool inKernel, u32 pid, u32 tid, u64 period, u64 time, u64 id) { + PerfEventRecordTemplate::Init(PERF_RECORD_SAMPLE, inKernel); data_.pid = pid; data_.tid = tid; - data_.addr = addr; - data_.len = len; - data_.pgoff = pgoff; - if (strncpy_s(data_.filename, KILO, filename.c_str(), filename.size()) != 0) { - HLOGE("strncpy_s failed"); - } - - header.size = sizeof(header) + sizeof(data_) - KILO + filename.size() + 1; -} - -bool PerfRecordMmap::GetBinary(std::vector &buf) const -{ - if (buf.size() < GetSize()) { - buf.resize(GetSize()); - } - - GetHeaderBinary(buf); - uint8_t *p = buf.data() + GetHeaderSize(); - - // data_.filename[] is variable-length - std::copy(reinterpret_cast(&data_), - reinterpret_cast(&data_) + GetSize() - GetHeaderSize(), p); - return true; -} - -void PerfRecordMmap::DumpData(int indent) const -{ -#if defined(is_ohos) && is_ohos - if (IsRoot()) { - PRINT_INDENT(indent, "pid %u, tid %u, addr 0x%llx, len 0x%llx\n", data_.pid, data_.tid, - data_.addr, data_.len); - PRINT_INDENT(indent, "pgoff 0x%llx, filename %s\n", data_.pgoff, data_.filename); - } -#endif -} - -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 !!!"); - } -} - -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") -{ - data_.pid = pid; - data_.tid = tid; - data_.addr = addr; - data_.len = len; - data_.pgoff = pgoff; - data_.maj = maj; - data_.min = min; - data_.ino = ino; - data_.ino_generation = 0; - data_.prot = prot; - data_.flags = flags; - if (strncpy_s(data_.filename, KILO, filename.c_str(), filename.size()) != 0) { - HLOGE("strncpy_s failed"); - } - - 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") -{ - data_.pid = pid; - data_.tid = tid; - if (item != nullptr) { - data_.addr = item->begin; - data_.len = item->end - item->begin; - data_.pgoff = item->offset; - data_.maj = item->major; - data_.min = item->minor; - data_.ino = item->inode; - data_.ino_generation = 0; - // r--p 00000000 103:3e 12307 /data/storage/el1/bundle/entry.hap - // why prot get from this is 7. rwxp - DfxMap::PermsToProts(item->perms, data_.prot, data_.flags); - if (strncpy_s(data_.filename, KILO, item->name.c_str(), item->name.size()) != 0) { - HLOGE("strncpy_s failed"); - } - - header.size = sizeof(header) + sizeof(data_) - KILO + item->name.size() + 1; - } else { - data_.addr = 0; - data_.len = 0; - data_.pgoff = 0; - data_.maj = 0; - data_.min = 0; - data_.ino = 0; - data_.ino_generation = 0; - if (memset_s(data_.filename, KILO, 0, KILO) != EOK) { - HLOGE("memset_s failed"); - } - } -} - -bool PerfRecordMmap2::GetBinary(std::vector &buf) const -{ - if (buf.size() < GetSize()) { - buf.resize(GetSize()); - } - - GetHeaderBinary(buf); - uint8_t *p = buf.data() + GetHeaderSize(); - - // data_.filename[] is variable-length - std::copy(reinterpret_cast(&data_), - reinterpret_cast(&data_) + GetSize() - GetHeaderSize(), p); - return true; -} - -void PerfRecordMmap2::DumpData(int indent) const -{ -#if defined(is_ohos) && is_ohos - if (IsRoot()) { - PRINT_INDENT(indent, "pid %u, tid %u, addr 0x%llx, len 0x%llx\n", data_.pid, data_.tid, - data_.addr, data_.len); - PRINT_INDENT(indent, "pgoff 0x%llx, maj %u, min %u, ino %llu, ino_generation %llu\n", - data_.pgoff, data_.maj, data_.min, data_.ino, data_.ino_generation); - PRINT_INDENT(indent, "prot %u, flags %u, filename %s\n", data_.prot, data_.flags, - data_.filename); - } -#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, - 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()) { - buf.resize(GetSize()); - } - - GetHeaderBinary(buf); - uint8_t *p = buf.data() + GetHeaderSize(); - - auto pDest = reinterpret_cast(p); - *pDest = data_; - - return true; -} - -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") -{ - 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; -} - -bool PerfRecordComm::GetBinary(std::vector &buf) const -{ - if (buf.size() < GetSize()) { - buf.resize(GetSize()); - } - - GetHeaderBinary(buf); - uint8_t *p = buf.data() + GetHeaderSize(); - - // data_.comm[] is variable-length - std::copy(reinterpret_cast(&data_), - reinterpret_cast(&data_) + GetSize() - GetHeaderSize(), p); - - return true; -} - -void PerfRecordComm::DumpData(int indent) const -{ - PRINT_INDENT(indent, "pid %u, tid %u, comm %s\n", data_.pid, data_.tid, data_.comm); -} - -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") -{ - 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 !!!"); - } -} - -bool PerfRecordExit::GetBinary(std::vector &buf) const -{ - if (buf.size() < GetSize()) { - buf.resize(GetSize()); - } - - GetHeaderBinary(buf); - uint8_t *p = buf.data() + GetHeaderSize(); - - auto pDest = reinterpret_cast(p); - *pDest = data_; - return true; -} - -void PerfRecordExit::DumpData(int indent) const -{ - PRINT_INDENT(indent, "pid %u, ppid %u, tid %u, ptid %u time 0x%llx\n", data_.pid, data_.ppid, - 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()) { - buf.resize(GetSize()); - } - - GetHeaderBinary(buf); - uint8_t *p = buf.data() + GetHeaderSize(); - - auto pDest = reinterpret_cast(p); - *pDest = data_; - return true; -} - -void PerfRecordThrottle::DumpData(int indent) const -{ - PRINT_INDENT(indent, "time 0x%llx, id %llx, stream_id %llx\n", data_.time, data_.id, - 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()) { - buf.resize(GetSize()); - } - - GetHeaderBinary(buf); - uint8_t *p = buf.data() + GetHeaderSize(); - - auto pDest = reinterpret_cast(p); - *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()) { - buf.resize(GetSize()); - } - - GetHeaderBinary(buf); - uint8_t *p = buf.data() + GetHeaderSize(); - - auto pDest = reinterpret_cast(p); - *pDest = data_; - return true; -} - -void PerfRecordFork::DumpData(int indent) const -{ - PRINT_INDENT(indent, "pid %u, ppid %u, tid %u, ptid %u\n", data_.pid, data_.ppid, data_.tid, - 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()) { - buf.resize(GetSize()); - } - - GetHeaderBinary(buf); - uint8_t *p = buf.data() + GetHeaderSize(); - - auto pDest = reinterpret_cast(p); - *pDest = data_; - return true; -} - -void PerfRecordRead::DumpData(int indent) const -{ - PRINT_INDENT(indent, "pid %u, tid %u\n", data_.pid, data_.tid); - PRINT_INDENT(indent, "values: value %llx, timeEnabled %llx, timeRunning %llx, id %llx\n", - 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()) { - buf.resize(GetSize()); - } - - GetHeaderBinary(buf); - uint8_t *p = buf.data() + GetHeaderSize(); - - PushToBinary(true, p, data_.aux_offset); - PushToBinary(true, p, data_.aux_size); - PushToBinary(true, p, data_.flags); - PushToBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.sample_id.pid, data_.sample_id.tid); - PushToBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.sample_id.time); - PushToBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.sample_id.id); - PushToBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.sample_id.stream_id); - - PushToBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.sample_id.cpu, data_.sample_id.res); - PushToBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id.id2); - return true; -} - -void PerfRecordAux::DumpData(int indent) const -{ - PRINT_INDENT(indent, "aux_offset 0x%llx aux_size 0x%llx flags 0x%llx pid %u tid %u time %llu", - data_.aux_offset, data_.aux_size, data_.flags, data_.sample_id.pid, data_.sample_id.tid, - 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()) { - buf.resize(GetSize()); - } - - GetHeaderBinary(buf); - uint8_t *p = buf.data() + GetHeaderSize(); - - auto pDest = reinterpret_cast(p); - *pDest = data_; - return true; -} - -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()) { - buf.resize(GetSize()); - } - - GetHeaderBinary(buf); - uint8_t *p = buf.data() + GetHeaderSize(); - - auto pDest = reinterpret_cast(p); - *pDest = data_; - return true; -} - -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()) { - buf.resize(GetSize()); - } - - GetHeaderBinary(buf); - uint8_t *p = buf.data() + GetHeaderSize(); - - auto pDest = reinterpret_cast(p); - *pDest = data_; - 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()) { - buf.resize(GetSize()); - } - - GetHeaderBinary(buf); - uint8_t *p = buf.data() + GetHeaderSize(); - - auto pDest = reinterpret_cast(p); - *pDest = data_; - return true; -} - -void PerfRecordSwitchCpuWide::DumpData(int indent) const -{ - PRINT_INDENT(indent, "next_prev_pid %u, next_prev_tid %u\n", data_.next_prev_pid, - data_.next_prev_tid); -} + data_.period = period; + data_.time = time; + data_.id = 0; + header_.size = sizeof(header_) + sizeof(data_); +}; pid_t PerfRecordSample::GetUstackServerPid() { @@ -1246,6 +815,271 @@ pid_t PerfRecordSample::GetServerPidof(unsigned int ipNr) return serverPidMap_[ipNr]; } } + + + + + +INIT_PERF_RECORD_DATA(PerfRecordExit) + +bool PerfRecordExit::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + auto pDest = reinterpret_cast(p); + *pDest = data_; + return true; +} + +void PerfRecordExit::DumpData(int indent) const +{ + PRINT_INDENT(indent, "pid %u, ppid %u, tid %u, ptid %u time 0x%llx\n", data_.pid, data_.ppid, + data_.tid, data_.ptid, data_.time); +} + + + +INIT_PERF_RECORD_DATA(PerfRecordThrottle) + + +bool PerfRecordThrottle::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + auto pDest = reinterpret_cast(p); + *pDest = data_; + return true; +} + +void PerfRecordThrottle::DumpData(int indent) const +{ + PRINT_INDENT(indent, "time 0x%llx, id %llx, stream_id %llx\n", data_.time, data_.id, + data_.stream_id); +} + + + +INIT_PERF_RECORD_DATA(PerfRecordUnthrottle) + +bool PerfRecordUnthrottle::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + auto pDest = reinterpret_cast(p); + *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); +} + + +INIT_PERF_RECORD_DATA(PerfRecordFork) + +bool PerfRecordFork::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + auto pDest = reinterpret_cast(p); + *pDest = data_; + return true; +} + +void PerfRecordFork::DumpData(int indent) const +{ + PRINT_INDENT(indent, "pid %u, ppid %u, tid %u, ptid %u\n", data_.pid, data_.ppid, data_.tid, + data_.ptid); +} + + + +INIT_PERF_RECORD_DATA(PerfRecordRead) + +bool PerfRecordRead::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + auto pDest = reinterpret_cast(p); + *pDest = data_; + return true; +} + +void PerfRecordRead::DumpData(int indent) const +{ + PRINT_INDENT(indent, "pid %u, tid %u\n", data_.pid, data_.tid); + PRINT_INDENT(indent, "values: value %llx, timeEnabled %llx, timeRunning %llx, id %llx\n", + data_.values.value, data_.values.timeEnabled, data_.values.timeRunning, data_.values.id); +} + + + +INIT_PERF_RECORD_DATA(PerfRecordAux) + +bool PerfRecordAux::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + PushToBinary(true, p, data_.aux_offset); + PushToBinary(true, p, data_.aux_size); + PushToBinary(true, p, data_.flags); + PushToBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.sample_id.pid, data_.sample_id.tid); + PushToBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.sample_id.time); + PushToBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.sample_id.id); + PushToBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.sample_id.stream_id); + + PushToBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.sample_id.cpu, data_.sample_id.res); + PushToBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id.id2); + return true; +} + +void PerfRecordAux::DumpData(int indent) const +{ + PRINT_INDENT(indent, "aux_offset 0x%llx aux_size 0x%llx flags 0x%llx pid %u tid %u time %llu", + data_.aux_offset, data_.aux_size, data_.flags, data_.sample_id.pid, data_.sample_id.tid, + data_.sample_id.time); +} + + + + + +INIT_PERF_RECORD_DATA(PerfRecordItraceStart) + +bool PerfRecordItraceStart::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + auto pDest = reinterpret_cast(p); + *pDest = data_; + return true; +} + +void PerfRecordItraceStart::DumpData(int indent) const +{ + PRINT_INDENT(indent, "pid %u, tid %u\n", data_.pid, data_.tid); +} + + + +INIT_PERF_RECORD_DATA(PerfRecordLostSamples) + +bool PerfRecordLostSamples::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + auto pDest = reinterpret_cast(p); + *pDest = data_; + return true; +} + +void PerfRecordLostSamples::DumpData(int indent) const +{ + PRINT_INDENT(indent, "lost %llu\n", data_.lost); +} + + + +INIT_PERF_RECORD_DATA(PerfRecordSwitch) + +bool PerfRecordSwitch::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + auto pDest = reinterpret_cast(p); + *pDest = data_; + return true; +} + + +INIT_PERF_RECORD_DATA(PerfRecordSwitchCpuWide) + +bool PerfRecordSwitchCpuWide::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + auto pDest = reinterpret_cast(p); + *pDest = data_; + return true; +} + +void PerfRecordSwitchCpuWide::DumpData(int indent) const +{ + PRINT_INDENT(indent, "next_prev_pid %u, next_prev_tid %u\n", data_.next_prev_pid, + data_.next_prev_tid); +} + +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..421a7de 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_; @@ -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_reader.cpp b/src/perf_file_reader.cpp index c051b20..180c282 100644 --- a/src/perf_file_reader.cpp +++ b/src/perf_file_reader.cpp @@ -276,20 +276,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.GetNameP() == 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_ += @@ -423,7 +423,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 4fa75a9..a586b1e 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.GetNameP(), 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.GetNameP()); // 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), + PerfEventRecord& record = PerfEventRecordFactory::GetPerfEventRecord(static_cast(header->type), data, defaultEventAttr_); // skip unknown record - CHECK_TRUE(record == nullptr, true, 0, ""); + CHECK_TRUE(record.GetNameP() == 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 { diff --git a/src/subcommand_dump.cpp b/src/subcommand_dump.cpp index 10f30bd..f2b0a31 100644 --- a/src/subcommand_dump.cpp +++ b/src/subcommand_dump.cpp @@ -401,13 +401,13 @@ void SubCommandDump::ExprotUserStack(const PerfRecordSample &recordSample) } } -void SubCommandDump::ExprotUserData(std::unique_ptr &record) +void SubCommandDump::ExprotUserData(PerfEventRecord& record) { - if (record->GetType() == PERF_RECORD_SAMPLE) { + if (record.GetType() == PERF_RECORD_SAMPLE) { if (currectSampleIndex_++ != exportSampleIndex_) { return; } - PerfRecordSample *recordSample = static_cast(record.get()); + PerfRecordSample* recordSample = static_cast(&record); ExprotUserStack(*recordSample); std::string userData = @@ -423,14 +423,14 @@ void SubCommandDump::ExprotUserData(std::unique_ptr &record) } } -void SubCommandDump::DumpCallChain(int indent, std::unique_ptr &sample) +void SubCommandDump::DumpCallChain(int indent, PerfRecordSample& sample) { - PRINT_INDENT(indent, "\n callchain: %zu\n", sample->callFrames_.size()); - if (sample->callFrames_.size() > 0) { + PRINT_INDENT(indent, "\n callchain: %zu\n", sample.callFrames_.size()); + if (sample.callFrames_.size() > 0) { indent += indent + 1; - for (auto frameIt = sample->callFrames_.begin(); frameIt != sample->callFrames_.end(); + for (auto frameIt = sample.callFrames_.begin(); frameIt != sample.callFrames_.end(); frameIt++) { - PRINT_INDENT(indent, "%02zd:%s\n", std::distance(frameIt, sample->callFrames_.end()), + PRINT_INDENT(indent, "%02zd:%s\n", std::distance(frameIt, sample.callFrames_.end()), frameIt->ToSymbolString().c_str()); } } @@ -439,8 +439,8 @@ void SubCommandDump::DumpCallChain(int indent, std::unique_ptr void SubCommandDump::DumpDataPortion(int indent) { int recordCount = 0; - auto recordcCallback = [&](std::unique_ptr record) { - CHECK_TRUE(record == nullptr, false, 0, ""); // return false in callback can stop the read process + auto recordcCallback = [&](PerfEventRecord& record) { + CHECK_TRUE(record.GetNameP() == nullptr, false, 0, ""); // return false in callback can stop the read process // for UT if (exportSampleIndex_ > 0) { @@ -448,15 +448,13 @@ void SubCommandDump::DumpDataPortion(int indent) } // tell process tree what happend for rebuild symbols - vr_.UpdateFromRecord(*record); + vr_.UpdateFromRecord(record); recordCount++; - record->Dump(indent, outputFilename_, g_outputDump); + record.Dump(indent, outputFilename_, g_outputDump); - if (record->GetType() == PERF_RECORD_SAMPLE) { - std::unique_ptr sample( - static_cast(record.release())); - DumpCallChain(indent, sample); + if (record.GetType() == PERF_RECORD_SAMPLE) { + DumpCallChain(indent, static_cast(record)); } return true; diff --git a/src/subcommand_record.cpp b/src/subcommand_record.cpp index 70222ed..41f265e 100644 --- a/src/subcommand_record.cpp +++ b/src/subcommand_record.cpp @@ -811,8 +811,8 @@ void SubCommandRecord::RecoverSavedCmdlinesSize() bool SubCommandRecord::PreparePerfEvent() { // we need to notify perfEvents_ sampling mode by SetRecordCallBack first - auto processRecord = [this](std::unique_ptr record) -> bool { - return this->ProcessRecord(std::move(record)); + auto processRecord = [this](PerfEventRecord& record) -> bool { + return this->ProcessRecord(record); }; perfEvents_.SetRecordCallBack(processRecord); @@ -897,8 +897,8 @@ bool SubCommandRecord::PrepareSysKernel() bool SubCommandRecord::PrepareVirtualRuntime() { - auto saveRecord = [this](std::unique_ptr record) -> bool { - return this->SaveRecord(std::move(record), false); + auto saveRecord = [this](PerfEventRecord& record) -> bool { + return this->SaveRecord(record, false); }; virtualRuntime_.SetRecordMode(saveRecord); @@ -1323,21 +1323,17 @@ void SubCommandRecord::RemoveVdsoTmpFile() } } -bool SubCommandRecord::ProcessRecord(std::unique_ptr record) +bool SubCommandRecord::ProcessRecord(PerfEventRecord& record) { - CHECK_TRUE(record == nullptr, false, 1, "record is null"); + CHECK_TRUE(record.GetNameP() == nullptr, false, 1, "record is null"); #if HIDEBUG_RECORD_NOT_PROCESS // some times we want to check performance // but we still want to see the record number - if (record->GetType() == PERF_RECORD_SAMPLE) { + if (record.GetType() == PERF_RECORD_SAMPLE) { recordSamples_++; } else { recordNoSamples_++; } - if (record->GetType() == PERF_RECORD_SAMPLE) { - // when the record is allowed from a cache memory, does not free memory after use - record.release(); - } return true; #else #ifdef HIPERF_DEBUG_TIME @@ -1345,11 +1341,7 @@ bool SubCommandRecord::ProcessRecord(std::unique_ptr record) #endif if (excludeHiperf_) { static pid_t pid = getpid(); - if (record->GetPid() == pid) { - if (record->GetType() == PERF_RECORD_SAMPLE) { - // when the record is allowed from a cache memory, does not free memory after use - record.release(); - } + if (record.GetPid() == pid) { // discard record return true; } @@ -1358,23 +1350,17 @@ bool SubCommandRecord::ProcessRecord(std::unique_ptr record) // May create some simulated events // it will call ProcessRecord before next line #if !HIDEBUG_RECORD_NOT_PROCESS_VM - virtualRuntime_.UpdateFromRecord(*record); + virtualRuntime_.UpdateFromRecord(record); #endif #ifdef HIPERF_DEBUG_TIME prcessRecordTimes_ += duration_cast(steady_clock::now() - startTime); #endif - return SaveRecord(std::move(record), true); + return SaveRecord(record, true); #endif } -bool SubCommandRecord::SaveRecord(std::unique_ptr record, bool ptrReleaseFlag) +bool SubCommandRecord::SaveRecord(PerfEventRecord& record, bool ptrReleaseFlag) { - ON_SCOPE_EXIT { - if (ptrReleaseFlag && record->GetType() == PERF_RECORD_SAMPLE) { - // when the record is allowed from a cache memory, does not free memory after use - record.release(); - } - }; #if HIDEBUG_RECORD_NOT_SAVE return true; #endif @@ -1389,22 +1375,22 @@ bool SubCommandRecord::SaveRecord(std::unique_ptr record, bool } } - if (record) { + if (record.GetNameP() == nullptr) { #ifdef HIPERF_DEBUG_TIME const auto saveTime = steady_clock::now(); #endif - if (!fileWriter_->WriteRecord(*record)) { + if (!fileWriter_->WriteRecord(record)) { // write file failed, need stop record perfEvents_.StopTracking(); - HLOGV("fail to write record %s", record->GetName().c_str()); + HLOGV("fail to write record %s", record.GetNameP()); return false; } - if (record->GetType() == PERF_RECORD_SAMPLE) { + if (record.GetType() == PERF_RECORD_SAMPLE) { recordSamples_++; } else { recordNoSamples_++; } - HLOGV(" write done. size=%zu name=%s", record->GetSize(), record->GetName().c_str()); + HLOGV(" write done. size=%zu name=%s", record.GetSize(), record.GetNameP()); #ifdef HIPERF_DEBUG_TIME saveRecordTimes_ += duration_cast(steady_clock::now() - saveTime); #endif @@ -1620,15 +1606,15 @@ bool SubCommandRecord::PostProcessRecordFile() } // 2. read out the file and unwind - auto record_callback = [&](std::unique_ptr record) { - if (record == nullptr) { + auto record_callback = [&](PerfEventRecord& record) { + if (record.GetNameP() == nullptr) { // return false in callback can stop the read process return false; - } else if (record->GetType() == PERF_RECORD_SAMPLE) { + } else if (record.GetType() == PERF_RECORD_SAMPLE) { HLOGM("readback record for unwind"); - virtualRuntime_.UnwindFromRecord(static_cast(*record)); + virtualRuntime_.UnwindFromRecord(static_cast(record)); } - SaveRecord(std::move(record)); + SaveRecord(record); return true; }; fileReader->ReadDataSection(record_callback); @@ -1669,22 +1655,20 @@ void SubCommandRecord::SymbolicHits() } #endif -bool SubCommandRecord::CollectionSymbol(std::unique_ptr record) +bool SubCommandRecord::CollectionSymbol(PerfEventRecord& record) { - CHECK_TRUE(record == nullptr, false, 0, ""); - if (record->GetType() == PERF_RECORD_SAMPLE) { - PerfRecordSample *sample = static_cast(record.get()); + CHECK_TRUE(record.GetNameP() == nullptr, false, 0, ""); + if (record.GetType() == PERF_RECORD_SAMPLE) { + PerfRecordSample* sample = static_cast(&record); #if USE_COLLECT_SYMBOLIC CollectSymbol(sample); #else virtualRuntime_.SymbolicRecord(*sample); #endif - // the record is allowed from a cache memory, does not free memory after use - record.release(); } - if (isSpe_ && record->GetType() == PERF_RECORD_AUXTRACE) { - PerfRecordAuxtrace *sample = static_cast(record.get()); + if (isSpe_ && record.GetType() == PERF_RECORD_AUXTRACE) { + PerfRecordAuxtrace* sample = static_cast(&record); virtualRuntime_.SymbolSpeRecord(*sample); } @@ -1694,7 +1678,7 @@ bool SubCommandRecord::CollectionSymbol(std::unique_ptr record) void SubCommandRecord::CollectSymbol(PerfRecordSample *sample) { CHECK_TRUE(sample == nullptr, NO_RETVAL, 0, ""); - perf_callchain_context context = sample->inKernel() ? PERF_CONTEXT_KERNEL + perf_callchain_context context = sample->InKernel() ? PERF_CONTEXT_KERNEL : PERF_CONTEXT_USER; pid_t serverPid; // if no nr use ip ? remove stack nr == 0? @@ -1754,8 +1738,8 @@ bool SubCommandRecord::FinishWriteRecordFile() virtualRuntime_.CollectDedupSymbol(kernelSymbolsHits_, userSymbolsHits_); } else { fileWriter_->ReadDataSection( - [this] (std::unique_ptr record) -> bool { - return this->CollectionSymbol(std::move(record)); + [this] (PerfEventRecord& record) -> bool { + return this->CollectionSymbol(record); }); } #if USE_COLLECT_SYMBOLIC diff --git a/src/subcommand_report.cpp b/src/subcommand_report.cpp index d3565c4..e0b23bf 100644 --- a/src/subcommand_report.cpp +++ b/src/subcommand_report.cpp @@ -223,13 +223,13 @@ void SubCommandReport::ProcessSample(std::unique_ptr &sample) } } -bool SubCommandReport::RecordCallBack(std::unique_ptr record) +bool SubCommandReport::RecordCallBack(PerfEventRecord& record) { // tell process tree what happend for rebuild symbols - GetReport().virtualRuntime_.UpdateFromRecord(*record); + GetReport().virtualRuntime_.UpdateFromRecord(record); - if (record->GetType() == PERF_RECORD_SAMPLE) { - std::unique_ptr sample(static_cast(record.release())); + if (record.GetType() == PERF_RECORD_SAMPLE) { + std::unique_ptr sample(new PerfRecordSample(static_cast(record))); std::unique_ptr prevSample = nullptr; if (cpuOffMode_) { auto prevIt = prevSampleCache_.find(sample->data_.tid); @@ -264,7 +264,7 @@ bool SubCommandReport::RecordCallBack(std::unique_ptr record) } else { #if defined(HAVE_PROTOBUF) && HAVE_PROTOBUF if (protobufFormat_) { - protobufOutputFileWriter_->ProcessRecord(*record); + protobufOutputFileWriter_->ProcessRecord(record); } #endif } @@ -478,8 +478,8 @@ bool SubCommandReport::LoadPerfData() // before load data section SetHM(); recordFileReader_->ReadDataSection( - [this] (std::unique_ptr record) -> bool { - return this->RecordCallBack(std::move(record)); + [this] (PerfEventRecord& record) -> bool { + return this->RecordCallBack(record); }); if (cpuOffMode_) { FlushCacheRecord(); diff --git a/src/virtual_runtime.cpp b/src/virtual_runtime.cpp index 6dbdf83..4579371 100644 --- a/src/virtual_runtime.cpp +++ b/src/virtual_runtime.cpp @@ -148,7 +148,7 @@ VirtualThread &VirtualRuntime::CreateThread(pid_t pid, pid_t tid, const std::str thread.name_.c_str(), thread.GetMaps().size()); // we need make a PerfRecordComm auto commRecord = std::make_unique(IsKernelThread(pid), pid, tid, thread.name_); - recordCallBack_(std::move(commRecord)); + recordCallBack_(*commRecord); // only work for pid if (pid == tid) { if (isHM_) { @@ -169,7 +169,7 @@ VirtualThread &VirtualRuntime::CreateThread(pid_t pid, pid_t tid, const std::str HLOGD("make PerfRecordMmap2 %d:%d:%s:%s(0x%" PRIx64 "-0x%" PRIx64 ")@%" PRIx64 " ", thread.pid_, thread.tid_, thread.name_.c_str(), map->name.c_str(), map->begin, map->end, map->offset); - recordCallBack_(std::move(mmapRecord)); + recordCallBack_(*mmapRecord); if (updateNormalSymbol) { UpdateSymbols(map, pid); } @@ -281,7 +281,7 @@ void VirtualRuntime::UpdateKernelModulesSpaceMaps() for (const auto &map : koMaps) { auto record = std::make_unique(true, 0, 0, map.begin, map.end - map.begin, 0, map.name); - recordCallBack_(std::move(record)); + recordCallBack_(*record); } } std::move(koMaps.begin(), koMaps.end(), std::back_inserter(kernelSpaceMemMaps_)); @@ -294,7 +294,7 @@ void VirtualRuntime::UpdateKernelSpaceMaps() if (recordCallBack_) { auto record = std::make_unique(true, 0, 0, map.begin, map.end - map.begin, 0, map.name); - recordCallBack_(std::move(record)); + recordCallBack_(*record); } } @@ -333,7 +333,7 @@ void VirtualRuntime::UpdateKernelSymbols() kernelFile->textExecVaddrFileOffset_, KERNEL_MMAP_NAME); if (recordCallBack_) { - recordCallBack_(std::move(record)); + recordCallBack_(*record); } symbolsFiles_.emplace_back(std::move(kernelFile)); } else { @@ -390,7 +390,7 @@ void VirtualRuntime::DedupFromRecord(PerfRecordSample *recordSample) } // callstack dedup success recordSample->stackId_.value = stackId.value; - recordSample->header.size -= (sizeof(u64) * nr - sizeof(stackId)); + recordSample->header_.size -= (sizeof(u64) * nr - sizeof(stackId)); recordSample->data_.nr = 0; recordSample->data_.ips = nullptr; recordSample->removeStack_ = true; @@ -553,7 +553,7 @@ void VirtualRuntime::NeedDropKernelCallChain(PerfRecordSample &sample) { // only do this in record mode. if (recordCallBack_ == nullptr || needkernelCallChain_ || - !sample.inKernel() || sample.data_.nr == 0) { + !sample.InKernel() || sample.data_.nr == 0) { return; } @@ -570,11 +570,11 @@ void VirtualRuntime::NeedDropKernelCallChain(PerfRecordSample &sample) } sample.skipKernel_ = skip; sample.data_.nr -= skip; - sample.header.size -= sizeof(u64) * skip; + sample.header_.size -= sizeof(u64) * skip; if (sample.data_.server_nr > 0) { sample.skipPid_ = skipPid; sample.data_.server_nr -= skipPid; - sample.header.size -= sizeof(u64) * skipPid; + sample.header_.size -= sizeof(u64) * skipPid; } } @@ -656,9 +656,9 @@ void VirtualRuntime::UpdateFromRecord(PerfRecordSample &recordSample) void VirtualRuntime::UpdateFromRecord(PerfRecordMmap &recordMmap) { - HLOGV(" MMAP: size %d pid %u tid %u", recordMmap.header.size, recordMmap.data_.pid, + HLOGV(" MMAP: size %d pid %u tid %u", recordMmap.header_.size, recordMmap.data_.pid, recordMmap.data_.tid); - HLOGV(" MMAP: %s dso '%s' (0x%llx-0x%llx)@0x%llx", recordMmap.inKernel() ? "kernel" : "user", + HLOGV(" MMAP: %s dso '%s' (0x%llx-0x%llx)@0x%llx", recordMmap.InKernel() ? "kernel" : "user", recordMmap.data_.filename, recordMmap.data_.addr, recordMmap.data_.addr + recordMmap.data_.len, recordMmap.data_.pgoff); // kernel mmap @@ -666,12 +666,12 @@ void VirtualRuntime::UpdateFromRecord(PerfRecordMmap &recordMmap) if (IsKernelThread(recordMmap.data_.pid)) { UpdateKernelThreadMap(recordMmap.data_.pid, recordMmap.data_.addr, recordMmap.data_.len, recordMmap.data_.filename); - } else if (recordMmap.inKernel()) { + } else if (recordMmap.InKernel()) { UpdatekernelMap(recordMmap.data_.addr, recordMmap.data_.addr + recordMmap.data_.len, recordMmap.data_.pgoff, recordMmap.data_.filename); } else { - NeedAdaptSandboxPath(recordMmap.data_.filename, recordMmap.data_.pid, recordMmap.header.size); - FixHMBundleMmap(recordMmap.data_.filename, recordMmap.data_.pid, recordMmap.header.size); + NeedAdaptSandboxPath(recordMmap.data_.filename, recordMmap.data_.pid, recordMmap.header_.size); + FixHMBundleMmap(recordMmap.data_.filename, recordMmap.data_.pid, recordMmap.header_.size); auto map = UpdateThreadMaps(recordMmap.data_.pid, recordMmap.data_.tid, recordMmap.data_.filename, recordMmap.data_.addr, recordMmap.data_.len, recordMmap.data_.pgoff); UpdateSymbols(map, recordMmap.data_.pid); @@ -710,11 +710,11 @@ bool VirtualRuntime::CheckValidSandBoxMmap(PerfRecordMmap2 &recordMmap2) u64 len = elfLoadInfoMap[0].mmapLen; u64 pgoff = elfLoadInfoMap[0].offset & (~(elfLoadInfoMap[0].align >= 1 ? elfLoadInfoMap[0].align - 1 : 0)); std::unique_ptr mmap2FirstSeg = - std::make_unique(recordMmap2.inKernel(), recordMmap2.data_.pid, recordMmap2.data_.tid, + std::make_unique(recordMmap2.InKernel(), recordMmap2.data_.pid, recordMmap2.data_.tid, begin, len, pgoff, 0, 0, 0, PROT_READ, 0, std::string(recordMmap2.data_.filename)); UpdateThreadMaps(mmap2FirstSeg->data_.pid, mmap2FirstSeg->data_.tid, mmap2FirstSeg->data_.filename, mmap2FirstSeg->data_.addr, mmap2FirstSeg->data_.len, mmap2FirstSeg->data_.pgoff); - recordCallBack_(std::move(mmap2FirstSeg)); + recordCallBack_(*mmap2FirstSeg); } else { auto elfLoadInfoMap = symFile->GetPtLoads(); u64 begin = recordMmap2.data_.addr - elfLoadInfoMap[0].mmapLen; @@ -722,21 +722,21 @@ bool VirtualRuntime::CheckValidSandBoxMmap(PerfRecordMmap2 &recordMmap2) u64 pgoff = elfLoadInfoMap[0].offset & (~(elfLoadInfoMap[0].align >= 1 ? elfLoadInfoMap[0].align - 1 : 0)); std::unique_ptr mmap2FirstSeg = - std::make_unique(recordMmap2.inKernel(), recordMmap2.data_.pid, recordMmap2.data_.tid, + std::make_unique(recordMmap2.InKernel(), recordMmap2.data_.pid, recordMmap2.data_.tid, begin, len, pgoff, 0, 0, 0, PROT_READ, 0, curMap->name); UpdateThreadMaps(mmap2FirstSeg->data_.pid, mmap2FirstSeg->data_.tid, curMap->name, mmap2FirstSeg->data_.addr, mmap2FirstSeg->data_.len, mmap2FirstSeg->data_.pgoff); - recordCallBack_(std::move(mmap2FirstSeg)); + recordCallBack_(*mmap2FirstSeg); std::unique_ptr mmap2SecondSegment = - std::make_unique(recordMmap2.inKernel(), recordMmap2.data_.pid, recordMmap2.data_.tid, + std::make_unique(recordMmap2.InKernel(), recordMmap2.data_.pid, recordMmap2.data_.tid, recordMmap2.data_.addr, recordMmap2.data_.len, recordMmap2.data_.pgoff - prevMap->offset, // minus load offset of hap 0, 0, 0, recordMmap2.data_.prot, 0, curMap->name); UpdateThreadMaps(mmap2SecondSegment->data_.pid, mmap2SecondSegment->data_.tid, curMap->name, mmap2SecondSegment->data_.addr, mmap2SecondSegment->data_.len, mmap2SecondSegment->data_.pgoff); - recordCallBack_(std::move(mmap2SecondSegment)); + recordCallBack_(*mmap2SecondSegment); recordMmap2.discard_ = true; } symbolsFiles_.emplace_back(std::move(symFile)); @@ -764,15 +764,15 @@ void VirtualRuntime::UpdateFromRecord(PerfRecordMmap2 &recordMmap2) return; } - HLOGV(" MMAP2: size %d pid %u tid %u", recordMmap2.header.size, recordMmap2.data_.pid, + HLOGV(" MMAP2: size %d pid %u tid %u", recordMmap2.header_.size, recordMmap2.data_.pid, recordMmap2.data_.tid); - HLOGV(" MMAP2: %s dso '%s' (0x%llx-0x%llx)@0x%llx prot:%u", recordMmap2.inKernel() ? "kernel" : "user", + HLOGV(" MMAP2: %s dso '%s' (0x%llx-0x%llx)@0x%llx prot:%u", recordMmap2.InKernel() ? "kernel" : "user", recordMmap2.data_.filename, recordMmap2.data_.addr, recordMmap2.data_.addr + recordMmap2.data_.len, recordMmap2.data_.pgoff, recordMmap2.data_.prot); if (recordCallBack_) { - if (NeedAdaptSandboxPath(recordMmap2.data_.filename, recordMmap2.data_.pid, recordMmap2.header.size)) { - FixHMBundleMmap(recordMmap2.data_.filename, recordMmap2.data_.pid, recordMmap2.header.size); + if (NeedAdaptSandboxPath(recordMmap2.data_.filename, recordMmap2.data_.pid, recordMmap2.header_.size)) { + FixHMBundleMmap(recordMmap2.data_.filename, recordMmap2.data_.pid, recordMmap2.header_.size); CHECK_TRUE(!CheckValidSandBoxMmap(recordMmap2), NO_RETVAL, 0, ""); } } @@ -1253,7 +1253,7 @@ void VirtualRuntime::UpdateServiceSpaceMaps() std::make_unique(true, SYSMGR_PID, SYSMGR_PID, map->begin, map->end - map->begin, 0, SYSMGR_FILE_NAME); - recordCallBack_(std::move(record)); + recordCallBack_(*record); } } } @@ -1291,7 +1291,7 @@ void VirtualRuntime::UpdateDevhostSpaceMaps() std::make_unique(false, devhostPid_, devhostPid_, map->begin, map->end - map->begin, 0, map->name); - recordCallBack_(std::move(record)); + recordCallBack_(*record); } } } From 5fc78205e29e3ffb306d2e0c49fb8bee73cfd63c Mon Sep 17 00:00:00 2001 From: yuanye Date: Sat, 16 Nov 2024 23:10:07 +0800 Subject: [PATCH 02/13] =?UTF-8?q?rom=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yuanye --- include/perf_event_record.h | 61 +++++++++--------------- src/perf_event_record.cpp | 94 ++----------------------------------- 2 files changed, 27 insertions(+), 128 deletions(-) diff --git a/include/perf_event_record.h b/include/perf_event_record.h index a553017..aeca9d6 100644 --- a/include/perf_event_record.h +++ b/include/perf_event_record.h @@ -38,7 +38,6 @@ namespace OHOS { namespace Developtools { namespace HiPerf { -// using namespace OHOS::HiviewDFX; using PerfRecordType = int32_t; static constexpr uint32_t RECORD_SIZE_LIMIT = 65535; @@ -66,12 +65,6 @@ enum perf_event_hiperf_ext_type { PERF_RECORD_HIPERF_CALLSTACK = UINT32_MAX / 2, }; -// static inline const std::string RECORD_TYPE_NAME = type; -// const std::string& GetName() const override -// { -// return RECORD_TYPE_NAME; -// } - struct AttrWithId { perf_event_attr attr; std::vector ids; @@ -103,8 +96,7 @@ public: virtual void DumpLog(const std::string &prefix) const = 0; }; - -template +template class PerfEventRecordTemplate : public PerfEventRecord { public: PerfEventRecordTemplate(const PerfEventRecordTemplate &) = delete; @@ -163,12 +155,8 @@ public: protected: void Init(perf_event_type type, bool inKernel); void Init(perf_event_hiperf_ext_type type); - -private: - const char* RECORD_TYPE_NAME = NAME; }; - // PerfEventRecord template void PerfEventRecordTemplate::Init(perf_event_type type, bool inKernel) @@ -196,8 +184,17 @@ void PerfEventRecordTemplate::Init(uint8_t *p, const perf_event_ return; } header_ = *(reinterpret_cast(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("##PerfRecordType## memcpy_s return failed!"); + } + } else { + HLOGE("##PerfRecordType## return failed!"); + } +} template void PerfEventRecordTemplate::GetHeaderBinary(std::vector &buf) const @@ -209,7 +206,6 @@ void PerfEventRecordTemplate::GetHeaderBinary(std::vector(p)) = header_; } - template void PerfEventRecordTemplate::Dump(int indent, std::string outputFilename, FILE *outputDump) const { @@ -238,7 +234,6 @@ void PerfEventRecordTemplate::DumpLog(const std::string &prefix) // define convert from linux/perf_event.h // description from https://man7.org/linux/man-pages/man2/perf_event_open.2.html - constexpr __u64 SAMPLE_ID = PERF_SAMPLE_TID | PERF_SAMPLE_TIME | PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER; @@ -251,7 +246,6 @@ class PerfRecordAuxtrace : public PerfEventRecordTemplate &buf) const; @@ -265,7 +259,6 @@ public: class PerfRecordMmap : public PerfEventRecordTemplate { public: PerfRecordMmap() = default; - void Init(uint8_t *data, const perf_event_attr&) override; PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff, const std::string &filename); @@ -278,7 +271,6 @@ class PerfRecordMmap2 : public PerfEventRecordTemplate &buf) const override; void DumpData(int indent) const override; @@ -308,7 +299,6 @@ class PerfRecordComm : public PerfEventRecordTemplate { public: - PerfRecordExit() = default; - void Init(uint8_t *data, const perf_event_attr&) override; - bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; @@ -371,8 +358,6 @@ public: class PerfRecordThrottle : public PerfEventRecordTemplate { public: PerfRecordThrottle() = default; - void Init(uint8_t *data, const perf_event_attr&) override; - bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; @@ -381,8 +366,6 @@ public: class PerfRecordUnthrottle : public PerfEventRecordTemplate { public: PerfRecordUnthrottle() = default; - void Init(uint8_t *data, const perf_event_attr&) override; - bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; @@ -391,8 +374,6 @@ public: class PerfRecordFork : public PerfEventRecordTemplate { public: PerfRecordFork() = default; - void Init(uint8_t *data, const perf_event_attr&) override; - bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; @@ -404,7 +385,6 @@ public: class PerfRecordRead : public PerfEventRecordTemplate { public: PerfRecordRead() = default; - void Init(uint8_t *data, const perf_event_attr&) override; bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; @@ -433,7 +413,6 @@ class PerfRecordAux : public PerfEventRecordTemplate &buf) const override; void DumpData(int indent) const override; @@ -453,7 +432,6 @@ public: class PerfRecordItraceStart : public PerfEventRecordTemplate { public: PerfRecordItraceStart() = default; - void Init(uint8_t *data, const perf_event_attr&) override; bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; @@ -467,7 +445,6 @@ public: class PerfRecordLostSamples : public PerfEventRecordTemplate { public: PerfRecordLostSamples() = default; - void Init(uint8_t *data, const perf_event_attr&) override; bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; @@ -482,10 +459,9 @@ public: class PerfRecordSwitch : public PerfEventRecordTemplate { public: PerfRecordSwitch() = default; - void Init(uint8_t *data, const perf_event_attr&) override; bool GetBinary(std::vector &buf) const override; - void DumpData([[maybe_unused]] int indent) const override {}; + void DumpData(int) const override {}; }; /* @@ -509,16 +485,23 @@ public: class PerfRecordSwitchCpuWide : public PerfEventRecordTemplate { public: PerfRecordSwitchCpuWide() = default; - void Init(uint8_t *data, const perf_event_attr&) override; bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; }; +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 *p, - const perf_event_attr &attr); + static PerfEventRecord& GetPerfEventRecord(PerfRecordType type, uint8_t* data, + const perf_event_attr& attr); private: static thread_local std::unordered_map recordMap_; }; diff --git a/src/perf_event_record.cpp b/src/perf_event_record.cpp index a72950b..68e01d9 100644 --- a/src/perf_event_record.cpp +++ b/src/perf_event_record.cpp @@ -29,22 +29,6 @@ namespace HiPerf { bool PerfRecordSample::dumpRemoveStack_ = false; thread_local std::unordered_map PerfEventRecordFactory::recordMap_ = {}; -#define INIT_PERF_RECORD_DATA(PerfRecordType) \ -void PerfRecordType::Init(uint8_t* data, const perf_event_attr&) \ -{ \ - PerfEventRecordTemplate::Init(data); \ - size_t dataSize = GetSize(); \ - if (dataSize >= sizeof(header_)) { \ - size_t copySize = dataSize - sizeof(header_); \ - if (memcpy_s(reinterpret_cast(&data_), sizeof(data_), data + sizeof(header_), copySize) != 0) { \ - HLOGE("##PerfRecordType## memcpy_s return failed!"); \ - } \ - } else { \ - HLOGE("##PerfRecordType## return failed!"); \ - } \ -} \ - - PerfEventRecord* CreatePerfEventRecord(PerfRecordType type) { switch (type) { @@ -82,11 +66,10 @@ PerfEventRecord* CreatePerfEventRecord(PerfRecordType type) return new PerfRecordSwitchCpuWide(); default: HLOGE("unknown record type %d\n", type); - return nullptr; + return new PerfRecordNull(); } } - template inline void PushToBinary(bool condition, uint8_t *&p, const T &v) { @@ -127,11 +110,6 @@ inline void PopFromBinary2(bool condition, uint8_t *&p, T1 &v1, T2 &v2) } } - - -INIT_PERF_RECORD_DATA(PerfRecordAuxtrace) - - PerfRecordAuxtrace::PerfRecordAuxtrace(u64 size, u64 offset, u64 reference, u32 idx, u32 tid, u32 cpu, u32 pid) { PerfEventRecordTemplate::Init(PERF_RECORD_AUXTRACE); @@ -207,9 +185,6 @@ size_t PerfRecordAuxtrace::GetSize() const return header_.size + data_.size; } - -INIT_PERF_RECORD_DATA(PerfRecordMmap) - PerfRecordMmap::PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff, const std::string &filename) { @@ -259,11 +234,6 @@ void PerfRecordMmap::DumpLog(const std::string &prefix) const header_.size, data_.pid, data_.tid, data_.filename, data_.addr, data_.addr + data_.len, data_.pgoff); } - -INIT_PERF_RECORD_DATA(PerfRecordMmap2) - - - 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) @@ -350,6 +320,7 @@ 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(), @@ -357,8 +328,6 @@ void PerfRecordMmap2::DumpLog(const std::string &prefix) const data_.pgoff); } -INIT_PERF_RECORD_DATA(PerfRecordLost) - bool PerfRecordLost::GetBinary(std::vector &buf) const { if (buf.size() < GetSize()) { @@ -387,10 +356,6 @@ PerfRecordLost::PerfRecordLost(bool inKernel, u64 id, u64 lost) header_.size = sizeof(header_) + sizeof(data_); } - - -INIT_PERF_RECORD_DATA(PerfRecordComm) - PerfRecordComm::PerfRecordComm(bool inKernel, u32 pid, u32 tid, const std::string &comm) { @@ -447,7 +412,6 @@ PerfRecordSample::PerfRecordSample(const PerfRecordSample& sample) removeStack_ = sample.removeStack_; } - void PerfRecordSample::Init(uint8_t *p, const perf_event_attr &attr) { PerfEventRecordTemplate::Init(p); @@ -508,7 +472,6 @@ void PerfRecordSample::Init(uint8_t *p, const perf_event_attr &attr) } } - void PerfRecordSample::SetDumpRemoveStack(bool dumpRemoveStack) { dumpRemoveStack_ = dumpRemoveStack; @@ -519,7 +482,6 @@ bool PerfRecordSample::IsDumpRemoveStack() return dumpRemoveStack_; } - bool PerfRecordSample::GetBinary(std::vector &buf) const { if (buf.size() < GetSize()) { @@ -816,12 +778,6 @@ pid_t PerfRecordSample::GetServerPidof(unsigned int ipNr) } } - - - - -INIT_PERF_RECORD_DATA(PerfRecordExit) - bool PerfRecordExit::GetBinary(std::vector &buf) const { if (buf.size() < GetSize()) { @@ -842,11 +798,6 @@ void PerfRecordExit::DumpData(int indent) const data_.tid, data_.ptid, data_.time); } - - -INIT_PERF_RECORD_DATA(PerfRecordThrottle) - - bool PerfRecordThrottle::GetBinary(std::vector &buf) const { if (buf.size() < GetSize()) { @@ -867,10 +818,6 @@ void PerfRecordThrottle::DumpData(int indent) const data_.stream_id); } - - -INIT_PERF_RECORD_DATA(PerfRecordUnthrottle) - bool PerfRecordUnthrottle::GetBinary(std::vector &buf) const { if (buf.size() < GetSize()) { @@ -884,15 +831,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); } - -INIT_PERF_RECORD_DATA(PerfRecordFork) - bool PerfRecordFork::GetBinary(std::vector &buf) const { if (buf.size() < GetSize()) { @@ -913,10 +858,6 @@ void PerfRecordFork::DumpData(int indent) const data_.ptid); } - - -INIT_PERF_RECORD_DATA(PerfRecordRead) - bool PerfRecordRead::GetBinary(std::vector &buf) const { if (buf.size() < GetSize()) { @@ -938,10 +879,6 @@ void PerfRecordRead::DumpData(int indent) const data_.values.value, data_.values.timeEnabled, data_.values.timeRunning, data_.values.id); } - - -INIT_PERF_RECORD_DATA(PerfRecordAux) - bool PerfRecordAux::GetBinary(std::vector &buf) const { if (buf.size() < GetSize()) { @@ -971,12 +908,6 @@ void PerfRecordAux::DumpData(int indent) const data_.sample_id.time); } - - - - -INIT_PERF_RECORD_DATA(PerfRecordItraceStart) - bool PerfRecordItraceStart::GetBinary(std::vector &buf) const { if (buf.size() < GetSize()) { @@ -996,10 +927,6 @@ void PerfRecordItraceStart::DumpData(int indent) const PRINT_INDENT(indent, "pid %u, tid %u\n", data_.pid, data_.tid); } - - -INIT_PERF_RECORD_DATA(PerfRecordLostSamples) - bool PerfRecordLostSamples::GetBinary(std::vector &buf) const { if (buf.size() < GetSize()) { @@ -1019,10 +946,6 @@ void PerfRecordLostSamples::DumpData(int indent) const PRINT_INDENT(indent, "lost %llu\n", data_.lost); } - - -INIT_PERF_RECORD_DATA(PerfRecordSwitch) - bool PerfRecordSwitch::GetBinary(std::vector &buf) const { if (buf.size() < GetSize()) { @@ -1037,9 +960,6 @@ bool PerfRecordSwitch::GetBinary(std::vector &buf) const return true; } - -INIT_PERF_RECORD_DATA(PerfRecordSwitchCpuWide) - bool PerfRecordSwitchCpuWide::GetBinary(std::vector &buf) const { if (buf.size() < GetSize()) { @@ -1060,8 +980,8 @@ void PerfRecordSwitchCpuWide::DumpData(int indent) const data_.next_prev_tid); } -PerfEventRecord& PerfEventRecordFactory::GetPerfEventRecord(PerfRecordType type, uint8_t *data, - const perf_event_attr &attr) +PerfEventRecord& PerfEventRecordFactory::GetPerfEventRecord(PerfRecordType type, uint8_t* data, + const perf_event_attr &attr) { HLOG_ASSERT(data == nullptr); PerfEventRecord* record = nullptr; @@ -1076,10 +996,6 @@ PerfEventRecord& PerfEventRecordFactory::GetPerfEventRecord(PerfRecordType type, return *record; } - - - - } // namespace HiPerf } // namespace Developtools } // namespace OHOS From b260a3a786015ed43d8f9173f39b6579f4b5d669 Mon Sep 17 00:00:00 2001 From: yuanye Date: Sat, 16 Nov 2024 23:50:23 +0800 Subject: [PATCH 03/13] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yuanye --- include/perf_event_record.h | 161 ++++++++++++++++++++---------------- 1 file changed, 91 insertions(+), 70 deletions(-) diff --git a/include/perf_event_record.h b/include/perf_event_record.h index aeca9d6..938a2ce 100644 --- a/include/perf_event_record.h +++ b/include/perf_event_record.h @@ -73,14 +73,14 @@ struct AttrWithId { class PerfEventRecord { public: - virtual const char* GetNameP() const; - virtual void Init(uint8_t *data, const perf_event_attr& attr) = 0; + virtual const char* GetNameP() const = 0; + virtual void Init(uint8_t* data, const perf_event_attr& attr) = 0; virtual ~PerfEventRecord() = default; virtual size_t GetSize() const = 0; virtual size_t GetHeaderSize() const = 0; - virtual void GetHeaderBinary(std::vector &buf) const = 0; + virtual void GetHeaderBinary(std::vector& buf) const = 0; virtual uint32_t GetType() const = 0; virtual uint16_t GetMisc() const = 0; @@ -90,17 +90,17 @@ public: // to support --exclude-hiperf, return sample_id.pid to filter record, virtual pid_t GetPid() const = 0; - virtual bool GetBinary(std::vector &buf) const = 0; - virtual void Dump(int indent = 0, std::string outputFilename = "", FILE *outputDump = nullptr) const = 0; + virtual bool GetBinary(std::vector& buf) const = 0; + virtual void Dump(int indent = 0, std::string outputFilename = "", FILE* outputDump = nullptr) const = 0; virtual void DumpData(int indent) const = 0; - virtual void DumpLog(const std::string &prefix) const = 0; + virtual void DumpLog(const std::string& prefix) const = 0; }; template class PerfEventRecordTemplate : public PerfEventRecord { public: - PerfEventRecordTemplate(const PerfEventRecordTemplate &) = delete; - PerfEventRecordTemplate &operator=(const PerfEventRecordTemplate &) = delete; + PerfEventRecordTemplate(const PerfEventRecordTemplate&) = delete; + PerfEventRecordTemplate& operator=(const PerfEventRecordTemplate&) = delete; struct perf_event_header header_ = {}; DataType data_ = {}; @@ -110,104 +110,125 @@ public: } PerfEventRecordTemplate() = default; - void Init(uint8_t *data, const perf_event_attr& = {}) override; + void Init(uint8_t* p, const perf_event_attr& = {}) override { + if (p == nullptr) { + header_.type = PERF_RECORD_MMAP; + header_.misc = PERF_RECORD_MISC_USER; + header_.size = 0; + return; + } + header_ = *(reinterpret_cast(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!"); + } + }; virtual ~PerfEventRecordTemplate() {} - virtual size_t GetSize() const override + size_t GetSize() const override { return header_.size; }; - size_t GetHeaderSize() const override + size_t GetHeaderSize() const override final { return sizeof(header_); }; - void GetHeaderBinary(std::vector &buf) const override; + void GetHeaderBinary(std::vector& buf) const override final; - uint32_t GetType() const override + uint32_t GetType() const override final { return header_.type; }; - uint16_t GetMisc() const override + uint16_t GetMisc() const override final { return header_.misc; }; - bool InKernel() override + bool InKernel() override final { return header_.misc & PERF_RECORD_MISC_KERNEL; } - bool InUser() override + bool InUser() override final { return header_.misc & PERF_RECORD_MISC_USER; } // to support --exclude-hiperf, return sample_id.pid to filter record, - virtual pid_t GetPid() const override + pid_t GetPid() const override { return 0; }; - virtual bool GetBinary(std::vector &buf) const override = 0; - void Dump(int indent = 0, std::string outputFilename = "", FILE *outputDump = nullptr) const override; - virtual void DumpData(int indent) const override = 0; - virtual void DumpLog(const std::string &prefix) const override; + bool GetBinary(std::vector& buf) const override = 0; + void Dump(int indent = 0, std::string outputFilename = "", FILE* outputDump = nullptr) const override final; + void DumpData(int indent) const override = 0; + void DumpLog(const std::string& prefix) const override; protected: - void Init(perf_event_type type, bool inKernel); - void Init(perf_event_hiperf_ext_type type); + void 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_); + }; + + void Init(perf_event_hiperf_ext_type type) { + header_.type = type; + header_.misc = PERF_RECORD_MISC_USER; + header_.size = sizeof(header_); + } }; // PerfEventRecord -template -void PerfEventRecordTemplate::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_); -} +// template +// void PerfEventRecordTemplate::Init(perf_event_type type, bool inKernel) +// { +// } + +// template +// void PerfEventRecordTemplate::Init(perf_event_hiperf_ext_type type) +// { +// } + +// template +// void PerfEventRecordTemplate::Init(uint8_t *p, const perf_event_attr&) +// { +// if (p == nullptr) { +// header_.type = PERF_RECORD_MMAP; +// header_.misc = PERF_RECORD_MISC_USER; +// header_.size = 0; +// return; +// } +// header_ = *(reinterpret_cast(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!"); +// } +// } template -void PerfEventRecordTemplate::Init(perf_event_hiperf_ext_type type) -{ - header_.type = type; - header_.misc = PERF_RECORD_MISC_USER; - header_.size = sizeof(header_); -} - -template -void PerfEventRecordTemplate::Init(uint8_t *p, const perf_event_attr&) -{ - if (p == nullptr) { - header_.type = PERF_RECORD_MMAP; - header_.misc = PERF_RECORD_MISC_USER; - header_.size = 0; - return; - } - header_ = *(reinterpret_cast(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("##PerfRecordType## memcpy_s return failed!"); - } - } else { - HLOGE("##PerfRecordType## return failed!"); - } -} - -template -void PerfEventRecordTemplate::GetHeaderBinary(std::vector &buf) const +void PerfEventRecordTemplate::GetHeaderBinary(std::vector& buf) const { if (buf.size() < GetHeaderSize()) { buf.resize(GetHeaderSize()); } - uint8_t *p = buf.data(); - *(reinterpret_cast(p)) = header_; + uint8_t* p = buf.data(); + *(reinterpret_cast(p)) = header_; } template -void PerfEventRecordTemplate::Dump(int indent, std::string outputFilename, FILE *outputDump) const +void PerfEventRecordTemplate::Dump(int indent, std::string outputFilename, FILE* outputDump) const { if (outputDump != nullptr) { g_outputDump = outputDump; @@ -226,7 +247,7 @@ void PerfEventRecordTemplate::Dump(int indent, std::string outpu } template -void PerfEventRecordTemplate::DumpLog(const std::string &prefix) const +void PerfEventRecordTemplate::DumpLog(const std::string& prefix) const { HLOGV("%s: record %s: type %u, misc %u, size %zu\n", prefix.c_str(), GetNameP(), GetType(), GetMisc(), GetSize()); @@ -323,7 +344,7 @@ public: 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; + void Init(uint8_t* data, const perf_event_attr& attr) override; StackId stackId_ {0}; bool removeStack_ {false}; @@ -507,16 +528,16 @@ private: }; template -void PushToBinary(bool condition, uint8_t *&p, const T &v); +void PushToBinary(bool condition, uint8_t*& p, const T& v); template -void PushToBinary2(bool condition, uint8_t *&p, const T1 &v1, const T2 &v2); +void PushToBinary2(bool condition, uint8_t*& p, const T1& v1, const T2& v2); template -void PopFromBinary(bool condition, uint8_t *&p, T &v); +void PopFromBinary(bool condition, uint8_t*& p, T& v); template -void PopFromBinary2(bool condition, uint8_t *&p, T1 &v1, T2 &v2); +void PopFromBinary2(bool condition, uint8_t*& p, T1& v1, T2& v2); } // namespace HiPerf } // namespace Developtools } // namespace OHOS From e0abef1784e99be0f89cbbb926b1cb822af610d7 Mon Sep 17 00:00:00 2001 From: yuanye Date: Sat, 16 Nov 2024 23:58:44 +0800 Subject: [PATCH 04/13] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=8F=98=E9=87=8F?= =?UTF-8?q?=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yuanye --- include/perf_event_record.h | 50 +++++++------------------------------ src/perf_event_record.cpp | 2 -- src/perf_file_reader.cpp | 2 +- src/perf_file_writer.cpp | 6 ++--- src/subcommand_dump.cpp | 2 +- src/subcommand_record.cpp | 12 ++++----- 6 files changed, 20 insertions(+), 54 deletions(-) diff --git a/include/perf_event_record.h b/include/perf_event_record.h index 938a2ce..4939e23 100644 --- a/include/perf_event_record.h +++ b/include/perf_event_record.h @@ -73,7 +73,7 @@ struct AttrWithId { class PerfEventRecord { public: - virtual const char* GetNameP() const = 0; + virtual const char* GetName() const = 0; virtual void Init(uint8_t* data, const perf_event_attr& attr) = 0; virtual ~PerfEventRecord() = default; @@ -104,7 +104,7 @@ public: struct perf_event_header header_ = {}; DataType data_ = {}; - const char* GetNameP() const override final + const char* GetName() const override final { return RECORD_TYPE_NAME; } @@ -184,39 +184,6 @@ protected: } }; -// PerfEventRecord -// template -// void PerfEventRecordTemplate::Init(perf_event_type type, bool inKernel) -// { -// } - -// template -// void PerfEventRecordTemplate::Init(perf_event_hiperf_ext_type type) -// { -// } - -// template -// void PerfEventRecordTemplate::Init(uint8_t *p, const perf_event_attr&) -// { -// if (p == nullptr) { -// header_.type = PERF_RECORD_MMAP; -// header_.misc = PERF_RECORD_MISC_USER; -// header_.size = 0; -// return; -// } -// header_ = *(reinterpret_cast(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!"); -// } -// } - template void PerfEventRecordTemplate::GetHeaderBinary(std::vector& buf) const { @@ -241,7 +208,7 @@ void PerfEventRecordTemplate::Dump(int indent, std::string outpu } } PRINT_INDENT(indent, "\n"); - PRINT_INDENT(indent, "record %s: type %u, misc %u, size %zu\n", GetNameP(), GetType(), + PRINT_INDENT(indent, "record %s: type %u, misc %u, size %zu\n", GetName(), GetType(), GetMisc(), GetSize()); DumpData(indent + 1); } @@ -249,12 +216,13 @@ void PerfEventRecordTemplate::Dump(int indent, std::string outpu template void PerfEventRecordTemplate::DumpLog(const std::string& prefix) const { - HLOGV("%s: record %s: type %u, misc %u, size %zu\n", prefix.c_str(), GetNameP(), + HLOGV("%s: record %s: type %u, misc %u, size %zu\n", prefix.c_str(), GetName(), GetType(), GetMisc(), GetSize()); } // define convert from linux/perf_event.h // description from https://man7.org/linux/man-pages/man2/perf_event_open.2.html + constexpr __u64 SAMPLE_ID = PERF_SAMPLE_TID | PERF_SAMPLE_TIME | PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER; @@ -528,16 +496,16 @@ private: }; template -void PushToBinary(bool condition, uint8_t*& p, const T& v); +void PushToBinary(bool condition, uint8_t *&p, const T &v); template -void PushToBinary2(bool condition, uint8_t*& p, const T1& v1, const T2& v2); +void PushToBinary2(bool condition, uint8_t *&p, const T1 &v1, const T2 &v2); template -void PopFromBinary(bool condition, uint8_t*& p, T& v); +void PopFromBinary(bool condition, uint8_t *&p, T &v); template -void PopFromBinary2(bool condition, uint8_t*& p, T1& v1, T2& v2); +void PopFromBinary2(bool condition, uint8_t *&p, T1 &v1, T2 &v2); } // namespace HiPerf } // namespace Developtools } // namespace OHOS diff --git a/src/perf_event_record.cpp b/src/perf_event_record.cpp index 68e01d9..10a2928 100644 --- a/src/perf_event_record.cpp +++ b/src/perf_event_record.cpp @@ -20,8 +20,6 @@ #include "utilities.h" -// using namespace OHOS::HiviewDFX; -// using namespace std; namespace OHOS { namespace Developtools { namespace HiPerf { diff --git a/src/perf_file_reader.cpp b/src/perf_file_reader.cpp index 180c282..9900880 100644 --- a/src/perf_file_reader.cpp +++ b/src/perf_file_reader.cpp @@ -279,7 +279,7 @@ bool PerfFileReader::ReadRecord(ProcessRecordCB &callback) PerfEventRecord& record = PerfEventRecordFactory::GetPerfEventRecord( static_cast(header->type), data, *attr); // unknown record , break the process - if (record.GetNameP() == nullptr) { + if (record.GetName() == nullptr) { return false; } else { HLOGV("record type %u", record.GetType()); diff --git a/src/perf_file_writer.cpp b/src/perf_file_writer.cpp index a586b1e..69e8532 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.GetNameP(), 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.GetNameP()); + "%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); @@ -189,7 +189,7 @@ bool PerfFileWriter::ReadRecords(ProcessRecordCB &callback) PerfEventRecord& record = PerfEventRecordFactory::GetPerfEventRecord(static_cast(header->type), data, defaultEventAttr_); // skip unknown record - CHECK_TRUE(record.GetNameP() == 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(record); diff --git a/src/subcommand_dump.cpp b/src/subcommand_dump.cpp index f2b0a31..302c301 100644 --- a/src/subcommand_dump.cpp +++ b/src/subcommand_dump.cpp @@ -440,7 +440,7 @@ void SubCommandDump::DumpDataPortion(int indent) { int recordCount = 0; auto recordcCallback = [&](PerfEventRecord& record) { - CHECK_TRUE(record.GetNameP() == nullptr, false, 0, ""); // return false in callback can stop the read process + CHECK_TRUE(record.GetName() == nullptr, false, 0, ""); // return false in callback can stop the read process // for UT if (exportSampleIndex_ > 0) { diff --git a/src/subcommand_record.cpp b/src/subcommand_record.cpp index 41f265e..e9d844b 100644 --- a/src/subcommand_record.cpp +++ b/src/subcommand_record.cpp @@ -1325,7 +1325,7 @@ void SubCommandRecord::RemoveVdsoTmpFile() bool SubCommandRecord::ProcessRecord(PerfEventRecord& record) { - CHECK_TRUE(record.GetNameP() == nullptr, false, 1, "record is null"); + CHECK_TRUE(record.GetName() == nullptr, false, 1, "record is null"); #if HIDEBUG_RECORD_NOT_PROCESS // some times we want to check performance // but we still want to see the record number @@ -1375,14 +1375,14 @@ bool SubCommandRecord::SaveRecord(PerfEventRecord& record, bool ptrReleaseFlag) } } - if (record.GetNameP() == nullptr) { + if (record.GetName() == nullptr) { #ifdef HIPERF_DEBUG_TIME const auto saveTime = steady_clock::now(); #endif if (!fileWriter_->WriteRecord(record)) { // write file failed, need stop record perfEvents_.StopTracking(); - HLOGV("fail to write record %s", record.GetNameP()); + HLOGV("fail to write record %s", record.GetName()); return false; } if (record.GetType() == PERF_RECORD_SAMPLE) { @@ -1390,7 +1390,7 @@ bool SubCommandRecord::SaveRecord(PerfEventRecord& record, bool ptrReleaseFlag) } else { recordNoSamples_++; } - HLOGV(" write done. size=%zu name=%s", record.GetSize(), record.GetNameP()); + HLOGV(" write done. size=%zu name=%s", record.GetSize(), record.GetName()); #ifdef HIPERF_DEBUG_TIME saveRecordTimes_ += duration_cast(steady_clock::now() - saveTime); #endif @@ -1607,7 +1607,7 @@ bool SubCommandRecord::PostProcessRecordFile() // 2. read out the file and unwind auto record_callback = [&](PerfEventRecord& record) { - if (record.GetNameP() == nullptr) { + if (record.GetName() == nullptr) { // return false in callback can stop the read process return false; } else if (record.GetType() == PERF_RECORD_SAMPLE) { @@ -1657,7 +1657,7 @@ void SubCommandRecord::SymbolicHits() bool SubCommandRecord::CollectionSymbol(PerfEventRecord& record) { - CHECK_TRUE(record.GetNameP() == nullptr, false, 0, ""); + CHECK_TRUE(record.GetName() == nullptr, false, 0, ""); if (record.GetType() == PERF_RECORD_SAMPLE) { PerfRecordSample* sample = static_cast(&record); #if USE_COLLECT_SYMBOLIC From 4bb1274cb502b7abcd110334d32382a49e973114 Mon Sep 17 00:00:00 2001 From: yuanye Date: Sun, 17 Nov 2024 09:50:07 +0800 Subject: [PATCH 05/13] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yuanye --- .../perffile_fuzzer/PerfFile_fuzzer.cpp | 2 +- .../common/native/perf_event_record_test.cpp | 72 ++++++++++++------- .../common/native/perf_events_test.cpp | 8 +-- .../common/native/perf_file_reader_test.cpp | 2 +- .../common/native/virtual_runtime_test.cpp | 9 +-- 5 files changed, 55 insertions(+), 38 deletions(-) diff --git a/test/fuzztest/perffile_fuzzer/PerfFile_fuzzer.cpp b/test/fuzztest/perffile_fuzzer/PerfFile_fuzzer.cpp index e2faedd..4c080e5 100644 --- a/test/fuzztest/perffile_fuzzer/PerfFile_fuzzer.cpp +++ b/test/fuzztest/perffile_fuzzer/PerfFile_fuzzer.cpp @@ -73,7 +73,7 @@ bool FuzzPerfFileReader(const uint8_t *data, size_t size) } reader->ReadFeatureSection(); - auto recordCallback = [&](const std::unique_ptr &record) { + auto recordCallback = [&](PerfEventRecord& record) { // nothing to do return true; }; diff --git a/test/unittest/common/native/perf_event_record_test.cpp b/test/unittest/common/native/perf_event_record_test.cpp index a060e42..4fd0a64 100644 --- a/test/unittest/common/native/perf_event_record_test.cpp +++ b/test/unittest/common/native/perf_event_record_test.cpp @@ -80,7 +80,8 @@ HWTEST_F(PerfEventRecordTest, Mmap, TestSize.Level1) size_t buffSize = HEADER_SIZE + sizeof(PerfRecordMmapData) - KILO + strlen(data.filename) + 1; ASSERT_EQ(recordIn.GetSize(), buffSize); - PerfRecordMmap recordOut(buff.data()); + PerfRecordMmap recordOut; + recordOut.Init(buff.data()); ASSERT_EQ(recordOut.GetType(), PERF_RECORD_MMAP); ASSERT_EQ(recordOut.GetName(), RECORDNAME_MMAP); ASSERT_EQ(recordOut.GetMisc(), PERF_RECORD_MISC_KERNEL); @@ -115,7 +116,8 @@ HWTEST_F(PerfEventRecordTest, Mmap2, TestSize.Level1) size_t buffSize = HEADER_SIZE + sizeof(PerfRecordMmap2Data) - KILO + strlen(data.filename) + 1; ASSERT_EQ(recordIn.GetSize(), buffSize); - PerfRecordMmap2 recordOut(buff.data()); + PerfRecordMmap2 recordOut; + recordOut.Init(buff.data()); ASSERT_EQ(recordOut.GetType(), PERF_RECORD_MMAP2); ASSERT_EQ(recordOut.GetName(), RECORDNAME_MMAP2); ASSERT_EQ(recordOut.GetMisc(), PERF_RECORD_MISC_KERNEL); @@ -153,7 +155,8 @@ HWTEST_F(PerfEventRecordTest, Comm, TestSize.Level1) size_t buffSize = HEADER_SIZE + sizeof(PerfRecordCommData) - KILO + strlen(data.comm) + 1; ASSERT_EQ(recordIn.GetSize(), buffSize); - PerfRecordComm recordOut(buff.data()); + PerfRecordComm recordOut; + recordOut.Init(buff.data()); ASSERT_EQ(recordOut.GetType(), PERF_RECORD_COMM); ASSERT_EQ(recordOut.GetName(), RECORDNAME_COMM); ASSERT_EQ(recordOut.GetMisc(), PERF_RECORD_MISC_KERNEL); @@ -175,7 +178,8 @@ HWTEST_F(PerfEventRecordTest, Lost, TestSize.Level1) {PERF_RECORD_LOST_SAMPLES, PERF_RECORD_MISC_KERNEL, sizeof(TestRecordLostst)}, {1, 2}}; - PerfRecordLost record((uint8_t *)&data); + PerfRecordLost record; + record.Init((uint8_t *)&data); ASSERT_EQ(record.GetType(), PERF_RECORD_LOST_SAMPLES); ASSERT_EQ(record.GetName(), RECORDNAME_LOST); ASSERT_EQ(record.GetMisc(), PERF_RECORD_MISC_KERNEL); @@ -197,7 +201,8 @@ HWTEST_F(PerfEventRecordTest, Exit, TestSize.Level1) TestRecordExitst data = {{PERF_RECORD_EXIT, PERF_RECORD_MISC_KERNEL, sizeof(TestRecordExitst)}, {1, 2, 3, 4, 5}}; - PerfRecordExit record((uint8_t *)&data); + PerfRecordExit record; + record.Init((uint8_t *)&data); ASSERT_EQ(record.GetType(), PERF_RECORD_EXIT); ASSERT_EQ(record.GetName(), RECORDNAME_EXIT); ASSERT_EQ(record.GetMisc(), PERF_RECORD_MISC_KERNEL); @@ -220,7 +225,8 @@ HWTEST_F(PerfEventRecordTest, Throttle, TestSize.Level1) {PERF_RECORD_THROTTLE, PERF_RECORD_MISC_KERNEL, sizeof(TestRecordThrottlest)}, {1, 2, 3}}; - PerfRecordThrottle record((uint8_t *)&data); + PerfRecordThrottle record; + record.Init((uint8_t *)&data); ASSERT_EQ(record.GetType(), PERF_RECORD_THROTTLE); ASSERT_EQ(record.GetName(), RECORDNAME_THROTTLE); ASSERT_EQ(record.GetMisc(), PERF_RECORD_MISC_KERNEL); @@ -243,7 +249,8 @@ HWTEST_F(PerfEventRecordTest, Unthrottle, TestSize.Level1) {PERF_RECORD_UNTHROTTLE, PERF_RECORD_MISC_KERNEL, sizeof(TestRecordUNThrottlest)}, {1, 2, 3}}; - PerfRecordUnthrottle record((uint8_t *)&data); + PerfRecordUnthrottle record; + record.Init((uint8_t *)&data); ASSERT_EQ(record.GetType(), PERF_RECORD_UNTHROTTLE); ASSERT_EQ(record.GetName(), RECORDNAME_UNTHROTTLE); ASSERT_EQ(record.GetMisc(), PERF_RECORD_MISC_KERNEL); @@ -265,7 +272,8 @@ HWTEST_F(PerfEventRecordTest, Fork, TestSize.Level1) TestRecordForkst data = {{PERF_RECORD_FORK, PERF_RECORD_MISC_KERNEL, sizeof(TestRecordForkst)}, {1, 2, 3, 4, 5}}; - PerfRecordFork record((uint8_t *)&data); + PerfRecordFork record; + record.Init((uint8_t *)&data); ASSERT_EQ(record.GetType(), PERF_RECORD_FORK); ASSERT_EQ(record.GetName(), RECORDNAME_FORK); ASSERT_EQ(record.GetMisc(), PERF_RECORD_MISC_KERNEL); @@ -419,7 +427,8 @@ HWTEST_F(PerfEventRecordTest, Sample, TestSize.Level1) {}}; InitTestRecordSample(data); - PerfRecordSample record((uint8_t *)&data, attr); + PerfRecordSample record; + record.Init((uint8_t *)&data, attr); ASSERT_EQ(record.GetType(), PERF_RECORD_SAMPLE); ASSERT_EQ(record.GetName(), RECORDNAME_SAMPLE); ASSERT_EQ(record.GetMisc(), PERF_RECORD_MISC_KERNEL); @@ -439,7 +448,8 @@ HWTEST_F(PerfEventRecordTest, SampleReplaceWithCallStack1, TestSize.Level1) {}}; InitTestRecordSample(data); - PerfRecordSample record((uint8_t *)&data, attr); + PerfRecordSample record; + record.Init((uint8_t *)&data, attr); record.sampleType_ |= PERF_SAMPLE_REGS_USER; record.sampleType_ |= PERF_SAMPLE_STACK_USER; record.sampleType_ |= PERF_SAMPLE_CALLCHAIN; @@ -472,7 +482,8 @@ HWTEST_F(PerfEventRecordTest, SampleReplaceWithCallStack2, TestSize.Level1) {}}; InitTestRecordSample(data); - PerfRecordSample record((uint8_t *)&data, attr); + PerfRecordSample record; + record.Init((uint8_t *)&data, attr); record.sampleType_ |= PERF_SAMPLE_CALLCHAIN; std::vector ips = {}; @@ -498,7 +509,8 @@ HWTEST_F(PerfEventRecordTest, SampleReplaceWithCallStack3, TestSize.Level1) {}}; InitTestRecordSample(data); - PerfRecordSample record((uint8_t *)&data, attr); + PerfRecordSample record; + record.Init((uint8_t *)&data, attr); record.sampleType_ |= PERF_SAMPLE_CALLCHAIN; record.callFrames_ = {4, 5, 6, 7, 8, 9}; @@ -527,7 +539,8 @@ HWTEST_F(PerfEventRecordTest, SampleReplaceWithCallStack4, TestSize.Level1) {}}; InitTestRecordSample(data); - PerfRecordSample record((uint8_t *)&data, attr); + PerfRecordSample record; + record.Init((uint8_t *)&data, attr); record.sampleType_ |= PERF_SAMPLE_CALLCHAIN; record.callFrames_ = {}; @@ -553,7 +566,8 @@ HWTEST_F(PerfEventRecordTest, Read, TestSize.Level1) PerfRecordReadst data = {{PERF_RECORD_READ, PERF_RECORD_MISC_KERNEL, sizeof(PerfRecordReadst)}, {1, 2, {11, 12, 13, 14}}}; - PerfRecordRead record((uint8_t *)&data); + PerfRecordRead record; + record.Init((uint8_t *)&data); ASSERT_EQ(record.GetType(), PERF_RECORD_READ); ASSERT_EQ(record.GetName(), RECORDNAME_READ); ASSERT_EQ(record.GetMisc(), PERF_RECORD_MISC_KERNEL); @@ -575,7 +589,8 @@ HWTEST_F(PerfEventRecordTest, Aux, TestSize.Level1) PerfRecordAuxst data = {{PERF_RECORD_AUX, PERF_RECORD_MISC_KERNEL, sizeof(PerfRecordAuxst)}, {1, 2, 3}}; - PerfRecordAux record((uint8_t *)&data); + PerfRecordAux record; + record.Init((uint8_t *)&data); ASSERT_EQ(record.GetType(), PERF_RECORD_AUX); ASSERT_EQ(record.GetName(), RECORDNAME_AUX); ASSERT_EQ(record.GetMisc(), PERF_RECORD_MISC_KERNEL); @@ -598,7 +613,8 @@ HWTEST_F(PerfEventRecordTest, ItraceStart, TestSize.Level1) {PERF_RECORD_ITRACE_START, PERF_RECORD_MISC_KERNEL, sizeof(PerfRecordItraceStartst)}, {1, 2}}; - PerfRecordItraceStart record((uint8_t *)&data); + PerfRecordItraceStart record; + record.Init((uint8_t *)&data); ASSERT_EQ(record.GetType(), PERF_RECORD_ITRACE_START); ASSERT_EQ(record.GetName(), RECORDNAME_ITRACE_START); ASSERT_EQ(record.GetMisc(), PERF_RECORD_MISC_KERNEL); @@ -621,7 +637,8 @@ HWTEST_F(PerfEventRecordTest, LostSamples, TestSize.Level1) {PERF_RECORD_LOST_SAMPLES, PERF_RECORD_MISC_KERNEL, sizeof(PerfRecordLostSamplesst)}, {1}}; - PerfRecordLostSamples record((uint8_t *)&data); + PerfRecordLostSamples record; + record.Init((uint8_t *)&data); ASSERT_EQ(record.GetType(), PERF_RECORD_LOST_SAMPLES); ASSERT_EQ(record.GetName(), RECORDNAME_LOST_SAMPLES); ASSERT_EQ(record.GetMisc(), PERF_RECORD_MISC_KERNEL); @@ -644,7 +661,8 @@ HWTEST_F(PerfEventRecordTest, Switch, TestSize.Level1) {PERF_RECORD_SWITCH, PERF_RECORD_MISC_KERNEL, sizeof(perf_event_header)}, {}}; - PerfRecordSwitch record((uint8_t *)&data); + PerfRecordSwitch record; + record.Init((uint8_t *)&data); ASSERT_EQ(record.GetType(), PERF_RECORD_SWITCH); ASSERT_EQ(record.GetName(), RECORDNAME_SWITCH); ASSERT_EQ(record.GetMisc(), PERF_RECORD_MISC_KERNEL); @@ -667,7 +685,8 @@ HWTEST_F(PerfEventRecordTest, SwitchCpuWide, TestSize.Level1) {PERF_RECORD_SWITCH_CPU_WIDE, PERF_RECORD_MISC_KERNEL, sizeof(PerfRecordSwitchCpuWidest)}, {}}; - PerfRecordSwitchCpuWide record((uint8_t *)&data); + PerfRecordSwitchCpuWide record; + record.Init((uint8_t *)&data); ASSERT_EQ(record.GetType(), PERF_RECORD_SWITCH_CPU_WIDE); ASSERT_EQ(record.GetName(), RECORDNAME_SWITCH_CPU_WIDE); ASSERT_EQ(record.GetMisc(), PERF_RECORD_MISC_KERNEL); @@ -694,16 +713,17 @@ HWTEST_F(PerfEventRecordTest, GetPerfEventRecord, TestSize.Level1) if (type == PERF_RECORD_SAMPLE) { continue; } - std::unique_ptr perfEventRecord = - GetPerfEventRecord(static_cast(type), reinterpret_cast(&data), attr); + PerfEventRecord& perfEventRecord = + PerfEventRecordFactory::GetPerfEventRecord(static_cast(type), + reinterpret_cast(&data), attr); if (type < PERF_RECORD_NAMESPACES) { - ASSERT_EQ(perfEventRecord != nullptr, true); + ASSERT_EQ(perfEventRecord.GetName() != nullptr, true); } } - std::unique_ptr perfEventRecord = - GetPerfEventRecord(static_cast(PERF_RECORD_AUXTRACE), - reinterpret_cast(&data), attr); - ASSERT_EQ(perfEventRecord != nullptr, true); + PerfEventRecord& perfEventRecord = + PerfEventRecordFactory::GetPerfEventRecord(static_cast(PERF_RECORD_AUXTRACE), + reinterpret_cast(&data), attr); + ASSERT_EQ(perfEventRecord.GetName() != nullptr, true); } } // namespace HiPerf } // namespace Developtools diff --git a/test/unittest/common/native/perf_events_test.cpp b/test/unittest/common/native/perf_events_test.cpp index e12fef4..7bf177c 100644 --- a/test/unittest/common/native/perf_events_test.cpp +++ b/test/unittest/common/native/perf_events_test.cpp @@ -41,7 +41,7 @@ public: static void TestCodeThread(void); static void RunTestThreads(std::vector &threads); static void SetAllConfig(PerfEvents &event); - static bool RecordCount(std::unique_ptr record); + static bool RecordCount(PerfEventRecord& record); static void StatCount( const std::map> &countEvents); @@ -71,13 +71,9 @@ void PerfEventsTest::TearDown() {} uint64_t PerfEventsTest::g_recordCount = 0; uint64_t PerfEventsTest::g_statCount = 0; -bool PerfEventsTest::RecordCount(std::unique_ptr record) +bool PerfEventsTest::RecordCount(PerfEventRecord& record) { g_recordCount++; - if (record->GetType() == PERF_RECORD_SAMPLE) { - // the record is allowed from a cache memory, does not free memory after use - record.release(); - } return true; } diff --git a/test/unittest/common/native/perf_file_reader_test.cpp b/test/unittest/common/native/perf_file_reader_test.cpp index dd1f18b..d7eec63 100644 --- a/test/unittest/common/native/perf_file_reader_test.cpp +++ b/test/unittest/common/native/perf_file_reader_test.cpp @@ -25,7 +25,7 @@ using namespace OHOS::HiviewDFX; namespace OHOS { namespace Developtools { namespace HiPerf { -using ProcessRecordCB = const std::function record)>; +using ProcessRecordCB = const std::function; class PerfFileReaderTest : public testing::Test { public: static void SetUpTestCase(void); diff --git a/test/unittest/common/native/virtual_runtime_test.cpp b/test/unittest/common/native/virtual_runtime_test.cpp index 9eec14d..bca726a 100644 --- a/test/unittest/common/native/virtual_runtime_test.cpp +++ b/test/unittest/common/native/virtual_runtime_test.cpp @@ -41,7 +41,7 @@ public: void LogLevelTest(std::vector args, DebugLevel level); default_random_engine rnd_; std::unique_ptr runtime_; - bool RecordCallBack(std::unique_ptr record); + bool RecordCallBack(PerfEventRecord& record); size_t callbackCount_ = 0; void PrepareKernelSymbol(); @@ -69,10 +69,10 @@ void VirtualRuntimeTest::TearDown() runtime_.release(); } -bool VirtualRuntimeTest::RecordCallBack(std::unique_ptr record) +bool VirtualRuntimeTest::RecordCallBack(PerfEventRecord& record) { callbackCount_++; - printf("callbackCount_ %zu: type %d\n", callbackCount_, record->GetType()); + printf("callbackCount_ %zu: type %d\n", callbackCount_, record.GetType()); return true; } @@ -371,7 +371,8 @@ HWTEST_F(VirtualRuntimeTest, UnwindFromRecord, TestSize.Level1) (void)memset_s(&attr, sizeof(perf_event_attr), 0, sizeof(perf_event_attr)); attr.sample_type = TEST_RECORD_SAMPLE_TYPE; attr.sample_regs_user = TEST_DWARF_RECORD_REGS_USER; - PerfRecordSample sample(data.data(), attr); + PerfRecordSample sample; + sample.Init(data.data(), attr); sample.DumpLog("UnwindFromRecord"); ASSERT_EQ(sample.data_.stack_size, TEST_DWARF_RECORD_STACK_SIZE); From db070e6065a0596c5e684e346a0689a77f9999cd Mon Sep 17 00:00:00 2001 From: yuanye Date: Sun, 17 Nov 2024 10:12:08 +0800 Subject: [PATCH 06/13] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yuanye --- include/perf_event_record.h | 19 +- src/perf_event_record.cpp | 718 ++++++++++++++++++------------------ 2 files changed, 371 insertions(+), 366 deletions(-) diff --git a/include/perf_event_record.h b/include/perf_event_record.h index 4939e23..9ab196d 100644 --- a/include/perf_event_record.h +++ b/include/perf_event_record.h @@ -281,7 +281,12 @@ public: void DumpData(int indent) const override; // only for UT - PerfRecordLost(bool inKernel, u64 id, u64 lost); + PerfRecordLost(bool inKernel, u64 id, u64 lost) { + PerfEventRecordTemplate::Init(PERF_RECORD_LOST, inKernel); + data_.id = id; + data_.lost = lost; + header_.size = sizeof(header_) + sizeof(data_); + } }; class PerfRecordComm : public PerfEventRecordTemplate { @@ -326,9 +331,19 @@ public: // originalSize is use for expand callstack void ReplaceWithCallStack(size_t originalSize = 0); pid_t GetPid() const override; + void Clean(); // only for UT - PerfRecordSample(bool inKernel, u32 pid, u32 tid, u64 period = 0, u64 time = 0, u64 id = 0); + PerfRecordSample(bool inKernel, u32 pid, u32 tid, u64 period = 0, u64 time = 0, u64 id = 0) { + PerfEventRecordTemplate::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_); + } pid_t GetUstackServerPid(); pid_t GetServerPidof(unsigned int ipNr); diff --git a/src/perf_event_record.cpp b/src/perf_event_record.cpp index 10a2928..8eb8ec2 100644 --- a/src/perf_event_record.cpp +++ b/src/perf_event_record.cpp @@ -183,6 +183,300 @@ size_t PerfRecordAuxtrace::GetSize() const 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, + data_.reg_nr, data_.dyn_size, data_.time); +} + +void PerfRecordSample::RecoverCallStack() +{ + data_.ips = ips_.data(); + data_.nr = ips_.size(); + removeStack_ = true; +} + +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) + 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 HiviewDFX::DfxFrame &frame) { + ips_.emplace_back(frame.pc); + 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) { + HLOGV("combed %zu", callFrames_.size()); + } else { + HLOGV("failed to combed %zu", callFrames_.size()); + } + + if (sampleType_ & PERF_SAMPLE_REGS_USER) { + 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); + + // 2. clean the size + data_.stack_size = 0; + data_.dyn_size = 0; + } + + if (sampleType_ & PERF_SAMPLE_CALLCHAIN) { + HLOGV("ips change from %llu -> %zu", data_.nr, ips_.size()); + + // 3. remove the nr size + header_.size -= data_.nr * sizeof(u64); + + // 4. add new nr size + data_.nr = ips_.size(); + header_.size += data_.nr * sizeof(u64); + + // 5. change ips potin to our ips array and hold it. + data_.ips = ips_.data(); + } + } else { + // nothing need change + return; + } +} + +void PerfRecordSample::Init(uint8_t *p, const perf_event_attr &attr) +{ + PerfEventRecordTemplate::Init(p); + + HLOG_ASSERT(p == nullptr); + // clear the vector data + Clean(); + sampleType_ = attr.sample_type; + uint8_t *start = p; + p += sizeof(header_); + + // parse record according SAMPLE_TYPE + PopFromBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id); + PopFromBinary(sampleType_ & PERF_SAMPLE_IP, p, data_.ip); + PopFromBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.pid, data_.tid); + PopFromBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.time); + PopFromBinary(sampleType_ & PERF_SAMPLE_ADDR, p, data_.addr); + PopFromBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.id); + PopFromBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.stream_id); + PopFromBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.cpu, data_.res); + PopFromBinary(sampleType_ & PERF_SAMPLE_PERIOD, p, data_.period); + PopFromBinary(sampleType_ & PERF_SAMPLE_CALLCHAIN, p, data_.nr); + if (data_.nr > 0) { + // the pointer is from input(p), require caller keep input(p) with *this together + // think it in next time + data_.ips = reinterpret_cast(p); + p += data_.nr * sizeof(u64); + } + PopFromBinary(sampleType_ & PERF_SAMPLE_RAW, p, data_.raw_size); + if (data_.raw_size > 0) { + data_.raw_data = p; + p += data_.raw_size * sizeof(u8); + } + PopFromBinary(sampleType_ & PERF_SAMPLE_BRANCH_STACK, p, data_.bnr); + if (data_.bnr > 0) { + data_.lbr = reinterpret_cast(p); + p += data_.bnr * sizeof(PerfBranchEntry); + } + PopFromBinary(sampleType_ & PERF_SAMPLE_REGS_USER, p, data_.user_abi); + if (data_.user_abi > 0) { + data_.reg_mask = attr.sample_regs_user; + data_.reg_nr = __builtin_popcountll(data_.reg_mask); + data_.user_regs = reinterpret_cast(p); + p += data_.reg_nr * sizeof(u64); + } + PopFromBinary(sampleType_ & PERF_SAMPLE_SERVER_PID, p, data_.server_nr); + if (data_.server_nr > 0) { + data_.server_pids = reinterpret_cast(p); + p += data_.server_nr * sizeof(u64); + } + PopFromBinary(sampleType_ & PERF_SAMPLE_STACK_USER, p, data_.stack_size); + if (data_.stack_size > 0) { + data_.stack_data = p; + p += data_.stack_size; + PopFromBinary(true, p, data_.dyn_size); + } + uint32_t remain = header_.size - (p - start); + if (data_.nr == 0 && dumpRemoveStack_ && remain == sizeof(stackId_)) { + PopFromBinary(true, p, stackId_.value); + } +} + +bool PerfRecordSample::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + PushToBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id); + PushToBinary(sampleType_ & PERF_SAMPLE_IP, p, data_.ip); + PushToBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.pid, data_.tid); + PushToBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.time); + PushToBinary(sampleType_ & PERF_SAMPLE_ADDR, p, data_.addr); + PushToBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.id); + PushToBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.stream_id); + PushToBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.cpu, data_.res); + PushToBinary(sampleType_ & PERF_SAMPLE_PERIOD, p, data_.period); + PushToBinary(sampleType_ & PERF_SAMPLE_CALLCHAIN, p, data_.nr); + if (data_.nr > 0 && !removeStack_) { + std::copy(data_.ips + skipKernel_, data_.ips + data_.nr + skipKernel_, + reinterpret_cast(p)); + p += data_.nr * sizeof(u64); + } + PushToBinary(sampleType_ & PERF_SAMPLE_RAW, p, data_.raw_size); + if (data_.raw_size > 0) { + std::copy(data_.raw_data, data_.raw_data + data_.raw_size, p); + p += data_.raw_size * sizeof(u8); + } + PushToBinary(sampleType_ & PERF_SAMPLE_BRANCH_STACK, p, data_.bnr); + if (data_.bnr > 0) { + std::copy(data_.lbr, data_.lbr + data_.bnr, reinterpret_cast(p)); + p += data_.bnr * sizeof(PerfBranchEntry); + } + PushToBinary(sampleType_ & PERF_SAMPLE_REGS_USER, p, data_.user_abi); + if (data_.user_abi > 0 && data_.reg_nr > 0) { + std::copy(data_.user_regs, data_.user_regs + data_.reg_nr, reinterpret_cast(p)); + p += data_.reg_nr * sizeof(u64); + } + PushToBinary(sampleType_ & PERF_SAMPLE_SERVER_PID, p, data_.server_nr); + if (data_.server_nr > 0) { + std::copy(data_.server_pids + skipPid_, data_.server_pids + data_.server_nr + skipPid_, + reinterpret_cast(p)); + p += data_.server_nr * sizeof(u64); + } + PushToBinary(sampleType_ & PERF_SAMPLE_STACK_USER, p, data_.stack_size); + if (data_.stack_size > 0) { + std::copy(data_.stack_data, data_.stack_data + data_.stack_size, p); + p += data_.stack_size * sizeof(u8); + PushToBinary(true, p, data_.dyn_size); + } + PushToBinary(removeStack_, p, stackId_.value); + return true; +} + +void PerfRecordSample::DumpData(int indent) const +{ + PRINT_INDENT(indent, "sample_type: 0x%" PRIx64 "\n", sampleType_); + + // dump record according sampleType + if (sampleType_ & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) { + PRINT_INDENT(indent, "ID %" PRIu64 "\n", static_cast(data_.sample_id)); + } + if (sampleType_ & PERF_SAMPLE_IP) { + PRINT_INDENT(indent, "ip %llx\n", data_.ip); + } + if (sampleType_ & PERF_SAMPLE_TID) { + PRINT_INDENT(indent, "pid %u, tid %u\n", data_.pid, data_.tid); + } + if (sampleType_ & PERF_SAMPLE_TIME) { + PRINT_INDENT(indent, "time %llu\n", data_.time); + } + if (sampleType_ & PERF_SAMPLE_ADDR) { + PRINT_INDENT(indent, "addr %p\n", reinterpret_cast(data_.addr)); + } + if (sampleType_ & PERF_SAMPLE_STREAM_ID) { + PRINT_INDENT(indent, "stream_id %" PRIu64 "\n", static_cast(data_.stream_id)); + } + if (sampleType_ & PERF_SAMPLE_CPU) { + PRINT_INDENT(indent, "cpu %u, res %u\n", data_.cpu, data_.res); + } + if (sampleType_ & PERF_SAMPLE_PERIOD) { + PRINT_INDENT(indent, "period %" PRIu64 "\n", static_cast(data_.period)); + } + if (stackId_.section.id > 0) { + PRINT_INDENT(indent, "stackid %" PRIu64 "\n", static_cast(stackId_.section.id)); + } + if (sampleType_ & PERF_SAMPLE_CALLCHAIN) { + bool userContext = false; + PRINT_INDENT(indent, "callchain nr=%lld\n", data_.nr); + for (uint64_t i = 0; i < data_.nr; ++i) { + std::string_view supplement = ""; + if ((sampleType_ & PERF_SAMPLE_STACK_USER) == 0 || data_.ips[i] != PERF_CONTEXT_USER) { + PRINT_INDENT(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 = " "; + } + PRINT_INDENT(indent + 1, "0x%llx%s\n", data_.ips[i], supplement.data()); + } + } + if (sampleType_ & PERF_SAMPLE_RAW) { + PRINT_INDENT(indent, "raw size=%u\n", data_.raw_size); + const uint32_t *data = reinterpret_cast(data_.raw_data); + size_t size = data_.raw_size / sizeof(uint32_t); + for (size_t i = 0; i < size; ++i) { + PRINT_INDENT(indent + 1, "0x%08x (%x)\n", data[i], data[i]); + } + } + if (sampleType_ & PERF_SAMPLE_BRANCH_STACK) { + PRINT_INDENT(indent, "branch_stack nr=%lld\n", data_.bnr); + for (uint64_t i = 0; i < data_.bnr; ++i) { + auto &item = data_.lbr[i]; + PRINT_INDENT(indent + 1, "from 0x%llx, to 0x%llx, flags 0x%llx\n", item.from, item.to, item.flags); + } + } + if (sampleType_ & PERF_SAMPLE_REGS_USER) { + PRINT_INDENT(indent, "user regs: abi=%lld, reg_nr=%lld\n", data_.user_abi, data_.reg_nr); + for (uint64_t i = 0; i < data_.reg_nr; ++i) { + PRINT_INDENT(indent + 1, "0x%llx\n", data_.user_regs[i]); + } + } + if (sampleType_ & PERF_SAMPLE_SERVER_PID) { + PRINT_INDENT(indent, "server nr=%lld\n", data_.server_nr); + for (uint64_t i = 0; i < data_.server_nr; ++i) { + PRINT_INDENT(indent + 1, "pid: %llu\n", data_.server_pids[i]); + } + } + if (sampleType_ & PERF_SAMPLE_STACK_USER) { + PRINT_INDENT(indent, "user stack: size %llu dyn_size %lld\n", data_.stack_size, + data_.dyn_size); + } +} + +inline pid_t PerfRecordSample::GetPid() const +{ + return data_.pid; +} + +void PerfRecordSample::Clean() +{ + ips_.clear(); + callFrames_.clear(); + serverPidMap_.clear(); +} + PerfRecordMmap::PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff, const std::string &filename) { @@ -346,17 +640,9 @@ void PerfRecordLost::DumpData(int indent) const PRINT_INDENT(indent, "id %llu, lost %llu\n", data_.id, data_.lost); } -PerfRecordLost::PerfRecordLost(bool inKernel, u64 id, u64 lost) -{ - PerfEventRecordTemplate::Init(PERF_RECORD_LOST, inKernel); - data_.id = id; - data_.lost = lost; - header_.size = sizeof(header_) + sizeof(data_); -} PerfRecordComm::PerfRecordComm(bool inKernel, u32 pid, u32 tid, const std::string &comm) { - PerfEventRecordTemplate::Init(PERF_RECORD_COMM, inKernel); data_.pid = pid; data_.tid = tid; @@ -410,66 +696,6 @@ PerfRecordSample::PerfRecordSample(const PerfRecordSample& sample) removeStack_ = sample.removeStack_; } -void PerfRecordSample::Init(uint8_t *p, const perf_event_attr &attr) -{ - PerfEventRecordTemplate::Init(p); - - HLOG_ASSERT(p == nullptr); - sampleType_ = attr.sample_type; - uint8_t *start = p; - p += sizeof(header_); - - // parse record according SAMPLE_TYPE - PopFromBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id); - PopFromBinary(sampleType_ & PERF_SAMPLE_IP, p, data_.ip); - PopFromBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.pid, data_.tid); - PopFromBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.time); - PopFromBinary(sampleType_ & PERF_SAMPLE_ADDR, p, data_.addr); - PopFromBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.id); - PopFromBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.stream_id); - PopFromBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.cpu, data_.res); - PopFromBinary(sampleType_ & PERF_SAMPLE_PERIOD, p, data_.period); - PopFromBinary(sampleType_ & PERF_SAMPLE_CALLCHAIN, p, data_.nr); - if (data_.nr > 0) { - // the pointer is from input(p), require caller keep input(p) with *this together - // think it in next time - data_.ips = reinterpret_cast(p); - p += data_.nr * sizeof(u64); - } - PopFromBinary(sampleType_ & PERF_SAMPLE_RAW, p, data_.raw_size); - if (data_.raw_size > 0) { - data_.raw_data = p; - p += data_.raw_size * sizeof(u8); - } - PopFromBinary(sampleType_ & PERF_SAMPLE_BRANCH_STACK, p, data_.bnr); - if (data_.bnr > 0) { - data_.lbr = reinterpret_cast(p); - p += data_.bnr * sizeof(PerfBranchEntry); - } - PopFromBinary(sampleType_ & PERF_SAMPLE_REGS_USER, p, data_.user_abi); - if (data_.user_abi > 0) { - data_.reg_mask = attr.sample_regs_user; - data_.reg_nr = __builtin_popcountll(data_.reg_mask); - data_.user_regs = reinterpret_cast(p); - p += data_.reg_nr * sizeof(u64); - } - PopFromBinary(sampleType_ & PERF_SAMPLE_SERVER_PID, p, data_.server_nr); - if (data_.server_nr > 0) { - data_.server_pids = reinterpret_cast(p); - p += data_.server_nr * sizeof(u64); - } - PopFromBinary(sampleType_ & PERF_SAMPLE_STACK_USER, p, data_.stack_size); - if (data_.stack_size > 0) { - data_.stack_data = p; - p += data_.stack_size; - PopFromBinary(true, p, data_.dyn_size); - } - uint32_t remain = header_.size - (p - start); - if (data_.nr == 0 && dumpRemoveStack_ && remain == sizeof(stackId_)) { - PopFromBinary(true, p, stackId_.value); - } -} - void PerfRecordSample::SetDumpRemoveStack(bool dumpRemoveStack) { dumpRemoveStack_ = dumpRemoveStack; @@ -480,302 +706,6 @@ bool PerfRecordSample::IsDumpRemoveStack() return dumpRemoveStack_; } -bool PerfRecordSample::GetBinary(std::vector &buf) const -{ - if (buf.size() < GetSize()) { - buf.resize(GetSize()); - } - - GetHeaderBinary(buf); - uint8_t *p = buf.data() + GetHeaderSize(); - - PushToBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id); - PushToBinary(sampleType_ & PERF_SAMPLE_IP, p, data_.ip); - PushToBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.pid, data_.tid); - PushToBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.time); - PushToBinary(sampleType_ & PERF_SAMPLE_ADDR, p, data_.addr); - PushToBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.id); - PushToBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.stream_id); - PushToBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.cpu, data_.res); - PushToBinary(sampleType_ & PERF_SAMPLE_PERIOD, p, data_.period); - PushToBinary(sampleType_ & PERF_SAMPLE_CALLCHAIN, p, data_.nr); - if (data_.nr > 0 && !removeStack_) { - std::copy(data_.ips + skipKernel_, data_.ips + data_.nr + skipKernel_, - reinterpret_cast(p)); - p += data_.nr * sizeof(u64); - } - PushToBinary(sampleType_ & PERF_SAMPLE_RAW, p, data_.raw_size); - if (data_.raw_size > 0) { - std::copy(data_.raw_data, data_.raw_data + data_.raw_size, p); - p += data_.raw_size * sizeof(u8); - } - PushToBinary(sampleType_ & PERF_SAMPLE_BRANCH_STACK, p, data_.bnr); - if (data_.bnr > 0) { - std::copy(data_.lbr, data_.lbr + data_.bnr, reinterpret_cast(p)); - p += data_.bnr * sizeof(PerfBranchEntry); - } - PushToBinary(sampleType_ & PERF_SAMPLE_REGS_USER, p, data_.user_abi); - if (data_.user_abi > 0 && data_.reg_nr > 0) { - std::copy(data_.user_regs, data_.user_regs + data_.reg_nr, reinterpret_cast(p)); - p += data_.reg_nr * sizeof(u64); - } - PushToBinary(sampleType_ & PERF_SAMPLE_SERVER_PID, p, data_.server_nr); - if (data_.server_nr > 0) { - std::copy(data_.server_pids + skipPid_, data_.server_pids + data_.server_nr + skipPid_, - reinterpret_cast(p)); - p += data_.server_nr * sizeof(u64); - } - PushToBinary(sampleType_ & PERF_SAMPLE_STACK_USER, p, data_.stack_size); - if (data_.stack_size > 0) { - std::copy(data_.stack_data, data_.stack_data + data_.stack_size, p); - p += data_.stack_size * sizeof(u8); - PushToBinary(true, p, data_.dyn_size); - } - PushToBinary(removeStack_, p, stackId_.value); - return true; -} - -void PerfRecordSample::DumpData(int indent) const -{ - PRINT_INDENT(indent, "sample_type: 0x%" PRIx64 "\n", sampleType_); - - // dump record according sampleType - if (sampleType_ & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) { - PRINT_INDENT(indent, "ID %" PRIu64 "\n", static_cast(data_.sample_id)); - } - if (sampleType_ & PERF_SAMPLE_IP) { - PRINT_INDENT(indent, "ip %llx\n", data_.ip); - } - if (sampleType_ & PERF_SAMPLE_TID) { - PRINT_INDENT(indent, "pid %u, tid %u\n", data_.pid, data_.tid); - } - if (sampleType_ & PERF_SAMPLE_TIME) { - PRINT_INDENT(indent, "time %llu\n", data_.time); - } - if (sampleType_ & PERF_SAMPLE_ADDR) { - PRINT_INDENT(indent, "addr %p\n", reinterpret_cast(data_.addr)); - } - if (sampleType_ & PERF_SAMPLE_STREAM_ID) { - PRINT_INDENT(indent, "stream_id %" PRIu64 "\n", static_cast(data_.stream_id)); - } - if (sampleType_ & PERF_SAMPLE_CPU) { - PRINT_INDENT(indent, "cpu %u, res %u\n", data_.cpu, data_.res); - } - if (sampleType_ & PERF_SAMPLE_PERIOD) { - PRINT_INDENT(indent, "period %" PRIu64 "\n", static_cast(data_.period)); - } - if (stackId_.section.id > 0) { - PRINT_INDENT(indent, "stackid %" PRIu64 "\n", static_cast(stackId_.section.id)); - } - if (sampleType_ & PERF_SAMPLE_CALLCHAIN) { - bool userContext = false; - PRINT_INDENT(indent, "callchain nr=%lld\n", data_.nr); - for (uint64_t i = 0; i < data_.nr; ++i) { - std::string_view supplement = ""; - if ((sampleType_ & PERF_SAMPLE_STACK_USER) == 0 || data_.ips[i] != PERF_CONTEXT_USER) { - PRINT_INDENT(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 = " "; - } - PRINT_INDENT(indent + 1, "0x%llx%s\n", data_.ips[i], supplement.data()); - } - } - if (sampleType_ & PERF_SAMPLE_RAW) { - PRINT_INDENT(indent, "raw size=%u\n", data_.raw_size); - const uint32_t *data = reinterpret_cast(data_.raw_data); - size_t size = data_.raw_size / sizeof(uint32_t); - for (size_t i = 0; i < size; ++i) { - PRINT_INDENT(indent + 1, "0x%08x (%x)\n", data[i], data[i]); - } - } - if (sampleType_ & PERF_SAMPLE_BRANCH_STACK) { - PRINT_INDENT(indent, "branch_stack nr=%lld\n", data_.bnr); - for (uint64_t i = 0; i < data_.bnr; ++i) { - auto &item = data_.lbr[i]; - PRINT_INDENT(indent + 1, "from 0x%llx, to 0x%llx, flags 0x%llx\n", item.from, item.to, item.flags); - } - } - if (sampleType_ & PERF_SAMPLE_REGS_USER) { - PRINT_INDENT(indent, "user regs: abi=%lld, reg_nr=%lld\n", data_.user_abi, data_.reg_nr); - for (uint64_t i = 0; i < data_.reg_nr; ++i) { - PRINT_INDENT(indent + 1, "0x%llx\n", data_.user_regs[i]); - } - } - if (sampleType_ & PERF_SAMPLE_SERVER_PID) { - PRINT_INDENT(indent, "server nr=%lld\n", data_.server_nr); - for (uint64_t i = 0; i < data_.server_nr; ++i) { - PRINT_INDENT(indent + 1, "pid: %llu\n", data_.server_pids[i]); - } - } - if (sampleType_ & PERF_SAMPLE_STACK_USER) { - PRINT_INDENT(indent, "user stack: size %llu dyn_size %lld\n", data_.stack_size, - data_.dyn_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, - data_.reg_nr, data_.dyn_size, data_.time); -} - -void PerfRecordSample::RecoverCallStack() -{ - data_.ips = ips_.data(); - data_.nr = ips_.size(); - removeStack_ = true; -} - -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) + 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 HiviewDFX::DfxFrame &frame) { - ips_.emplace_back(frame.pc); - 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) { - HLOGV("combed %zu", callFrames_.size()); - } else { - HLOGV("failed to combed %zu", callFrames_.size()); - } - - if (sampleType_ & PERF_SAMPLE_REGS_USER) { - 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); - - // 2. clean the size - data_.stack_size = 0; - data_.dyn_size = 0; - } - - if (sampleType_ & PERF_SAMPLE_CALLCHAIN) { - HLOGV("ips change from %llu -> %zu", data_.nr, ips_.size()); - - // 3. remove the nr size - header_.size -= data_.nr * sizeof(u64); - - // 4. add new nr size - data_.nr = ips_.size(); - header_.size += data_.nr * sizeof(u64); - - // 5. change ips potin to our ips array and hold it. - data_.ips = ips_.data(); - } - } else { - // nothing need change - return; - } -} - -inline pid_t PerfRecordSample::GetPid() const -{ - return data_.pid; -} - -PerfRecordSample::PerfRecordSample(bool inKernel, u32 pid, u32 tid, u64 period, u64 time, u64 id) -{ - PerfEventRecordTemplate::Init(PERF_RECORD_SAMPLE, inKernel); - data_.pid = pid; - data_.tid = tid; - data_.period = period; - data_.time = time; - data_.id = 0; - header_.size = sizeof(header_) + sizeof(data_); -}; - -pid_t PerfRecordSample::GetUstackServerPid() -{ - if (!data_.server_nr) { - return data_.pid; - } - - size_t currServer = 0; - // ipNr == 1...nr: server_pid of data_.ips[nr] - for (size_t i = 0; i < data_.nr; i++) { - // context change, use next server pid - if (data_.ips[i] >= PERF_CONTEXT_MAX) { - currServer++; - } - } - // ipNr == nr + 1: server_pid of ustack - if (currServer > 0) { - currServer++; - } - if (currServer >= data_.server_nr) { - HLOGE("ustack server pid nr %zu out of range", currServer); - return data_.pid; - } - - // return server pid - return data_.server_pids[currServer]; -} - -pid_t PerfRecordSample::GetServerPidof(unsigned int ipNr) -{ - if (!data_.server_nr) { - return data_.pid; - } - - // init serverPidMap_ - if (!serverPidMap_.size()) { - size_t currServer = 0; - // ipNr == 0: server_pid of data_.ip - serverPidMap_.emplace_back(data_.server_pids[currServer]); - // ipNr == 1...nr: server_pid of data_.ips[nr] - for (size_t i = 1; i < data_.nr; i++) { - // context change, use next server pid - if (data_.ips[i] >= PERF_CONTEXT_MAX) { - currServer++; - } - if (currServer >= data_.server_nr) { - HLOGE("callchain server pid nr %zu out of range", currServer); - break; - } - serverPidMap_.emplace_back(data_.server_pids[currServer]); - } - } - - // return server pid - if (ipNr >= serverPidMap_.size()) { - return data_.pid; - } else { - return serverPidMap_[ipNr]; - } -} - bool PerfRecordExit::GetBinary(std::vector &buf) const { if (buf.size() < GetSize()) { @@ -978,6 +908,66 @@ void PerfRecordSwitchCpuWide::DumpData(int indent) const data_.next_prev_tid); } +pid_t PerfRecordSample::GetUstackServerPid() +{ + if (!data_.server_nr) { + return data_.pid; + } + + size_t currServer = 0; + // ipNr == 1...nr: server_pid of data_.ips[nr] + for (size_t i = 0; i < data_.nr; i++) { + // context change, use next server pid + if (data_.ips[i] >= PERF_CONTEXT_MAX) { + currServer++; + } + } + // ipNr == nr + 1: server_pid of ustack + if (currServer > 0) { + currServer++; + } + if (currServer >= data_.server_nr) { + HLOGE("ustack server pid nr %zu out of range", currServer); + return data_.pid; + } + + // return server pid + return data_.server_pids[currServer]; +} + +pid_t PerfRecordSample::GetServerPidof(unsigned int ipNr) +{ + if (!data_.server_nr) { + return data_.pid; + } + + // init serverPidMap_ + if (!serverPidMap_.size()) { + size_t currServer = 0; + // ipNr == 0: server_pid of data_.ip + serverPidMap_.emplace_back(data_.server_pids[currServer]); + // ipNr == 1...nr: server_pid of data_.ips[nr] + for (size_t i = 1; i < data_.nr; i++) { + // context change, use next server pid + if (data_.ips[i] >= PERF_CONTEXT_MAX) { + currServer++; + } + if (currServer >= data_.server_nr) { + HLOGE("callchain server pid nr %zu out of range", currServer); + break; + } + serverPidMap_.emplace_back(data_.server_pids[currServer]); + } + } + + // return server pid + if (ipNr >= serverPidMap_.size()) { + return data_.pid; + } else { + return serverPidMap_[ipNr]; + } +} + PerfEventRecord& PerfEventRecordFactory::GetPerfEventRecord(PerfRecordType type, uint8_t* data, const perf_event_attr &attr) { From 46d6b9ac76079ab262ff8f7e87d32f96e066612a Mon Sep 17 00:00:00 2001 From: yuanye Date: Sun, 17 Nov 2024 11:25:49 +0800 Subject: [PATCH 07/13] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yuanye --- include/perf_event_record.h | 35 +++++----- .../common/native/perf_event_record_test.cpp | 68 +++++++++++++++++++ 2 files changed, 86 insertions(+), 17 deletions(-) diff --git a/include/perf_event_record.h b/include/perf_event_record.h index 9ab196d..26db357 100644 --- a/include/perf_event_record.h +++ b/include/perf_event_record.h @@ -43,22 +43,23 @@ using PerfRecordType = int32_t; static constexpr uint32_t RECORD_SIZE_LIMIT = 65535; static constexpr uint32_t RECORD_SIZE_LIMIT_SPE = 524288; // auxMmapPages_ * pageSize_ -static const char PERF_RECORD_TYPE_AUXTRACE[] = "auxtrace"; -static const char PERF_RECORD_TYPE_SAMPLE[] = "sample"; -static const char PERF_RECORD_TYPE_MMAP[] = "mmap"; -static const char PERF_RECORD_TYPE_MMAP2[] = "mmap2"; -static const char PERF_RECORD_TYPE_LOST[] = "lost"; -static const char PERF_RECORD_TYPE_COMM[] = "comm"; -static const char PERF_RECORD_TYPE_EXIT[] = "exit"; -static const char PERF_RECORD_TYPE_THROTTLE[] = "throttle"; -static const char PERF_RECORD_TYPE_UNTHROTTLE[] = "unthrottle"; -static const char PERF_RECORD_TYPE_FORK[] = "fork"; -static const char PERF_RECORD_TYPE_READ[] = "read"; -static const char PERF_RECORD_TYPE_AUX[] = "aux"; -static const char PERF_RECORD_TYPE_ITRACESTART[] = "itraceStart"; -static const char PERF_RECORD_TYPE_LOSTSAMPLE[] = "lostSamples"; -static const char PERF_RECORD_TYPE_SWITCH[] = "switch"; -static const char PERF_RECORD_TYPE_SWITCHCPUWIDE[] = "switchCpuWide"; +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, @@ -494,7 +495,7 @@ public: void DumpData(int indent) const override; }; -class PerfRecordNull : public PerfEventRecordTemplate { +class PerfRecordNull : public PerfEventRecordTemplate { public: PerfRecordNull() = default; diff --git a/test/unittest/common/native/perf_event_record_test.cpp b/test/unittest/common/native/perf_event_record_test.cpp index 4fd0a64..ed05e08 100644 --- a/test/unittest/common/native/perf_event_record_test.cpp +++ b/test/unittest/common/native/perf_event_record_test.cpp @@ -16,6 +16,7 @@ #include "perf_event_record_test.h" #include +#include using namespace testing::ext; using namespace std; @@ -725,6 +726,73 @@ HWTEST_F(PerfEventRecordTest, GetPerfEventRecord, TestSize.Level1) reinterpret_cast(&data), attr); ASSERT_EQ(perfEventRecord.GetName() != nullptr, true); } + +HWTEST_F(PerfEventRecordTest, GetPerfEventRecord2, TestSize.Level1) +{ + struct PerfRecordSwitchCpuWidest { + perf_event_header h; + PerfRecordSwitchCpuWideData d; + }; + PerfRecordSwitchCpuWidest data = { + {PERF_RECORD_SWITCH_CPU_WIDE, PERF_RECORD_MISC_KERNEL, sizeof(PerfRecordSwitchCpuWidest)}, + {}}; + perf_event_attr attr {}; + attr.sample_type = UINT64_MAX; + PerfEventRecord& perfEventRecord1 = + PerfEventRecordFactory::GetPerfEventRecord(static_cast(PERF_RECORD_AUXTRACE), + reinterpret_cast(&data), attr); + PerfEventRecord& perfEventRecord2 = + PerfEventRecordFactory::GetPerfEventRecord(static_cast(PERF_RECORD_AUXTRACE), + reinterpret_cast(&data), attr); + + ASSERT_TRUE(&perfEventRecord1 == &perfEventRecord2); +} + + +HWTEST_F(PerfEventRecordTest, GetPerfEventRecord3, TestSize.Level1) +{ + struct PerfRecordSwitchCpuWidest { + perf_event_header h; + PerfRecordSwitchCpuWideData d; + }; + PerfRecordSwitchCpuWidest data = { + {PERF_RECORD_SWITCH_CPU_WIDE, PERF_RECORD_MISC_KERNEL, sizeof(PerfRecordSwitchCpuWidest)}, + {}}; + perf_event_attr attr {}; + attr.sample_type = UINT64_MAX; + PerfEventRecord& perfEventRecord1 = + PerfEventRecordFactory::GetPerfEventRecord(static_cast(PERF_RECORD_AUXTRACE), + reinterpret_cast(&data), attr); + PerfEventRecord& perfEventRecord2 = + PerfEventRecordFactory::GetPerfEventRecord(INT32_MAX, + reinterpret_cast(&data), attr); + ASSERT_TRUE(perfEventRecord1.GetName() != nullptr); + ASSERT_TRUE(perfEventRecord2.GetName() == nullptr); +} + +HWTEST_F(PerfEventRecordTest, MultiThreadGetPerfEventRecord, TestSize.Level1) +{ + struct PerfRecordSwitchCpuWidest { + perf_event_header h; + PerfRecordSwitchCpuWideData d; + }; + PerfRecordSwitchCpuWidest data = { + {PERF_RECORD_SWITCH_CPU_WIDE, PERF_RECORD_MISC_KERNEL, sizeof(PerfRecordSwitchCpuWidest)}, + {}}; + perf_event_attr attr {}; + attr.sample_type = UINT64_MAX; + PerfEventRecord& perfEventRecord1 = + PerfEventRecordFactory::GetPerfEventRecord(static_cast(PERF_RECORD_AUXTRACE), + reinterpret_cast(&data), attr); + + std::thread t1([&perfEventRecord1, &data, attr]() { + PerfEventRecord& perfEventRecord2 = + PerfEventRecordFactory::GetPerfEventRecord(static_cast(PERF_RECORD_AUXTRACE), + reinterpret_cast(&data), attr); + ASSERT_TRUE(&perfEventRecord1 != &perfEventRecord2); + }); + t1.join(); +} } // namespace HiPerf } // namespace Developtools } // namespace OHOS From 47cc911f123ec7687951bec80908cbb4cc482fbd Mon Sep 17 00:00:00 2001 From: yuanye Date: Tue, 19 Nov 2024 06:55:08 +0000 Subject: [PATCH 08/13] =?UTF-8?q?=E4=BC=98=E5=8C=96rom?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yuanye --- include/perf_event_record.h | 201 ++++++++++++------------------------ src/perf_event_record.cpp | 90 +++++++++++++--- src/perf_file_writer.cpp | 4 +- src/subcommand_record.cpp | 2 +- src/subcommand_report.cpp | 3 +- 5 files changed, 151 insertions(+), 149 deletions(-) diff --git a/include/perf_event_record.h b/include/perf_event_record.h index 26db357..51a2728 100644 --- a/include/perf_event_record.h +++ b/include/perf_event_record.h @@ -38,6 +38,7 @@ namespace OHOS { namespace Developtools { namespace HiPerf { +using namespace OHOS::HiviewDFX; using PerfRecordType = int32_t; static constexpr uint32_t RECORD_SIZE_LIMIT = 65535; @@ -74,27 +75,54 @@ struct AttrWithId { class PerfEventRecord { public: + struct perf_event_header header_ = {}; + virtual const char* GetName() const = 0; virtual void Init(uint8_t* data, const perf_event_attr& attr) = 0; virtual ~PerfEventRecord() = default; - virtual size_t GetSize() const = 0; - virtual size_t GetHeaderSize() const = 0; - virtual void GetHeaderBinary(std::vector& buf) const = 0; - - virtual uint32_t GetType() const = 0; - virtual uint16_t GetMisc() const = 0; - virtual bool InKernel() = 0; - virtual bool InUser() = 0; + virtual size_t GetSize() const + { + return header_.size; + }; + size_t GetHeaderSize() const + { + return sizeof(header_); + }; + void GetHeaderBinary(std::vector& buf) const; + uint32_t GetType() const + { + return header_.type; + }; + uint16_t GetMisc() const + { + return header_.misc; + }; + bool InKernel() + { + return header_.misc & PERF_RECORD_MISC_KERNEL; + } + bool InUser() + { + return header_.misc & PERF_RECORD_MISC_USER; + } // to support --exclude-hiperf, return sample_id.pid to filter record, - virtual pid_t GetPid() const = 0; + virtual pid_t GetPid() const + { + return 0; + }; - virtual bool GetBinary(std::vector& buf) const = 0; - virtual void Dump(int indent = 0, std::string outputFilename = "", FILE* outputDump = nullptr) const = 0; + 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 = 0; + 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 @@ -103,7 +131,6 @@ public: PerfEventRecordTemplate(const PerfEventRecordTemplate&) = delete; PerfEventRecordTemplate& operator=(const PerfEventRecordTemplate&) = delete; - struct perf_event_header header_ = {}; DataType data_ = {}; const char* GetName() const override final { @@ -111,14 +138,10 @@ public: } PerfEventRecordTemplate() = default; - void Init(uint8_t* p, const perf_event_attr& = {}) override { - if (p == nullptr) { - header_.type = PERF_RECORD_MMAP; - header_.misc = PERF_RECORD_MISC_USER; - header_.size = 0; - return; - } - header_ = *(reinterpret_cast(p)); + virtual ~PerfEventRecordTemplate() = default; + void Init(uint8_t* p, const perf_event_attr& = {}) override + { + InitHeader(p); size_t dataSize = GetSize(); if (dataSize >= sizeof(header_)) { @@ -130,97 +153,8 @@ public: HLOGE("init perf record failed!"); } }; - - virtual ~PerfEventRecordTemplate() {} - - size_t GetSize() const override - { - return header_.size; - }; - size_t GetHeaderSize() const override final - { - return sizeof(header_); - }; - void GetHeaderBinary(std::vector& buf) const override final; - - uint32_t GetType() const override final - { - return header_.type; - }; - uint16_t GetMisc() const override final - { - return header_.misc; - }; - bool InKernel() override final - { - return header_.misc & PERF_RECORD_MISC_KERNEL; - } - bool InUser() override final - { - return header_.misc & PERF_RECORD_MISC_USER; - } - - // to support --exclude-hiperf, return sample_id.pid to filter record, - pid_t GetPid() const override - { - return 0; - }; - - bool GetBinary(std::vector& buf) const override = 0; - void Dump(int indent = 0, std::string outputFilename = "", FILE* outputDump = nullptr) const override final; - void DumpData(int indent) const override = 0; - void DumpLog(const std::string& prefix) const override; - -protected: - void 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_); - }; - - void Init(perf_event_hiperf_ext_type type) { - header_.type = type; - header_.misc = PERF_RECORD_MISC_USER; - header_.size = sizeof(header_); - } }; -template -void PerfEventRecordTemplate::GetHeaderBinary(std::vector& buf) const -{ - if (buf.size() < GetHeaderSize()) { - buf.resize(GetHeaderSize()); - } - uint8_t* p = buf.data(); - *(reinterpret_cast(p)) = header_; -} - -template -void PerfEventRecordTemplate::Dump(int indent, std::string outputFilename, FILE* outputDump) const -{ - if (outputDump != nullptr) { - g_outputDump = outputDump; - } else if (!outputFilename.empty() && g_outputDump == nullptr) { - std::string resolvedPath = CanonicalizeSpecPath(outputFilename.c_str()); - g_outputDump = fopen(resolvedPath.c_str(), "w"); - if (g_outputDump == nullptr) { - printf("unable open file to '%s' because '%d'\n", outputFilename.c_str(), errno); - return; - } - } - PRINT_INDENT(indent, "\n"); - PRINT_INDENT(indent, "record %s: type %u, misc %u, size %zu\n", GetName(), GetType(), - GetMisc(), GetSize()); - DumpData(indent + 1); -} - -template -void PerfEventRecordTemplate::DumpLog(const std::string& prefix) const -{ - HLOGV("%s: record %s: type %u, misc %u, size %zu\n", prefix.c_str(), GetName(), - GetType(), GetMisc(), GetSize()); -} - // define convert from linux/perf_event.h // description from https://man7.org/linux/man-pages/man2/perf_event_open.2.html @@ -243,7 +177,7 @@ public: void DumpData(int indent) const override; void DumpLog(const std::string &prefix) const override; - size_t GetSize() const override; + virtual size_t GetSize() const override; }; class PerfRecordMmap : public PerfEventRecordTemplate { @@ -257,7 +191,7 @@ public: void DumpLog(const std::string &prefix) const override; }; -class PerfRecordMmap2 : public PerfEventRecordTemplate { +class PerfRecordMmap2 : public PerfEventRecordTemplate { public: PerfRecordMmap2() = default; @@ -265,7 +199,7 @@ public: 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); - PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, std::shared_ptr item); + PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, std::shared_ptr item); bool GetBinary(std::vector &buf) const override; void DumpData(int indent) const override; @@ -273,7 +207,7 @@ public: bool discard_ = false; }; -class PerfRecordLost : public PerfEventRecordTemplate { +class PerfRecordLost : public PerfEventRecordTemplate { public: PerfRecordLost() = default; @@ -282,20 +216,19 @@ public: void DumpData(int indent) const override; // only for UT - PerfRecordLost(bool inKernel, u64 id, u64 lost) { - PerfEventRecordTemplate::Init(PERF_RECORD_LOST, inKernel); + PerfRecordLost(bool inKernel, u64 id, u64 lost) + { + PerfEventRecord::Init(PERF_RECORD_LOST, inKernel); data_.id = id; data_.lost = lost; header_.size = sizeof(header_) + sizeof(data_); } }; -class PerfRecordComm : public PerfEventRecordTemplate { +class PerfRecordComm : public PerfEventRecordTemplate { public: PerfRecordComm() = default; - - PerfRecordComm(bool inKernel, u32 pid, u32 tid, const std::string &comm); bool GetBinary(std::vector &buf) const override; @@ -303,7 +236,7 @@ public: void DumpLog(const std::string &prefix) const override; }; -class PerfRecordSample : public PerfEventRecordTemplate { +class PerfRecordSample : public PerfEventRecordTemplate { public: uint64_t sampleType_ = SAMPLE_TYPE; uint64_t skipKernel_ = 0; @@ -312,7 +245,7 @@ public: // hold the new ips memory (after unwind) // used for data_.ips replace (ReplaceWithCallStack) std::vector ips_; - std::vector callFrames_; + std::vector callFrames_; std::vector serverPidMap_; PerfRecordSample() = default; @@ -335,8 +268,9 @@ public: void Clean(); // only for UT - PerfRecordSample(bool inKernel, u32 pid, u32 tid, u64 period = 0, u64 time = 0, u64 id = 0) { - PerfEventRecordTemplate::Init(PERF_RECORD_SAMPLE, inKernel); + PerfRecordSample(bool inKernel, u32 pid, u32 tid, u64 period = 0, u64 time = 0, u64 id = 0) + { + PerfEventRecord::Init(PERF_RECORD_SAMPLE, inKernel); Clean(); data_.pid = pid; data_.tid = tid; @@ -352,7 +286,7 @@ private: static bool dumpRemoveStack_; }; -class PerfRecordExit : public PerfEventRecordTemplate { +class PerfRecordExit : public PerfEventRecordTemplate { public: PerfRecordExit() = default; @@ -360,7 +294,7 @@ public: void DumpData(int indent) const override; }; -class PerfRecordThrottle : public PerfEventRecordTemplate { +class PerfRecordThrottle : public PerfEventRecordTemplate { public: PerfRecordThrottle() = default; @@ -368,7 +302,7 @@ public: void DumpData(int indent) const override; }; -class PerfRecordUnthrottle : public PerfEventRecordTemplate { +class PerfRecordUnthrottle : public PerfEventRecordTemplate { public: PerfRecordUnthrottle() = default; @@ -376,7 +310,7 @@ public: void DumpData(int indent) const override; }; -class PerfRecordFork : public PerfEventRecordTemplate { +class PerfRecordFork : public PerfEventRecordTemplate { public: PerfRecordFork() = default; @@ -387,7 +321,7 @@ public: /* This record indicates a read event. */ -class PerfRecordRead : public PerfEventRecordTemplate { +class PerfRecordRead : public PerfEventRecordTemplate { public: PerfRecordRead() = default; @@ -414,7 +348,7 @@ public: if set, then the data returned has overwritten previous data. */ -class PerfRecordAux : public PerfEventRecordTemplate { +class PerfRecordAux : public PerfEventRecordTemplate { public: uint64_t sampleType_ = SAMPLE_ID; PerfRecordAux() = default; @@ -434,7 +368,7 @@ public: tid thread ID of the thread starting an instruction trace. */ -class PerfRecordItraceStart : public PerfEventRecordTemplate { +class PerfRecordItraceStart : public PerfEventRecordTemplate { public: PerfRecordItraceStart() = default; @@ -447,7 +381,7 @@ public: record indicates some number of samples that may have been lost. */ -class PerfRecordLostSamples : public PerfEventRecordTemplate { +class PerfRecordLostSamples : public PerfEventRecordTemplate { public: PerfRecordLostSamples() = default; @@ -461,7 +395,7 @@ public: indicates whether it was a context switch into or away from the current process. */ -class PerfRecordSwitch : public PerfEventRecordTemplate { +class PerfRecordSwitch : public PerfEventRecordTemplate { public: PerfRecordSwitch() = default; @@ -487,7 +421,8 @@ public: The thread ID of the previous (if switching in) or next (if switching out) thread on the CPU. */ -class PerfRecordSwitchCpuWide : public PerfEventRecordTemplate { +class PerfRecordSwitchCpuWide + : public PerfEventRecordTemplate { public: PerfRecordSwitchCpuWide() = default; diff --git a/src/perf_event_record.cpp b/src/perf_event_record.cpp index 8eb8ec2..a5a3da9 100644 --- a/src/perf_event_record.cpp +++ b/src/perf_event_record.cpp @@ -20,6 +20,8 @@ #include "utilities.h" +using namespace OHOS::HiviewDFX; +using namespace std; namespace OHOS { namespace Developtools { namespace HiPerf { @@ -27,7 +29,7 @@ namespace HiPerf { bool PerfRecordSample::dumpRemoveStack_ = false; thread_local std::unordered_map PerfEventRecordFactory::recordMap_ = {}; -PerfEventRecord* CreatePerfEventRecord(PerfRecordType type) +static PerfEventRecord* CreatePerfEventRecord(PerfRecordType type) { switch (type) { case PERF_RECORD_SAMPLE: @@ -108,9 +110,68 @@ inline void PopFromBinary2(bool condition, uint8_t *&p, T1 &v1, T2 &v2) } } +// PerfEventRecord +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_); +}; + +void PerfEventRecord::Init(perf_event_hiperf_ext_type type) +{ + header_.type = type; + header_.misc = PERF_RECORD_MISC_USER; + header_.size = sizeof(header_); +} + +void PerfEventRecord::InitHeader(uint8_t* p) +{ + if (p == nullptr) { + header_.type = PERF_RECORD_MMAP; + header_.misc = PERF_RECORD_MISC_USER; + header_.size = 0; + return; + } + header_ = *(reinterpret_cast(p)); +} + +void PerfEventRecord::GetHeaderBinary(std::vector &buf) const +{ + if (buf.size() < GetHeaderSize()) { + buf.resize(GetHeaderSize()); + } + uint8_t *p = buf.data(); + *(reinterpret_cast(p)) = header_; +} + +void PerfEventRecord::Dump(int indent, std::string outputFilename, FILE *outputDump) const +{ + if (outputDump != nullptr) { + g_outputDump = outputDump; + } else if (!outputFilename.empty() && g_outputDump == nullptr) { + std::string resolvedPath = CanonicalizeSpecPath(outputFilename.c_str()); + g_outputDump = fopen(resolvedPath.c_str(), "w"); + if (g_outputDump == nullptr) { + printf("unable open file to '%s' because '%d'\n", outputFilename.c_str(), errno); + return; + } + } + PRINT_INDENT(indent, "\n"); + 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(), + GetType(), GetMisc(), GetSize()); +} + PerfRecordAuxtrace::PerfRecordAuxtrace(u64 size, u64 offset, u64 reference, u32 idx, u32 tid, u32 cpu, u32 pid) { - PerfEventRecordTemplate::Init(PERF_RECORD_AUXTRACE); + PerfEventRecord::Init(PERF_RECORD_AUXTRACE); data_.size = size; data_.offset = offset; data_.reference = reference; @@ -213,7 +274,7 @@ void PerfRecordSample::ReplaceWithCallStack(size_t originalSize) 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 HiviewDFX::DfxFrame &frame) { + 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 ips_.size() == (originalSize + beginIpsSize)) { @@ -266,12 +327,17 @@ void PerfRecordSample::ReplaceWithCallStack(size_t originalSize) void PerfRecordSample::Init(uint8_t *p, const perf_event_attr &attr) { - PerfEventRecordTemplate::Init(p); + PerfEventRecord::InitHeader(p); - HLOG_ASSERT(p == nullptr); + 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_); @@ -480,7 +546,7 @@ void PerfRecordSample::Clean() PerfRecordMmap::PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff, const std::string &filename) { - PerfEventRecordTemplate::Init(PERF_RECORD_MMAP, inKernel); + PerfEventRecord::Init(PERF_RECORD_MMAP, inKernel); data_.pid = pid; data_.tid = tid; @@ -530,7 +596,7 @@ PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, u64 addr, u64 u32 maj, u32 min, u64 ino, u32 prot, u32 flags, const std::string &filename) { - PerfEventRecordTemplate::Init(PERF_RECORD_MMAP2, inKernel); + PerfEventRecord::Init(PERF_RECORD_MMAP2, inKernel); data_.pid = pid; data_.tid = tid; data_.addr = addr; @@ -549,9 +615,9 @@ PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, u64 addr, u64 header_.size = sizeof(header_) + sizeof(data_) - KILO + filename.size() + 1; } -PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, std::shared_ptr item) +PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, std::shared_ptr item) { - PerfEventRecordTemplate::Init(PERF_RECORD_MMAP2, inKernel); + PerfEventRecord::Init(PERF_RECORD_MMAP2, inKernel); data_.pid = pid; data_.tid = tid; if (item != nullptr) { @@ -564,7 +630,7 @@ PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, std::shared_pt data_.ino_generation = 0; // r--p 00000000 103:3e 12307 /data/storage/el1/bundle/entry.hap // why prot get from this is 7. rwxp - HiviewDFX::DfxMap::PermsToProts(item->perms, data_.prot, data_.flags); + DfxMap::PermsToProts(item->perms, data_.prot, data_.flags); if (strncpy_s(data_.filename, KILO, item->name.c_str(), item->name.size()) != 0) { HLOGE("strncpy_s failed"); } @@ -643,7 +709,7 @@ void PerfRecordLost::DumpData(int indent) const PerfRecordComm::PerfRecordComm(bool inKernel, u32 pid, u32 tid, const std::string &comm) { - PerfEventRecordTemplate::Init(PERF_RECORD_COMM, inKernel); + PerfEventRecord::Init(PERF_RECORD_COMM, inKernel); data_.pid = pid; data_.tid = tid; if (strncpy_s(data_.comm, KILO, comm.c_str(), comm.size()) != 0) { @@ -971,7 +1037,7 @@ pid_t PerfRecordSample::GetServerPidof(unsigned int ipNr) PerfEventRecord& PerfEventRecordFactory::GetPerfEventRecord(PerfRecordType type, uint8_t* data, const perf_event_attr &attr) { - HLOG_ASSERT(data == nullptr); + HLOG_ASSERT(data != nullptr); PerfEventRecord* record = nullptr; auto it = recordMap_.find(type); if (it == recordMap_.end()) { diff --git a/src/perf_file_writer.cpp b/src/perf_file_writer.cpp index 69e8532..72913a4 100644 --- a/src/perf_file_writer.cpp +++ b/src/perf_file_writer.cpp @@ -186,8 +186,8 @@ bool PerfFileWriter::ReadRecords(ProcessRecordCB &callback) } uint8_t *data = buf; // the record is allowed from a cache memory, does not free memory after use - PerfEventRecord& record = PerfEventRecordFactory::GetPerfEventRecord(static_cast(header->type), - data, defaultEventAttr_); + PerfEventRecord& record = PerfEventRecordFactory::GetPerfEventRecord( + static_cast(header->type), data, defaultEventAttr_); // skip unknown record CHECK_TRUE(record.GetName() == nullptr, true, 0, ""); remainingSize = remainingSize - header->size - speSize; diff --git a/src/subcommand_record.cpp b/src/subcommand_record.cpp index e9d844b..b22c41e 100644 --- a/src/subcommand_record.cpp +++ b/src/subcommand_record.cpp @@ -1375,7 +1375,7 @@ bool SubCommandRecord::SaveRecord(PerfEventRecord& record, bool ptrReleaseFlag) } } - if (record.GetName() == nullptr) { + if (record.GetName() != nullptr) { #ifdef HIPERF_DEBUG_TIME const auto saveTime = steady_clock::now(); #endif diff --git a/src/subcommand_report.cpp b/src/subcommand_report.cpp index e0b23bf..8bcbf75 100644 --- a/src/subcommand_report.cpp +++ b/src/subcommand_report.cpp @@ -229,7 +229,8 @@ bool SubCommandReport::RecordCallBack(PerfEventRecord& record) GetReport().virtualRuntime_.UpdateFromRecord(record); if (record.GetType() == PERF_RECORD_SAMPLE) { - std::unique_ptr sample(new PerfRecordSample(static_cast(record))); + std::unique_ptr sample + = std::make_unique(static_cast(record)); std::unique_ptr prevSample = nullptr; if (cpuOffMode_) { auto prevIt = prevSampleCache_.find(sample->data_.tid); From f1d9f60fb6c85cdcfb4f6c39c57e2359c96dfc67 Mon Sep 17 00:00:00 2001 From: yuanye Date: Wed, 20 Nov 2024 14:36:53 +0800 Subject: [PATCH 09/13] =?UTF-8?q?=E8=A7=A3=E7=BC=96=E8=AF=91=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yuanye --- include/perf_event_record.h | 1 + 1 file changed, 1 insertion(+) mode change 100644 => 100755 include/perf_event_record.h diff --git a/include/perf_event_record.h b/include/perf_event_record.h old mode 100644 new mode 100755 index 51a2728..2ce1b77 --- a/include/perf_event_record.h +++ b/include/perf_event_record.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include From f7714ccc8733ab2a08b46d55905cefccd64356da Mon Sep 17 00:00:00 2001 From: yuanye Date: Wed, 20 Nov 2024 17:14:47 +0800 Subject: [PATCH 10/13] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=86=85=E5=AD=98?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yuanye --- include/perf_event_record.h | 8 ++++---- src/perf_event_record.cpp | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) mode change 100644 => 100755 src/perf_event_record.cpp diff --git a/include/perf_event_record.h b/include/perf_event_record.h index 2ce1b77..86d03af 100755 --- a/include/perf_event_record.h +++ b/include/perf_event_record.h @@ -91,7 +91,7 @@ public: { return sizeof(header_); }; - void GetHeaderBinary(std::vector& buf) const; + void GetHeaderBinary(std::vector &buf) const; uint32_t GetType() const { @@ -245,9 +245,9 @@ public: // extend // hold the new ips memory (after unwind) // used for data_.ips replace (ReplaceWithCallStack) - std::vector ips_; - std::vector callFrames_; - std::vector serverPidMap_; + static std::vector ips_; + static std::vector callFrames_; + static std::vector serverPidMap_; PerfRecordSample() = default; PerfRecordSample(const PerfRecordSample& sample); diff --git a/src/perf_event_record.cpp b/src/perf_event_record.cpp old mode 100644 new mode 100755 index a5a3da9..b36bafb --- a/src/perf_event_record.cpp +++ b/src/perf_event_record.cpp @@ -169,6 +169,10 @@ void PerfEventRecord::DumpLog(const std::string &prefix) const GetType(), GetMisc(), GetSize()); } +std::vector PerfRecordSample::ips_ = {}; +std::vector PerfRecordSample::callFrames_ = {}; +std::vector PerfRecordSample::serverPidMap_ = {}; + PerfRecordAuxtrace::PerfRecordAuxtrace(u64 size, u64 offset, u64 reference, u32 idx, u32 tid, u32 cpu, u32 pid) { PerfEventRecord::Init(PERF_RECORD_AUXTRACE); From 91879d0c37af30dcb1e0af7f80b924407364ea16 Mon Sep 17 00:00:00 2001 From: yuanye Date: Wed, 20 Nov 2024 17:15:58 +0800 Subject: [PATCH 11/13] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yuanye --- include/perf_event_record.h | 0 src/perf_event_record.cpp | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 include/perf_event_record.h mode change 100755 => 100644 src/perf_event_record.cpp diff --git a/include/perf_event_record.h b/include/perf_event_record.h old mode 100755 new mode 100644 diff --git a/src/perf_event_record.cpp b/src/perf_event_record.cpp old mode 100755 new mode 100644 From 28583c60f3d06eb51f79135becf4c8a657c7b8eb Mon Sep 17 00:00:00 2001 From: yuanye Date: Thu, 21 Nov 2024 14:23:07 +0800 Subject: [PATCH 12/13] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=97=A0=E7=94=A8?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yuanye --- include/perf_event_record.h | 1 + include/utilities.h | 23 ----------------------- src/perf_event_record.cpp | 6 ++++++ 3 files changed, 7 insertions(+), 23 deletions(-) diff --git a/include/perf_event_record.h b/include/perf_event_record.h index 86d03af..c394acd 100644 --- a/include/perf_event_record.h +++ b/include/perf_event_record.h @@ -172,6 +172,7 @@ public: u8* rawData_ = nullptr; 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; diff --git a/include/utilities.h b/include/utilities.h index 2c0ef91..9809f49 100644 --- a/include/utilities.h +++ b/include/utilities.h @@ -345,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/src/perf_event_record.cpp b/src/perf_event_record.cpp index b36bafb..a38c9ab 100644 --- a/src/perf_event_record.cpp +++ b/src/perf_event_record.cpp @@ -173,6 +173,12 @@ std::vector PerfRecordSample::ips_ = {}; std::vector PerfRecordSample::callFrames_ = {}; std::vector PerfRecordSample::serverPidMap_ = {}; +void PerfRecordAuxtrace::Init(uint8_t* data, const perf_event_attr& attr) +{ + PerfEventRecordTemplate::Init(data); + rawData_ = data + header_.size; +} + PerfRecordAuxtrace::PerfRecordAuxtrace(u64 size, u64 offset, u64 reference, u32 idx, u32 tid, u32 cpu, u32 pid) { PerfEventRecord::Init(PERF_RECORD_AUXTRACE); From 9c7fb628d96b0c7ff101e451e8256e839b32f42f Mon Sep 17 00:00:00 2001 From: yuanye Date: Thu, 21 Nov 2024 15:20:00 +0800 Subject: [PATCH 13/13] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=B8=B8=E5=BC=95?= =?UTF-8?q?=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yuanye --- include/subcommand_dump.h | 2 +- include/subcommand_record.h | 2 +- src/subcommand_dump.cpp | 2 +- src/subcommand_record.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/subcommand_dump.h b/include/subcommand_dump.h index cb4e7b2..2e7ddcc 100644 --- a/include/subcommand_dump.h +++ b/include/subcommand_dump.h @@ -107,7 +107,7 @@ private: void DumpPrintFileHeader(int indent = 0); void DumpAttrPortion(int indent = 0); void DumpDataPortion(int indent = 0); - void DumpCallChain(int indent, PerfRecordSample& sample); + void DumpCallChain(int indent, const PerfRecordSample& sample); void DumpFeaturePortion(int indent = 0); void DumpUniqueStackTableNode(int indent, const PerfFileSectionUniStackTable &uniStackTable); void ExprotUserData(PerfEventRecord& record); diff --git a/include/subcommand_record.h b/include/subcommand_record.h index e2ba4ef..81f1b18 100644 --- a/include/subcommand_record.h +++ b/include/subcommand_record.h @@ -304,7 +304,7 @@ private: // callback to process record bool ProcessRecord(PerfEventRecord& record); - bool SaveRecord(PerfEventRecord& record, bool ptrReleaseFlag = false); + 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); diff --git a/src/subcommand_dump.cpp b/src/subcommand_dump.cpp index 302c301..6d5cc9d 100644 --- a/src/subcommand_dump.cpp +++ b/src/subcommand_dump.cpp @@ -423,7 +423,7 @@ void SubCommandDump::ExprotUserData(PerfEventRecord& record) } } -void SubCommandDump::DumpCallChain(int indent, PerfRecordSample& sample) +void SubCommandDump::DumpCallChain(int indent, const PerfRecordSample& sample) { PRINT_INDENT(indent, "\n callchain: %zu\n", sample.callFrames_.size()); if (sample.callFrames_.size() > 0) { diff --git a/src/subcommand_record.cpp b/src/subcommand_record.cpp index b22c41e..24bfa70 100644 --- a/src/subcommand_record.cpp +++ b/src/subcommand_record.cpp @@ -1359,7 +1359,7 @@ bool SubCommandRecord::ProcessRecord(PerfEventRecord& record) #endif } -bool SubCommandRecord::SaveRecord(PerfEventRecord& record, bool ptrReleaseFlag) +bool SubCommandRecord::SaveRecord(const PerfEventRecord& record, bool ptrReleaseFlag) { #if HIDEBUG_RECORD_NOT_SAVE return true;