mirror of
https://gitee.com/openharmony/developtools_hiperf
synced 2024-11-26 17:21:15 +00:00
对象复用优化性能
Signed-off-by: yuanye <yuanye64@huawei.com>
This commit is contained in:
parent
c6abb4898f
commit
45e403fdbf
@ -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<uint8_t> &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<uint8_t> &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<uint8_t> &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 <typename DataType, const char* NAME>
|
||||
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<uint8_t> &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<uint8_t> &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<uint8_t> &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 <typename DataType, const char* NAME>
|
||||
void PerfEventRecordTemplate<DataType, NAME>::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 <typename DataType, const char* NAME>
|
||||
void PerfEventRecordTemplate<DataType, NAME>::Init(perf_event_hiperf_ext_type type)
|
||||
{
|
||||
header_.type = type;
|
||||
header_.misc = PERF_RECORD_MISC_USER;
|
||||
header_.size = sizeof(header_);
|
||||
}
|
||||
|
||||
template <typename DataType, const char* NAME>
|
||||
void PerfEventRecordTemplate<DataType, NAME>::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<perf_event_header *>(p));
|
||||
}
|
||||
|
||||
|
||||
template <typename DataType, const char* NAME>
|
||||
void PerfEventRecordTemplate<DataType, NAME>::GetHeaderBinary(std::vector<uint8_t> &buf) const
|
||||
{
|
||||
if (buf.size() < GetHeaderSize()) {
|
||||
buf.resize(GetHeaderSize());
|
||||
}
|
||||
uint8_t *p = buf.data();
|
||||
*(reinterpret_cast<perf_event_header *>(p)) = header_;
|
||||
}
|
||||
|
||||
|
||||
template <typename DataType, const char* NAME>
|
||||
void PerfEventRecordTemplate<DataType, NAME>::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 <typename DataType, const char* NAME>
|
||||
void PerfEventRecordTemplate<DataType, NAME>::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<PerfRecordAuxtraceData, PERF_RECORD_TYPE_AUXTRACE> {
|
||||
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<uint8_t> &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<PerfRecordMmapData, PERF_RECORD_TYPE_MMAP> {
|
||||
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<PerfRecordMmap2Data, PERF_RECORD_TYPE_MMAP> {
|
||||
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<DfxMap> item);
|
||||
PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, std::shared_ptr<HiviewDFX::DfxMap> item);
|
||||
|
||||
bool GetBinary(std::vector<uint8_t> &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<PerfRecordLostData, PERF_RECORD_TYPE_MMAP> {
|
||||
public:
|
||||
PerfRecordLostData data_;
|
||||
|
||||
explicit PerfRecordLost(uint8_t *p);
|
||||
PerfRecordLost() = default;
|
||||
void Init(uint8_t *data, const perf_event_attr&) override;
|
||||
|
||||
bool GetBinary(std::vector<uint8_t> &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<PerfRecordCommData, PERF_RECORD_TYPE_MMAP> {
|
||||
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<PerfRecordSampleData, PERF_RECORD_TYPE_MMAP> {
|
||||
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<u64> ips_;
|
||||
static std::vector<DfxFrame> callFrames_;
|
||||
static std::vector<pid_t> serverPidMap_;
|
||||
std::vector<u64> ips_;
|
||||
std::vector<HiviewDFX::DfxFrame> callFrames_;
|
||||
std::vector<pid_t> 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<uint8_t> &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<PerfRecordExitData, PERF_RECORD_TYPE_MMAP> {
|
||||
public:
|
||||
PerfRecordExitData data_;
|
||||
|
||||
explicit PerfRecordExit(uint8_t *p);
|
||||
PerfRecordExit() = default;
|
||||
void Init(uint8_t *data, const perf_event_attr&) override;
|
||||
|
||||
|
||||
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
||||
void DumpData(int indent) const override;
|
||||
};
|
||||
|
||||
class PerfRecordThrottle : public PerfEventRecord {
|
||||
class PerfRecordThrottle : public PerfEventRecordTemplate<PerfRecordThrottleData, PERF_RECORD_TYPE_MMAP> {
|
||||
public:
|
||||
PerfRecordThrottleData data_;
|
||||
PerfRecordThrottle() = default;
|
||||
void Init(uint8_t *data, const perf_event_attr&) override;
|
||||
|
||||
PerfRecordThrottle(uint8_t *p);
|
||||
|
||||
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
||||
void DumpData(int indent) const override;
|
||||
};
|
||||
|
||||
class PerfRecordUnthrottle : public PerfEventRecord {
|
||||
class PerfRecordUnthrottle : public PerfEventRecordTemplate<PerfRecordThrottleData, PERF_RECORD_TYPE_MMAP> {
|
||||
public:
|
||||
PerfRecordThrottleData data_;
|
||||
PerfRecordUnthrottle() = default;
|
||||
void Init(uint8_t *data, const perf_event_attr&) override;
|
||||
|
||||
explicit PerfRecordUnthrottle(uint8_t *p);
|
||||
|
||||
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
||||
void DumpData(int indent) const override;
|
||||
};
|
||||
|
||||
class PerfRecordFork : public PerfEventRecord {
|
||||
class PerfRecordFork : public PerfEventRecordTemplate<PerfRecordForkData, PERF_RECORD_TYPE_MMAP> {
|
||||
public:
|
||||
PerfRecordForkData data_;
|
||||
PerfRecordFork() = default;
|
||||
void Init(uint8_t *data, const perf_event_attr&) override;
|
||||
|
||||
explicit PerfRecordFork(uint8_t *p);
|
||||
|
||||
bool GetBinary(std::vector<uint8_t> &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<PerfRecordReadData, PERF_RECORD_TYPE_MMAP> {
|
||||
public:
|
||||
PerfRecordReadData data_;
|
||||
PerfRecordRead() = default;
|
||||
void Init(uint8_t *data, const perf_event_attr&) override;
|
||||
|
||||
explicit PerfRecordRead(uint8_t *p);
|
||||
bool GetBinary(std::vector<uint8_t> &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<PerfRecordAuxData, PERF_RECORD_TYPE_MMAP> {
|
||||
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<uint8_t> &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<PerfRecordItraceStartData, PERF_RECORD_TYPE_MMAP> {
|
||||
public:
|
||||
PerfRecordItraceStartData data_;
|
||||
PerfRecordItraceStart() = default;
|
||||
void Init(uint8_t *data, const perf_event_attr&) override;
|
||||
|
||||
explicit PerfRecordItraceStart(uint8_t *p);
|
||||
bool GetBinary(std::vector<uint8_t> &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<PerfRecordLostSamplesData, PERF_RECORD_TYPE_MMAP> {
|
||||
public:
|
||||
PerfRecordLostSamplesData data_;
|
||||
PerfRecordLostSamples() = default;
|
||||
void Init(uint8_t *data, const perf_event_attr&) override;
|
||||
|
||||
explicit PerfRecordLostSamples(uint8_t *p);
|
||||
bool GetBinary(std::vector<uint8_t> &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<PerfRecordSwitchData, PERF_RECORD_TYPE_MMAP> {
|
||||
public:
|
||||
PerfRecordSwitchData data_;
|
||||
explicit PerfRecordSwitch(uint8_t *p);
|
||||
PerfRecordSwitch() = default;
|
||||
void Init(uint8_t *data, const perf_event_attr&) override;
|
||||
|
||||
bool GetBinary(std::vector<uint8_t> &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<PerfRecordSwitchCpuWideData, PERF_RECORD_TYPE_MMAP> {
|
||||
public:
|
||||
PerfRecordSwitchCpuWideData data_;
|
||||
explicit PerfRecordSwitchCpuWide(uint8_t *p);
|
||||
PerfRecordSwitchCpuWide() = default;
|
||||
void Init(uint8_t *data, const perf_event_attr&) override;
|
||||
|
||||
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
||||
void DumpData(int indent) const override;
|
||||
};
|
||||
|
||||
std::unique_ptr<PerfEventRecord> 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<PerfEventRecord> GetPerfSampleFromCache(const int type, uint8_t *p,
|
||||
const perf_event_attr &attr);
|
||||
std::unique_ptr<PerfEventRecord> GetPerfSampleFromCacheMain(const int type, uint8_t *p,
|
||||
const perf_event_attr &attr);
|
||||
private:
|
||||
static thread_local std::unordered_map<PerfRecordType, PerfEventRecord*> recordMap_;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void PushToBinary(bool condition, uint8_t *&p, const T &v);
|
||||
|
@ -443,7 +443,7 @@ public:
|
||||
};
|
||||
using StatCallBack =
|
||||
std::function<void(const std::map<std::string, std::unique_ptr<PerfEvents::CountEvent>> &)>;
|
||||
using RecordCallBack = std::function<bool(std::unique_ptr<PerfEventRecord>)>;
|
||||
using RecordCallBack = std::function<bool(PerfEventRecord&)>;
|
||||
|
||||
void SetStatCallBack(StatCallBack reportCallBack);
|
||||
void SetRecordCallBack(RecordCallBack recordCallBack);
|
||||
|
@ -26,7 +26,7 @@
|
||||
namespace OHOS {
|
||||
namespace Developtools {
|
||||
namespace HiPerf {
|
||||
using ProcessRecordCB = const std::function<bool(std::unique_ptr<PerfEventRecord> record)>;
|
||||
using ProcessRecordCB = const std::function<bool(PerfEventRecord& record)>;
|
||||
// read record from data file, like perf.data.
|
||||
// format of file follow
|
||||
// tools/perf/Documentation/perf.data-file-format.txt
|
||||
|
@ -61,7 +61,7 @@ public:
|
||||
uint GetRecordCount() const;
|
||||
std::chrono::microseconds writeTimes_ = std::chrono::microseconds::zero();
|
||||
|
||||
using ProcessRecordCB = const std::function<bool(std::unique_ptr<PerfEventRecord> record)>;
|
||||
using ProcessRecordCB = const std::function<bool(PerfEventRecord& record)>;
|
||||
bool ReadDataSection(ProcessRecordCB &callback);
|
||||
bool ReadRecords(ProcessRecordCB &callback);
|
||||
bool Read(void *buf, size_t len);
|
||||
|
@ -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<PerfRecordSample> &sample);
|
||||
void DumpCallChain(int indent, PerfRecordSample& sample);
|
||||
void DumpFeaturePortion(int indent = 0);
|
||||
void DumpUniqueStackTableNode(int indent, const PerfFileSectionUniStackTable &uniStackTable);
|
||||
void ExprotUserData(std::unique_ptr<PerfEventRecord> &record);
|
||||
void ExprotUserData(PerfEventRecord& record);
|
||||
void ExprotUserStack(const PerfRecordSample &recordSample);
|
||||
void PrintHeaderInfo(const int &indent);
|
||||
void PrintSymbolFile(const int &indent, const SymbolFileStruct &symbolFileStruct);
|
||||
|
@ -303,8 +303,8 @@ private:
|
||||
bool isSpe_ = false;
|
||||
|
||||
// callback to process record
|
||||
bool ProcessRecord(std::unique_ptr<PerfEventRecord>);
|
||||
bool SaveRecord(std::unique_ptr<PerfEventRecord>, 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<PerfEventRecord> record);
|
||||
bool CollectionSymbol(PerfEventRecord& record);
|
||||
void CollectSymbol(PerfRecordSample *sample);
|
||||
bool SetPerfLimit(const std::string& file, int value, std::function<bool (int, int)> const& cmd,
|
||||
const std::string& param);
|
||||
|
@ -107,7 +107,7 @@ public:
|
||||
bool ParseOption(std::vector<std::string> &args) override;
|
||||
void DumpOptions(void) const override;
|
||||
static bool RegisterSubCommandReport(void);
|
||||
bool RecordCallBack(std::unique_ptr<PerfEventRecord> record);
|
||||
bool RecordCallBack(PerfEventRecord& record);
|
||||
|
||||
~SubCommandReport();
|
||||
|
||||
|
@ -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<bool(std::unique_ptr<PerfEventRecord>)>;
|
||||
using RecordCallBack = std::function<bool(PerfEventRecord&)>;
|
||||
using CollectSymbolCallBack = std::function<void(PerfRecordSample*)>;
|
||||
|
||||
void SetRecordMode(RecordCallBack recordCallBack);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -117,16 +117,16 @@ void PerfEvents::ReadRecordsFromSpeMmaps(MmapFd& mmapFd, u64 auxOffset, u64 auxS
|
||||
arm_spe_reference(), cpu, tid, cpu, pid);
|
||||
static std::vector<u8> 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
|
||||
|
@ -276,20 +276,20 @@ bool PerfFileReader::ReadRecord(ProcessRecordCB &callback)
|
||||
}
|
||||
}
|
||||
uint8_t *data = buf;
|
||||
std::unique_ptr<PerfEventRecord> record = GetPerfEventRecord(
|
||||
PerfEventRecord& record = PerfEventRecordFactory::GetPerfEventRecord(
|
||||
static_cast<perf_event_type>(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<PerfFileSectionUniStackTable>(feature, (char *)&buf[0], buf.size()));
|
||||
PerfRecordSample::dumpRemoveStack_ = true;
|
||||
PerfRecordSample::SetDumpRemoveStack(true);
|
||||
} else {
|
||||
HLOGW("still not imp how to process with feature %d", feature);
|
||||
}
|
||||
|
@ -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<u8> 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<perf_event_type>(header->type),
|
||||
PerfEventRecord& record = PerfEventRecordFactory::GetPerfEventRecord(static_cast<perf_event_type>(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 {
|
||||
|
@ -401,13 +401,13 @@ void SubCommandDump::ExprotUserStack(const PerfRecordSample &recordSample)
|
||||
}
|
||||
}
|
||||
|
||||
void SubCommandDump::ExprotUserData(std::unique_ptr<PerfEventRecord> &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<PerfRecordSample *>(record.get());
|
||||
PerfRecordSample* recordSample = static_cast<PerfRecordSample*>(&record);
|
||||
ExprotUserStack(*recordSample);
|
||||
|
||||
std::string userData =
|
||||
@ -423,14 +423,14 @@ void SubCommandDump::ExprotUserData(std::unique_ptr<PerfEventRecord> &record)
|
||||
}
|
||||
}
|
||||
|
||||
void SubCommandDump::DumpCallChain(int indent, std::unique_ptr<PerfRecordSample> &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<PerfRecordSample>
|
||||
void SubCommandDump::DumpDataPortion(int indent)
|
||||
{
|
||||
int recordCount = 0;
|
||||
auto recordcCallback = [&](std::unique_ptr<PerfEventRecord> 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<PerfRecordSample> sample(
|
||||
static_cast<PerfRecordSample *>(record.release()));
|
||||
DumpCallChain(indent, sample);
|
||||
if (record.GetType() == PERF_RECORD_SAMPLE) {
|
||||
DumpCallChain(indent, static_cast<PerfRecordSample&>(record));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -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<PerfEventRecord> 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<PerfEventRecord> 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<PerfEventRecord> 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<PerfEventRecord> 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<PerfEventRecord> 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<microseconds>(steady_clock::now() - startTime);
|
||||
#endif
|
||||
return SaveRecord(std::move(record), true);
|
||||
return SaveRecord(record, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SubCommandRecord::SaveRecord(std::unique_ptr<PerfEventRecord> 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<PerfEventRecord> 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<microseconds>(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<PerfEventRecord> 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<PerfRecordSample &>(*record));
|
||||
virtualRuntime_.UnwindFromRecord(static_cast<PerfRecordSample&>(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<PerfEventRecord> record)
|
||||
bool SubCommandRecord::CollectionSymbol(PerfEventRecord& record)
|
||||
{
|
||||
CHECK_TRUE(record == nullptr, false, 0, "");
|
||||
if (record->GetType() == PERF_RECORD_SAMPLE) {
|
||||
PerfRecordSample *sample = static_cast<PerfRecordSample *>(record.get());
|
||||
CHECK_TRUE(record.GetNameP() == nullptr, false, 0, "");
|
||||
if (record.GetType() == PERF_RECORD_SAMPLE) {
|
||||
PerfRecordSample* sample = static_cast<PerfRecordSample*>(&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<PerfRecordAuxtrace *>(record.get());
|
||||
if (isSpe_ && record.GetType() == PERF_RECORD_AUXTRACE) {
|
||||
PerfRecordAuxtrace* sample = static_cast<PerfRecordAuxtrace*>(&record);
|
||||
virtualRuntime_.SymbolSpeRecord(*sample);
|
||||
}
|
||||
|
||||
@ -1694,7 +1678,7 @@ bool SubCommandRecord::CollectionSymbol(std::unique_ptr<PerfEventRecord> 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<PerfEventRecord> record) -> bool {
|
||||
return this->CollectionSymbol(std::move(record));
|
||||
[this] (PerfEventRecord& record) -> bool {
|
||||
return this->CollectionSymbol(record);
|
||||
});
|
||||
}
|
||||
#if USE_COLLECT_SYMBOLIC
|
||||
|
@ -223,13 +223,13 @@ void SubCommandReport::ProcessSample(std::unique_ptr<PerfRecordSample> &sample)
|
||||
}
|
||||
}
|
||||
|
||||
bool SubCommandReport::RecordCallBack(std::unique_ptr<PerfEventRecord> 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<PerfRecordSample> sample(static_cast<PerfRecordSample *>(record.release()));
|
||||
if (record.GetType() == PERF_RECORD_SAMPLE) {
|
||||
std::unique_ptr<PerfRecordSample> sample(new PerfRecordSample(static_cast<PerfRecordSample&>(record)));
|
||||
std::unique_ptr<PerfRecordSample> prevSample = nullptr;
|
||||
if (cpuOffMode_) {
|
||||
auto prevIt = prevSampleCache_.find(sample->data_.tid);
|
||||
@ -264,7 +264,7 @@ bool SubCommandReport::RecordCallBack(std::unique_ptr<PerfEventRecord> 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<PerfEventRecord> record) -> bool {
|
||||
return this->RecordCallBack(std::move(record));
|
||||
[this] (PerfEventRecord& record) -> bool {
|
||||
return this->RecordCallBack(record);
|
||||
});
|
||||
if (cpuOffMode_) {
|
||||
FlushCacheRecord();
|
||||
|
@ -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<PerfRecordComm>(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<PerfRecordMmap>(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<PerfRecordMmap>(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<PerfRecordMmap2> mmap2FirstSeg =
|
||||
std::make_unique<PerfRecordMmap2>(recordMmap2.inKernel(), recordMmap2.data_.pid, recordMmap2.data_.tid,
|
||||
std::make_unique<PerfRecordMmap2>(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<PerfRecordMmap2> mmap2FirstSeg =
|
||||
std::make_unique<PerfRecordMmap2>(recordMmap2.inKernel(), recordMmap2.data_.pid, recordMmap2.data_.tid,
|
||||
std::make_unique<PerfRecordMmap2>(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<PerfRecordMmap2> mmap2SecondSegment =
|
||||
std::make_unique<PerfRecordMmap2>(recordMmap2.inKernel(), recordMmap2.data_.pid, recordMmap2.data_.tid,
|
||||
std::make_unique<PerfRecordMmap2>(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<PerfRecordMmap>(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<PerfRecordMmap>(false, devhostPid_, devhostPid_,
|
||||
map->begin, map->end - map->begin,
|
||||
0, map->name);
|
||||
recordCallBack_(std::move(record));
|
||||
recordCallBack_(*record);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user