mirror of
https://gitee.com/openharmony/developtools_hiperf
synced 2024-11-23 07:29:42 +00:00
Merge branch 'master' of gitee.com:openharmony/developtools_hiperf into master
Signed-off-by: wenlong_12 <wenlong12@huawei.com>
This commit is contained in:
commit
e5f40dc795
@ -23,6 +23,7 @@
|
||||
#include <string>
|
||||
#include <sys/types.h>
|
||||
#include <unique_fd.h>
|
||||
#include <unordered_map>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
#include <linux/perf_event.h>
|
||||
@ -39,63 +40,34 @@ namespace OHOS {
|
||||
namespace Developtools {
|
||||
namespace HiPerf {
|
||||
using namespace OHOS::HiviewDFX;
|
||||
using PerfRecordType = int32_t;
|
||||
|
||||
static constexpr uint32_t RECORD_SIZE_LIMIT = 65535;
|
||||
static constexpr uint32_t RECORD_SIZE_LIMIT_SPE = 524288; // auxMmapPages_ * pageSize_
|
||||
|
||||
static constexpr char PERF_RECORD_TYPE_AUXTRACE[] = "auxtrace";
|
||||
static constexpr char PERF_RECORD_TYPE_SAMPLE[] = "sample";
|
||||
static constexpr char PERF_RECORD_TYPE_MMAP[] = "mmap";
|
||||
static constexpr char PERF_RECORD_TYPE_MMAP2[] = "mmap2";
|
||||
static constexpr char PERF_RECORD_TYPE_LOST[] = "lost";
|
||||
static constexpr char PERF_RECORD_TYPE_COMM[] = "comm";
|
||||
static constexpr char PERF_RECORD_TYPE_EXIT[] = "exit";
|
||||
static constexpr char PERF_RECORD_TYPE_THROTTLE[] = "throttle";
|
||||
static constexpr char PERF_RECORD_TYPE_UNTHROTTLE[] = "unthrottle";
|
||||
static constexpr char PERF_RECORD_TYPE_FORK[] = "fork";
|
||||
static constexpr char PERF_RECORD_TYPE_READ[] = "read";
|
||||
static constexpr char PERF_RECORD_TYPE_AUX[] = "aux";
|
||||
static constexpr char PERF_RECORD_TYPE_ITRACESTART[] = "itraceStart";
|
||||
static constexpr char PERF_RECORD_TYPE_LOSTSAMPLE[] = "lostSamples";
|
||||
static constexpr char PERF_RECORD_TYPE_SWITCH[] = "switch";
|
||||
static constexpr char PERF_RECORD_TYPE_SWITCHCPUWIDE[] = "switchCpuWide";
|
||||
static constexpr char* PERF_RECORD_TYPE_NULL = nullptr;
|
||||
|
||||
enum perf_event_hiperf_ext_type {
|
||||
PERF_RECORD_AUXTRACE = 71,
|
||||
PERF_RECORD_HIPERF_CALLSTACK = UINT32_MAX / 2,
|
||||
};
|
||||
|
||||
struct CallFrame {
|
||||
uint64_t ip_ = 0; // pc
|
||||
uint64_t sp_ = 0; // sp
|
||||
int32_t symbolFileIndex_ = -1; // symbolFileIndex_, symbols file index, used to report protobuf file
|
||||
uint64_t vaddrInFile_ = 0; // funcOffset, vaddr of symbol in file
|
||||
uint64_t offsetToVaddr_ = 0; // mapOffset, offset of ip to vaddr
|
||||
int32_t symbolIndex_ = -1; // index, symbols index , should update after sort
|
||||
std::string_view symbolName_; // funcName
|
||||
std::string_view filePath_; // mapName, lib path , elf path
|
||||
|
||||
CallFrame(uint64_t ip, uint64_t sp = 0) : ip_(ip), sp_(sp) {}
|
||||
|
||||
// this is for ut test
|
||||
CallFrame(uint64_t ip, uint64_t vaddrInFile, const char *name, const char *filePath)
|
||||
: ip_(ip), vaddrInFile_(vaddrInFile), symbolName_(name), filePath_(filePath)
|
||||
{
|
||||
}
|
||||
bool operator==(const CallFrame &b) const
|
||||
{
|
||||
return (ip_ == b.ip_) && (sp_ == b.sp_);
|
||||
}
|
||||
bool operator!=(const CallFrame &b) const
|
||||
{
|
||||
return (ip_ != b.ip_) || (sp_ != b.sp_);
|
||||
}
|
||||
std::string ToString() const
|
||||
{
|
||||
return StringPrintf("ip: 0x%016llx sp: 0x%016llx", ip_, sp_);
|
||||
}
|
||||
std::string ToSymbolString() const
|
||||
{
|
||||
std::string output = StringPrintf(" 0x%016llx : ", ip_);
|
||||
output.append(symbolName_);
|
||||
if (vaddrInFile_ != 0) {
|
||||
output += StringPrintf("[0x%016llx:0x%016llx][+0x%llx]", ip_ - offsetToVaddr_,
|
||||
vaddrInFile_, offsetToVaddr_);
|
||||
}
|
||||
|
||||
output.append("@");
|
||||
output.append(filePath_);
|
||||
if (symbolIndex_ != -1) {
|
||||
output.append(":");
|
||||
output.append(std::to_string(symbolIndex_));
|
||||
}
|
||||
return output;
|
||||
}
|
||||
};
|
||||
|
||||
struct AttrWithId {
|
||||
perf_event_attr attr;
|
||||
std::vector<uint64_t> ids;
|
||||
@ -104,50 +76,39 @@ struct AttrWithId {
|
||||
|
||||
class PerfEventRecord {
|
||||
public:
|
||||
PerfEventRecord(const PerfEventRecord &) = delete;
|
||||
PerfEventRecord &operator=(const PerfEventRecord &) = delete;
|
||||
struct perf_event_header header_ = {};
|
||||
|
||||
struct perf_event_header header;
|
||||
const std::string name_ {};
|
||||
virtual const char* GetName() const = 0;
|
||||
virtual void Init(uint8_t* data, const perf_event_attr& attr) = 0;
|
||||
|
||||
PerfEventRecord(perf_event_type type, bool inKernel, const std::string &name);
|
||||
PerfEventRecord(perf_event_hiperf_ext_type type, const std::string &name);
|
||||
|
||||
PerfEventRecord(uint8_t *p, const std::string &name);
|
||||
|
||||
virtual ~PerfEventRecord() {}
|
||||
virtual ~PerfEventRecord() = default;
|
||||
|
||||
virtual size_t GetSize() const
|
||||
{
|
||||
return header.size;
|
||||
return header_.size;
|
||||
};
|
||||
size_t GetHeaderSize() const
|
||||
{
|
||||
return sizeof(header);
|
||||
return sizeof(header_);
|
||||
};
|
||||
void GetHeaderBinary(std::vector<uint8_t> &buf) const;
|
||||
|
||||
uint32_t GetType() const
|
||||
{
|
||||
return header.type;
|
||||
return header_.type;
|
||||
};
|
||||
uint16_t GetMisc() const
|
||||
{
|
||||
return header.misc;
|
||||
return header_.misc;
|
||||
};
|
||||
bool inKernel()
|
||||
bool InKernel()
|
||||
{
|
||||
return header.misc & PERF_RECORD_MISC_KERNEL;
|
||||
return header_.misc & PERF_RECORD_MISC_KERNEL;
|
||||
}
|
||||
bool inUser()
|
||||
bool InUser()
|
||||
{
|
||||
return header.misc & PERF_RECORD_MISC_USER;
|
||||
return header_.misc & PERF_RECORD_MISC_USER;
|
||||
}
|
||||
const std::string &GetName() const
|
||||
{
|
||||
return name_;
|
||||
};
|
||||
|
||||
// to support --exclude-hiperf, return sample_id.pid to filter record,
|
||||
virtual pid_t GetPid() const
|
||||
{
|
||||
@ -157,7 +118,42 @@ public:
|
||||
virtual bool GetBinary(std::vector<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 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 <typename DataType, const char* RECORD_TYPE_NAME>
|
||||
class PerfEventRecordTemplate : public PerfEventRecord {
|
||||
public:
|
||||
PerfEventRecordTemplate(const PerfEventRecordTemplate&) = delete;
|
||||
PerfEventRecordTemplate& operator=(const PerfEventRecordTemplate&) = delete;
|
||||
|
||||
DataType data_ = {};
|
||||
const char* GetName() const override final
|
||||
{
|
||||
return RECORD_TYPE_NAME;
|
||||
}
|
||||
|
||||
PerfEventRecordTemplate() = default;
|
||||
virtual ~PerfEventRecordTemplate() = default;
|
||||
void Init(uint8_t* p, const perf_event_attr& = {}) override
|
||||
{
|
||||
InitHeader(p);
|
||||
|
||||
size_t dataSize = GetSize();
|
||||
if (dataSize >= sizeof(header_)) {
|
||||
size_t copySize = dataSize - sizeof(header_);
|
||||
if (memcpy_s(reinterpret_cast<uint8_t*>(&data_), sizeof(data_), p + sizeof(header_), copySize) != 0) {
|
||||
HLOGE("init perf record memcpy_s failed!");
|
||||
}
|
||||
} else {
|
||||
HLOGE("init perf record failed!");
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// define convert from linux/perf_event.h
|
||||
@ -171,12 +167,12 @@ constexpr __u64 SAMPLE_TYPE = PERF_SAMPLE_IP | SAMPLE_ID | PERF_SAMPLE_PERIOD;
|
||||
constexpr __u32 MIN_SAMPLE_STACK_SIZE = 8;
|
||||
constexpr __u32 MAX_SAMPLE_STACK_SIZE = 65528;
|
||||
|
||||
class PerfRecordAuxtrace : public PerfEventRecord {
|
||||
class PerfRecordAuxtrace : public PerfEventRecordTemplate<PerfRecordAuxtraceData, PERF_RECORD_TYPE_AUXTRACE> {
|
||||
public:
|
||||
PerfRecordAuxtraceData data_;
|
||||
u8* rawData_ = nullptr;
|
||||
explicit PerfRecordAuxtrace(uint8_t *p);
|
||||
PerfRecordAuxtrace() = default;
|
||||
PerfRecordAuxtrace(u64 size, u64 offset, u64 reference, u32 idx, u32 tid, u32 cpu, u32 pid);
|
||||
void Init(uint8_t* data, const perf_event_attr& attr) override;
|
||||
|
||||
bool GetBinary1(std::vector<uint8_t> &buf) const;
|
||||
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
||||
@ -186,12 +182,9 @@ public:
|
||||
virtual 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;
|
||||
PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff,
|
||||
const std::string &filename);
|
||||
|
||||
@ -200,11 +193,10 @@ public:
|
||||
void DumpLog(const std::string &prefix) const override;
|
||||
};
|
||||
|
||||
class PerfRecordMmap2 : public PerfEventRecord {
|
||||
class PerfRecordMmap2 : public PerfEventRecordTemplate<PerfRecordMmap2Data, PERF_RECORD_TYPE_MMAP2> {
|
||||
public:
|
||||
PerfRecordMmap2Data data_;
|
||||
|
||||
explicit PerfRecordMmap2(uint8_t *p);
|
||||
PerfRecordMmap2() = default;
|
||||
|
||||
PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff, u32 maj, u32 min,
|
||||
u64 ino, u32 prot, u32 flags, const std::string &filename);
|
||||
@ -217,31 +209,28 @@ public:
|
||||
bool discard_ = false;
|
||||
};
|
||||
|
||||
class PerfRecordLost : public PerfEventRecord {
|
||||
class PerfRecordLost : public PerfEventRecordTemplate<PerfRecordLostData, PERF_RECORD_TYPE_LOST> {
|
||||
public:
|
||||
PerfRecordLostData data_;
|
||||
|
||||
explicit PerfRecordLost(uint8_t *p);
|
||||
PerfRecordLost() = default;
|
||||
|
||||
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")
|
||||
{
|
||||
PerfEventRecord::Init(PERF_RECORD_LOST, inKernel);
|
||||
data_.id = id;
|
||||
data_.lost = lost;
|
||||
header.size = sizeof(header) + sizeof(data_);
|
||||
header_.size = sizeof(header_) + sizeof(data_);
|
||||
}
|
||||
};
|
||||
|
||||
class PerfRecordComm : public PerfEventRecord {
|
||||
class PerfRecordComm : public PerfEventRecordTemplate<PerfRecordCommData, PERF_RECORD_TYPE_COMM> {
|
||||
public:
|
||||
PerfRecordCommData data_;
|
||||
|
||||
explicit PerfRecordComm(uint8_t *p);
|
||||
|
||||
PerfRecordComm() = default;
|
||||
PerfRecordComm(bool inKernel, u32 pid, u32 tid, const std::string &comm);
|
||||
|
||||
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
||||
@ -249,9 +238,8 @@ public:
|
||||
void DumpLog(const std::string &prefix) const override;
|
||||
};
|
||||
|
||||
class PerfRecordSample : public PerfEventRecord {
|
||||
class PerfRecordSample : public PerfEventRecordTemplate<PerfRecordSampleData, PERF_RECORD_TYPE_SAMPLE> {
|
||||
public:
|
||||
PerfRecordSampleData data_ = {};
|
||||
uint64_t sampleType_ = SAMPLE_TYPE;
|
||||
uint64_t skipKernel_ = 0;
|
||||
uint64_t skipPid_ = 0;
|
||||
@ -262,11 +250,15 @@ public:
|
||||
static std::vector<DfxFrame> callFrames_;
|
||||
static 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;
|
||||
@ -279,56 +271,50 @@ public:
|
||||
|
||||
// only for UT
|
||||
PerfRecordSample(bool inKernel, u32 pid, u32 tid, u64 period = 0, u64 time = 0, u64 id = 0)
|
||||
: PerfEventRecord(PERF_RECORD_SAMPLE, inKernel, "sample")
|
||||
{
|
||||
PerfEventRecord::Init(PERF_RECORD_SAMPLE, inKernel);
|
||||
Clean();
|
||||
data_.pid = pid;
|
||||
data_.tid = tid;
|
||||
data_.period = period;
|
||||
data_.time = time;
|
||||
data_.id = 0;
|
||||
header.size = sizeof(header) + sizeof(data_);
|
||||
};
|
||||
header_.size = sizeof(header_) + sizeof(data_);
|
||||
}
|
||||
|
||||
pid_t GetUstackServerPid();
|
||||
pid_t GetServerPidof(unsigned int ipNr);
|
||||
private:
|
||||
static bool dumpRemoveStack_;
|
||||
};
|
||||
|
||||
class PerfRecordExit : public PerfEventRecord {
|
||||
class PerfRecordExit : public PerfEventRecordTemplate<PerfRecordExitData, PERF_RECORD_TYPE_EXIT> {
|
||||
public:
|
||||
PerfRecordExitData data_;
|
||||
|
||||
explicit PerfRecordExit(uint8_t *p);
|
||||
PerfRecordExit() = default;
|
||||
|
||||
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_THROTTLE> {
|
||||
public:
|
||||
PerfRecordThrottleData data_;
|
||||
|
||||
PerfRecordThrottle(uint8_t *p);
|
||||
PerfRecordThrottle() = default;
|
||||
|
||||
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_UNTHROTTLE> {
|
||||
public:
|
||||
PerfRecordThrottleData data_;
|
||||
|
||||
explicit PerfRecordUnthrottle(uint8_t *p);
|
||||
PerfRecordUnthrottle() = default;
|
||||
|
||||
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_FORK> {
|
||||
public:
|
||||
PerfRecordForkData data_;
|
||||
|
||||
explicit PerfRecordFork(uint8_t *p);
|
||||
PerfRecordFork() = default;
|
||||
|
||||
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
||||
void DumpData(int indent) const override;
|
||||
@ -337,11 +323,10 @@ public:
|
||||
/*
|
||||
This record indicates a read event.
|
||||
*/
|
||||
class PerfRecordRead : public PerfEventRecord {
|
||||
class PerfRecordRead : public PerfEventRecordTemplate<PerfRecordReadData, PERF_RECORD_TYPE_READ> {
|
||||
public:
|
||||
PerfRecordReadData data_;
|
||||
PerfRecordRead() = default;
|
||||
|
||||
explicit PerfRecordRead(uint8_t *p);
|
||||
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
||||
void DumpData(int indent) const override;
|
||||
};
|
||||
@ -365,12 +350,11 @@ public:
|
||||
if set, then the data returned has
|
||||
overwritten previous data.
|
||||
*/
|
||||
class PerfRecordAux : public PerfEventRecord {
|
||||
class PerfRecordAux : public PerfEventRecordTemplate<PerfRecordAuxData, PERF_RECORD_TYPE_AUX> {
|
||||
public:
|
||||
uint64_t sampleType_ = SAMPLE_ID;
|
||||
PerfRecordAuxData data_;
|
||||
PerfRecordAux() = default;
|
||||
|
||||
explicit PerfRecordAux(uint8_t *p);
|
||||
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
||||
void DumpData(int indent) const override;
|
||||
};
|
||||
@ -386,11 +370,10 @@ public:
|
||||
tid thread ID of the thread starting an instruction
|
||||
trace.
|
||||
*/
|
||||
class PerfRecordItraceStart : public PerfEventRecord {
|
||||
class PerfRecordItraceStart : public PerfEventRecordTemplate<PerfRecordItraceStartData, PERF_RECORD_TYPE_ITRACESTART> {
|
||||
public:
|
||||
PerfRecordItraceStartData data_;
|
||||
PerfRecordItraceStart() = default;
|
||||
|
||||
explicit PerfRecordItraceStart(uint8_t *p);
|
||||
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
||||
void DumpData(int indent) const override;
|
||||
};
|
||||
@ -400,11 +383,10 @@ public:
|
||||
record indicates some number of samples that may have
|
||||
been lost.
|
||||
*/
|
||||
class PerfRecordLostSamples : public PerfEventRecord {
|
||||
class PerfRecordLostSamples : public PerfEventRecordTemplate<PerfRecordLostSamplesData, PERF_RECORD_TYPE_LOSTSAMPLE> {
|
||||
public:
|
||||
PerfRecordLostSamplesData data_;
|
||||
PerfRecordLostSamples() = default;
|
||||
|
||||
explicit PerfRecordLostSamples(uint8_t *p);
|
||||
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
||||
void DumpData(int indent) const override;
|
||||
};
|
||||
@ -415,12 +397,12 @@ public:
|
||||
indicates whether it was a context switch into or away
|
||||
from the current process.
|
||||
*/
|
||||
class PerfRecordSwitch : public PerfEventRecord {
|
||||
class PerfRecordSwitch : public PerfEventRecordTemplate<PerfRecordSwitchData, PERF_RECORD_TYPE_SWITCH> {
|
||||
public:
|
||||
PerfRecordSwitchData data_;
|
||||
explicit PerfRecordSwitch(uint8_t *p);
|
||||
PerfRecordSwitch() = default;
|
||||
|
||||
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
||||
void DumpData([[maybe_unused]] int indent) const override {};
|
||||
void DumpData(int) const override {};
|
||||
};
|
||||
|
||||
/*
|
||||
@ -441,20 +423,30 @@ public:
|
||||
The thread ID of the previous (if switching in)
|
||||
or next (if switching out) thread on the CPU.
|
||||
*/
|
||||
class PerfRecordSwitchCpuWide : public PerfEventRecord {
|
||||
class PerfRecordSwitchCpuWide
|
||||
: public PerfEventRecordTemplate<PerfRecordSwitchCpuWideData, PERF_RECORD_TYPE_SWITCHCPUWIDE> {
|
||||
public:
|
||||
PerfRecordSwitchCpuWideData data_;
|
||||
explicit PerfRecordSwitchCpuWide(uint8_t *p);
|
||||
PerfRecordSwitchCpuWide() = default;
|
||||
|
||||
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,
|
||||
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);
|
||||
class PerfRecordNull : public PerfEventRecordTemplate<PerfRecordSwitchCpuWideData, PERF_RECORD_TYPE_NULL> {
|
||||
public:
|
||||
PerfRecordNull() = default;
|
||||
|
||||
bool GetBinary(std::vector<uint8_t>&) const override { return false; };
|
||||
void DumpData(int indent) const override {};
|
||||
};
|
||||
|
||||
class PerfEventRecordFactory {
|
||||
public:
|
||||
static PerfEventRecord& GetPerfEventRecord(PerfRecordType type, uint8_t* data,
|
||||
const perf_event_attr& attr);
|
||||
private:
|
||||
static thread_local std::unordered_map<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,10 +61,11 @@ 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);
|
||||
void SetWriteRecordStat(bool isWrite);
|
||||
|
||||
private:
|
||||
std::string fileBuffer_;
|
||||
|
@ -284,7 +284,6 @@ struct SpeDecoder {
|
||||
struct SpePkt packet;
|
||||
};
|
||||
|
||||
struct SpeDecoder *SpeDecoderNew(struct SpeParams *params);
|
||||
struct SpeDecoder *SpeDecoderDataNew(const unsigned char *speBuf, size_t speLen);
|
||||
void SpeDecoderFree(struct SpeDecoder *decoder);
|
||||
|
||||
|
@ -80,7 +80,7 @@ public:
|
||||
};
|
||||
|
||||
// called from main
|
||||
static bool RegisterSubCommand(std::string, std::unique_ptr<SubCommand>);
|
||||
static bool RegisterSubCommand(const std::string&, std::unique_ptr<SubCommand>);
|
||||
|
||||
// get some cmd
|
||||
static const std::map<std::string, std::unique_ptr<SubCommand>> &GetSubCommands();
|
||||
|
@ -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, const 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(const PerfEventRecord& record, bool ptrReleaseFlag = false);
|
||||
|
||||
// file format like as 0,1-3,4-6,7,8
|
||||
uint32_t GetCountFromFile(const std::string &fileName);
|
||||
@ -327,7 +327,7 @@ private:
|
||||
void ReportTime();
|
||||
#endif
|
||||
|
||||
bool CollectionSymbol(std::unique_ptr<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();
|
||||
|
||||
|
@ -310,6 +310,7 @@ bool IsBeta();
|
||||
bool IsAllowProfilingUid();
|
||||
bool IsHiviewCall();
|
||||
bool PowerOfTwo(uint64_t n);
|
||||
bool IsNumeric(const std::string& str);
|
||||
|
||||
const std::string HMKERNEL = "HongMeng";
|
||||
|
||||
@ -344,29 +345,6 @@ bool IsArkJsFile(const std::string& filepath);
|
||||
std::string GetProcessName(int pid);
|
||||
bool NeedAdaptSandboxPath(char *filename, int pid, u16 &headerSize);
|
||||
bool NeedAdaptHMBundlePath(std::string& filename, const std::string& threadname);
|
||||
|
||||
template <typename Func>
|
||||
class ScopeGuard {
|
||||
public:
|
||||
explicit ScopeGuard(Func&& fn)
|
||||
: fn_(fn) {}
|
||||
~ScopeGuard()
|
||||
{
|
||||
fn_();
|
||||
}
|
||||
private:
|
||||
Func fn_;
|
||||
};
|
||||
|
||||
struct ScopeGuardOnExit {};
|
||||
template <typename Func>
|
||||
static inline ScopeGuard<Func> operator+(ScopeGuardOnExit, Func&& fn)
|
||||
{
|
||||
return ScopeGuard<Func>(std::forward<Func>(fn));
|
||||
}
|
||||
|
||||
#define ON_SCOPE_EXIT \
|
||||
auto __onGuardExit__ = ScopeGuardOnExit{} + [&]
|
||||
} // namespace HiPerf
|
||||
} // namespace Developtools
|
||||
} // namespace OHOS
|
||||
|
@ -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);
|
||||
|
@ -14,6 +14,7 @@
|
||||
*/
|
||||
#include "hiperf_client_napi.h"
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include "hiperf_hilog.h"
|
||||
#include "hiperf_client.h"
|
||||
@ -30,46 +31,44 @@ static std::unique_ptr<HiperfClient::Client> g_hiperfClient =
|
||||
static std::unique_ptr<HiperfClient::RecordOption> g_hiperfRecordOption =
|
||||
std::make_unique<HiperfClient::RecordOption>();
|
||||
|
||||
static std::vector<std::string> StringSplit(std::string source, const std::string &split = ",")
|
||||
static std::vector<std::string> StringSplit(const std::string& text, char delimiter = ',')
|
||||
{
|
||||
size_t pos = 0;
|
||||
std::vector<std::string> result;
|
||||
|
||||
// find
|
||||
while ((pos = source.find(split)) != std::string::npos) {
|
||||
// split
|
||||
std::string token = source.substr(0, pos);
|
||||
std::vector<std::string> tokens;
|
||||
std::string token;
|
||||
std::istringstream tokenStream(text);
|
||||
while (std::getline(tokenStream, token, delimiter)) {
|
||||
if (!token.empty()) {
|
||||
result.push_back(token);
|
||||
tokens.push_back(token);
|
||||
}
|
||||
source.erase(0, pos + split.length());
|
||||
}
|
||||
// add last token
|
||||
if (!source.empty()) {
|
||||
result.push_back(source);
|
||||
}
|
||||
return result;
|
||||
return tokens;
|
||||
}
|
||||
|
||||
static std::vector<int> StringSplitToInt(std::string source, const std::string &split = ",")
|
||||
static bool IsNumeric(const std::string& str)
|
||||
{
|
||||
size_t pos = 0;
|
||||
std::vector<int> result;
|
||||
std::istringstream iss(str);
|
||||
int number;
|
||||
char trailingCharacter;
|
||||
if (!(iss >> number)) {
|
||||
return false;
|
||||
}
|
||||
if (iss >> trailingCharacter) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// find
|
||||
while ((pos = source.find(split)) != std::string::npos) {
|
||||
// split
|
||||
std::string token = source.substr(0, pos);
|
||||
if (!token.empty()) {
|
||||
result.push_back(std::stoi(token));
|
||||
static std::vector<int> StringSplitToInt(const std::string& text, char delimiter = ',')
|
||||
{
|
||||
std::vector<int> tokens;
|
||||
std::string token;
|
||||
std::istringstream tokenStream(text);
|
||||
while (std::getline(tokenStream, token, delimiter)) {
|
||||
if (IsNumeric(token)) {
|
||||
tokens.push_back(std::stoi(token));
|
||||
}
|
||||
source.erase(0, pos + split.length());
|
||||
}
|
||||
// add last token
|
||||
if (!source.empty()) {
|
||||
result.push_back(std::stoi(source));
|
||||
}
|
||||
return result;
|
||||
return tokens;
|
||||
}
|
||||
|
||||
static std::string GetJsStringFromOption(const napi_env &env, const napi_callback_info &info)
|
||||
@ -85,7 +84,10 @@ static std::string GetJsStringFromOption(const napi_env &env, const napi_callbac
|
||||
|
||||
char value[PATH_MAX] = {0};
|
||||
size_t valueLen = 0;
|
||||
napi_get_value_string_utf8(env, args[0], value, sizeof(value), &valueLen);
|
||||
if (napi_get_value_string_utf8(env, args[0], value, sizeof(value), &valueLen) != napi_ok) {
|
||||
HIPERF_HILOGE(MODULE_JS_NAPI, "napi_get_value_string_utf8 failed.");
|
||||
return "";
|
||||
}
|
||||
HIPERF_HILOGD(MODULE_JS_NAPI, "%{public}s", value);
|
||||
return std::string(value);
|
||||
}
|
||||
|
@ -4021,7 +4021,6 @@ input{
|
||||
if (this.data) {
|
||||
if (this.reverse) {
|
||||
this.drawCReverse(
|
||||
0,
|
||||
this.c,
|
||||
1,
|
||||
{
|
||||
@ -4120,18 +4119,14 @@ input{
|
||||
return heatColor;
|
||||
}
|
||||
|
||||
drawCReverse = (parentEvents, c, dept, rect) => {
|
||||
drawCReverse = (c, dept, rect) => {
|
||||
let ctx = this.context;
|
||||
let offset = 0;
|
||||
if (parentEvents === 0) {
|
||||
parentEvents = c.reduce((acc, cur) => acc + cur.subEvents, 0);
|
||||
}
|
||||
for (let i = 0; i < c.length; i++) {
|
||||
let funName = this.getFunctionName(c[i].symbol);
|
||||
let funcId = c[i].symbol;
|
||||
let percent = c[i].subEvents * 100 / parentEvents;
|
||||
let percent = c[i].subEvents * 100 / (c.reduce((acc, cur) => acc + cur.subEvents, 0));
|
||||
let percent2 = c[i].subEvents * 100 / this.sumCount;
|
||||
if (percent2 < 0.1) continue // 过滤掉 百分比为0.1一下的节点
|
||||
let heatColor = this.getColor(percent2, funName);
|
||||
let w = rect.w * (percent / 100.0);
|
||||
if (w < 1) {
|
||||
@ -4164,13 +4159,8 @@ input{
|
||||
ctx.strokeStyle = `#000000`;
|
||||
ctx.strokeRect(_x, rect.y + 1, w - 1, rect.h);
|
||||
let statisticNum = this.getStatistics(c[i]);
|
||||
let count = this.getCount(c[i]);
|
||||
this.funcNameSpan.textContent = funName;
|
||||
if (this.type === 1 || this.type === 2 || this.type === 3) {
|
||||
this.panel.title = funName + ': [' + count + ' ' + statisticNum + ']';
|
||||
} else {
|
||||
this.panel.title = funName + ': [' + statisticNum + ']';
|
||||
}
|
||||
this.panel.title = funName + ': [' + statisticNum + ']';
|
||||
this.percentSpan.textContent = statisticNum;
|
||||
} else {
|
||||
if (this.mouseState === 'mouseUp') {
|
||||
@ -4187,7 +4177,7 @@ input{
|
||||
// 递归绘制子节点
|
||||
if (c[i].callStack && c[i].callStack.length > 0) {
|
||||
_rect.y = _rect.y + _rect.h;
|
||||
this.drawCReverse(c[i].subEvents, [i].callStack, dept + 1, _rect);
|
||||
this.drawCReverse(c[i].callStack, dept + 1, _rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4202,7 +4192,6 @@ input{
|
||||
let funcId = c[i].symbol;
|
||||
let percent = c[i].subEvents * 100 / parentEvents;// sumCount;
|
||||
let percent2 = c[i].subEvents * 100 / this.sumCount;
|
||||
if (percent2 < 0.1) continue // 过滤掉 百分比为0.1一下的节点
|
||||
let heatColor = this.getColor(percent2, funName);
|
||||
let w = rect.w * (percent / 100.0);
|
||||
if (w < 1) {
|
||||
@ -4420,7 +4409,7 @@ input{
|
||||
if (json.osVersion) {
|
||||
rows.push({key: 'OS Version', value: json.osVersion,time:''});
|
||||
}
|
||||
rows.push({key: 'Script Version', value: '1.0.0.240604',time:''});
|
||||
rows.push({key: 'Script Version', value: '1.0.0.241031',time:''});
|
||||
if (json.deviceCommandLine) {
|
||||
rows.push({key:'Record cmdline',value: json.deviceCommandLine,time:''});
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ const std::map<unw_error_t, const std::string> UNW_ERROR_MAP = {
|
||||
};
|
||||
const std::string CallStack::GetUnwErrorName(int error)
|
||||
{
|
||||
if (UNW_ERROR_MAP.count(static_cast<unw_error_t>(-error)) > 0) {
|
||||
if (UNW_ERROR_MAP.find(static_cast<unw_error_t>(-error)) != UNW_ERROR_MAP.end()) {
|
||||
return UNW_ERROR_MAP.at(static_cast<unw_error_t>(-error));
|
||||
} else {
|
||||
return "UNKNOW_UNW_ERROR";
|
||||
@ -292,7 +292,7 @@ int CallStack::AccessMem([[maybe_unused]] unw_addr_space_t as, unw_word_t addr,
|
||||
return -UNW_EUNSPEC;
|
||||
}
|
||||
|
||||
if (addr < unwindInfoPtr->callStack.stackPoint_ or
|
||||
if (addr < unwindInfoPtr->callStack.stackPoint_ ||
|
||||
addr + sizeof(unw_word_t) >= unwindInfoPtr->callStack.stackEnd_) {
|
||||
if (ReadVirtualThreadMemory(*unwindInfoPtr, addr, valuePoint)) {
|
||||
HLOGM("access_mem addr get val 0x%" UNW_WORD_PFLAG ", from mmap", *valuePoint);
|
||||
@ -540,8 +540,8 @@ size_t CallStack::DoExpandCallStack(std::vector<DfxFrame> &newCallFrames,
|
||||
{
|
||||
int maxCycle = 0;
|
||||
|
||||
if (expandLimit == 0 or newCallFrames.size() < expandLimit or
|
||||
cachedCallFrames.size() < expandLimit or
|
||||
if (expandLimit == 0 || newCallFrames.size() < expandLimit ||
|
||||
cachedCallFrames.size() < expandLimit ||
|
||||
cachedCallFrames.size() >= MAX_CALL_FRAME_UNWIND_SIZE) {
|
||||
HLOGM("expandLimit %zu not match new %zu cache %zu", expandLimit, newCallFrames.size(),
|
||||
cachedCallFrames.size());
|
||||
@ -777,7 +777,7 @@ int CallStack::AccessMem2(uintptr_t addr, uintptr_t *val, void *arg)
|
||||
"unwindInfoPtr is null or address overflow at 0x%" UNW_WORD_PFLAG " increase 0x%zu",
|
||||
addr, sizeof(uintptr_t));
|
||||
|
||||
if (addr < unwindInfoPtr->callStack.stackPoint_ or
|
||||
if (addr < unwindInfoPtr->callStack.stackPoint_ ||
|
||||
addr + sizeof(uintptr_t) >= unwindInfoPtr->callStack.stackEnd_) {
|
||||
if (ReadVirtualThreadMemory(*unwindInfoPtr, addr, val)) {
|
||||
HLOGM("access_mem addr get val 0x%" UNW_WORD_PFLAG ", from mmap", *val);
|
||||
|
@ -15,19 +15,15 @@
|
||||
|
||||
#include "debug_logger.h"
|
||||
|
||||
#include <ratio>
|
||||
|
||||
#include "option.h"
|
||||
#if defined(is_ohos) && is_ohos
|
||||
#include "hiperf_hilog.h"
|
||||
#endif
|
||||
|
||||
using namespace std::literals::chrono_literals;
|
||||
using namespace std::chrono;
|
||||
namespace OHOS {
|
||||
namespace Developtools {
|
||||
namespace HiPerf {
|
||||
DebugLogger::DebugLogger() : timeStamp_(steady_clock::now()), logPath_(DEFAULT_LOG_PATH)
|
||||
DebugLogger::DebugLogger() : timeStamp_(std::chrono::steady_clock::now()), logPath_(DEFAULT_LOG_PATH)
|
||||
{
|
||||
OpenLog();
|
||||
}
|
||||
@ -82,12 +78,12 @@ int DebugLogger::Log(DebugLevel level, const std::string &logTag, const char *fm
|
||||
{
|
||||
constexpr const int DEFAULT_STRING_BUF_SIZE = 4096;
|
||||
#ifdef HIPERF_DEBUG_TIME
|
||||
const auto startSprintf = steady_clock::now();
|
||||
const auto startSprintf = std::chrono::steady_clock::now();
|
||||
#endif
|
||||
const auto startTime = steady_clock::now();
|
||||
if (!ShouldLog(level, logTag) or logDisabled_ or fmt == nullptr) {
|
||||
const auto startTime = std::chrono::steady_clock::now();
|
||||
if (!ShouldLog(level, logTag) || logDisabled_ || fmt == nullptr) {
|
||||
#ifdef HIPERF_DEBUG_TIME
|
||||
logTimes_ += duration_cast<microseconds>(steady_clock::now() - startSprintf);
|
||||
logTimes_ += duration_cast<microseconds>(std::chrono::steady_clock::now() - startSprintf);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@ -99,9 +95,9 @@ int DebugLogger::Log(DebugLevel level, const std::string &logTag, const char *fm
|
||||
ret = vsnprintf_s(buffer.data(), buffer.size(), buffer.size() >= 1 ? buffer.size() - 1 : 0, fmt, va);
|
||||
va_end(va);
|
||||
#ifdef HIPERF_DEBUG_TIME
|
||||
logSprintfTimes_ += duration_cast<microseconds>(steady_clock::now() - startSprintf);
|
||||
logSprintfTimes_ += duration_cast<microseconds>(std::chrono::steady_clock::now() - startSprintf);
|
||||
#endif
|
||||
if ((mixLogOutput_ and level < LEVEL_FATAL) or level == LEVEL_FATAL) {
|
||||
if ((mixLogOutput_ && level < LEVEL_FATAL) || level == LEVEL_FATAL) {
|
||||
ret = fprintf(stdout, "%s", buffer.data()); // to the stdout
|
||||
}
|
||||
|
||||
@ -113,17 +109,17 @@ int DebugLogger::Log(DebugLevel level, const std::string &logTag, const char *fm
|
||||
} else if (file_ != nullptr) {
|
||||
std::lock_guard<std::recursive_mutex> lock(logMutex_);
|
||||
#ifdef HIPERF_DEBUG_TIME
|
||||
const auto startWriteTime = steady_clock::now();
|
||||
const auto startWriteTime = std::chrono::steady_clock::now();
|
||||
#endif
|
||||
milliseconds timeStamp = duration_cast<milliseconds>(startTime - timeStamp_);
|
||||
auto timeStamp = startTime - timeStamp_;
|
||||
fprintf(file_, "%05" PRId64 "ms %s", (int64_t)timeStamp.count(), buffer.data()); // to the file
|
||||
#ifdef HIPERF_DEBUG_TIME
|
||||
logWriteTimes_ += duration_cast<microseconds>(steady_clock::now() - startWriteTime);
|
||||
logWriteTimes_ += duration_cast<microseconds>(std::chrono::steady_clock::now() - startWriteTime);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HIPERF_DEBUG_TIME
|
||||
logTimes_ += duration_cast<microseconds>(steady_clock::now() - startTime);
|
||||
logTimes_ += duration_cast<microseconds>(std::chrono::steady_clock::now() - startTime);
|
||||
logCount_++;
|
||||
#endif
|
||||
if (level == LEVEL_FATAL && exitOnFatal_) {
|
||||
@ -170,7 +166,7 @@ bool DebugLogger::SetLogPath(const std::string &newLogPath)
|
||||
{
|
||||
// make sure not write happend when rename
|
||||
std::lock_guard<std::recursive_mutex> lock(logMutex_);
|
||||
if (newLogPath.empty() and newLogPath != logPath_) {
|
||||
if (newLogPath.empty() && newLogPath != logPath_) {
|
||||
return false;
|
||||
}
|
||||
if (file_ != nullptr) {
|
||||
|
@ -47,7 +47,7 @@ int Report(const char *perfFile, const char *reportFile, const char *reportOptio
|
||||
{
|
||||
std::unique_ptr<SubCommandReport> report = std::make_unique<SubCommandReport>();
|
||||
HLOGD("report the file %s to %s\n", perfFile, reportFile);
|
||||
if (perfFile != nullptr and reportFile != nullptr) {
|
||||
if (perfFile != nullptr && reportFile != nullptr) {
|
||||
std::vector<std::string> args;
|
||||
args.emplace_back("-i");
|
||||
args.emplace_back(perfFile);
|
||||
@ -77,7 +77,7 @@ int ReportUnwindJson(const char *perfFile, const char *reportFile, const char *s
|
||||
{
|
||||
std::unique_ptr<SubCommandReport> report = std::make_unique<SubCommandReport>();
|
||||
HLOGD("report the file %s to json file %s symbols from %s\n", perfFile, reportFile, symbolsDir);
|
||||
if (perfFile != nullptr and reportFile != nullptr) {
|
||||
if (perfFile != nullptr && reportFile != nullptr) {
|
||||
std::vector<std::string> args;
|
||||
args.emplace_back("-i");
|
||||
args.emplace_back(perfFile);
|
||||
@ -119,11 +119,13 @@ const char *ReportGetSymbolFiles(const char *perfFile)
|
||||
static std::string result; // static for hold the c_str buffer
|
||||
result.clear();
|
||||
if (perfFile == nullptr) {
|
||||
HLOGW("perfFile is nullptr.");
|
||||
return result.c_str();
|
||||
}
|
||||
|
||||
auto reader = GetReader(perfFile);
|
||||
if (reader == nullptr) {
|
||||
HLOGW("reader is nullptr.");
|
||||
return result.c_str();
|
||||
}
|
||||
// found symbols in file
|
||||
|
@ -47,7 +47,7 @@ int main(const int argc, const char *argv[])
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (argc < 0 || argc > 128) { // 128 : max input argument counts
|
||||
if (argc > 128) { // 128 : max input argument counts
|
||||
printf("The number of input arguments exceeds the upper limit.\n");
|
||||
return -1;
|
||||
}
|
||||
@ -55,9 +55,6 @@ int main(const int argc, const char *argv[])
|
||||
cin.tie(nullptr);
|
||||
|
||||
#if defined(is_ohos) && is_ohos
|
||||
if (IsRoot() && setgid(2000) != 0) { // 2000 is shell group
|
||||
printf("setgid failed errno: %d.\n", errno);
|
||||
}
|
||||
WriteStringToFile("/proc/self/oom_score_adj", "0");
|
||||
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
|
||||
HIPERF_HILOGI(MODULE_DEFAULT, "ignore SIGPIPE failed.");
|
||||
|
@ -63,7 +63,7 @@ std::vector<std::string>::iterator FindOption(argsVector &args, const std::strin
|
||||
break;
|
||||
}
|
||||
}
|
||||
auto it = find(args.begin(), args.end(), optionName);
|
||||
auto it = std::find(args.begin(), args.end(), optionName);
|
||||
if (it != args.end()) {
|
||||
if (tmpit != args.end() && it > tmpit) {
|
||||
it = args.end();
|
||||
|
@ -20,100 +20,54 @@
|
||||
|
||||
#include "utilities.h"
|
||||
|
||||
using namespace OHOS::HiviewDFX;
|
||||
using namespace std;
|
||||
namespace OHOS {
|
||||
namespace Developtools {
|
||||
namespace HiPerf {
|
||||
|
||||
void *g_sampleMemCache = nullptr; // for read record from buf thread
|
||||
void *g_sampleMemCacheMain = nullptr; // for main thread:collecttionsymbol
|
||||
constexpr size_t SAMPLE_CACHE_SIZE = 4 * 1024;
|
||||
bool PerfRecordSample::dumpRemoveStack_ = false;
|
||||
thread_local std::unordered_map<PerfRecordType, PerfEventRecord*> PerfEventRecordFactory::recordMap_ = {};
|
||||
|
||||
std::unique_ptr<PerfEventRecord> GetPerfEventRecord(const int type, uint8_t *p,
|
||||
const perf_event_attr &attr)
|
||||
static PerfEventRecord* CreatePerfEventRecord(PerfRecordType type)
|
||||
{
|
||||
HLOG_ASSERT(p);
|
||||
uint8_t *data = p;
|
||||
|
||||
// check kernel
|
||||
switch (type) {
|
||||
case PERF_RECORD_SAMPLE:
|
||||
return std::make_unique<PerfRecordSample>(data, attr);
|
||||
return new PerfRecordSample();
|
||||
case PERF_RECORD_MMAP:
|
||||
return std::make_unique<PerfRecordMmap>(data);
|
||||
return new PerfRecordMmap();
|
||||
case PERF_RECORD_MMAP2:
|
||||
return std::make_unique<PerfRecordMmap2>(data);
|
||||
return new PerfRecordMmap2();
|
||||
case PERF_RECORD_LOST:
|
||||
return std::make_unique<PerfRecordLost>(data);
|
||||
return new PerfRecordLost();
|
||||
case PERF_RECORD_COMM:
|
||||
return std::make_unique<PerfRecordComm>(data);
|
||||
return new PerfRecordComm();
|
||||
case PERF_RECORD_EXIT:
|
||||
return std::make_unique<PerfRecordExit>(data);
|
||||
return new PerfRecordExit();
|
||||
case PERF_RECORD_THROTTLE:
|
||||
return std::make_unique<PerfRecordThrottle>(data);
|
||||
return new PerfRecordThrottle();
|
||||
case PERF_RECORD_UNTHROTTLE:
|
||||
return std::make_unique<PerfRecordUnthrottle>(data);
|
||||
return new PerfRecordUnthrottle();
|
||||
case PERF_RECORD_FORK:
|
||||
return std::make_unique<PerfRecordFork>(data);
|
||||
return new PerfRecordFork();
|
||||
case PERF_RECORD_READ:
|
||||
return std::make_unique<PerfRecordRead>(data);
|
||||
return new PerfRecordRead();
|
||||
case PERF_RECORD_AUX:
|
||||
return std::make_unique<PerfRecordAux>(data);
|
||||
return new PerfRecordAux();
|
||||
case PERF_RECORD_AUXTRACE:
|
||||
return std::make_unique<PerfRecordAuxtrace>(data);
|
||||
return new PerfRecordAuxtrace();
|
||||
case PERF_RECORD_ITRACE_START:
|
||||
return std::make_unique<PerfRecordItraceStart>(data);
|
||||
return new PerfRecordItraceStart();
|
||||
case PERF_RECORD_LOST_SAMPLES:
|
||||
return std::make_unique<PerfRecordLostSamples>(data);
|
||||
return new PerfRecordLostSamples();
|
||||
case PERF_RECORD_SWITCH:
|
||||
return std::make_unique<PerfRecordSwitch>(data);
|
||||
return new PerfRecordSwitch();
|
||||
case PERF_RECORD_SWITCH_CPU_WIDE:
|
||||
return std::make_unique<PerfRecordSwitchCpuWide>(data);
|
||||
return new PerfRecordSwitchCpuWide();
|
||||
default:
|
||||
HLOGE("unknown record type %d\n", type);
|
||||
return nullptr;
|
||||
return new PerfRecordNull();
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<PerfEventRecord> 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<PerfEventRecord>(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<PerfEventRecord>(new (g_sampleMemCache) PerfRecordSample(data, attr));
|
||||
}
|
||||
}
|
||||
return GetPerfEventRecord(type, p, attr);
|
||||
}
|
||||
|
||||
std::unique_ptr<PerfEventRecord> 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<PerfEventRecord>(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<PerfEventRecord>(new (g_sampleMemCacheMain) PerfRecordSample(data, attr));
|
||||
}
|
||||
}
|
||||
return GetPerfEventRecord(type, p, attr);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void PushToBinary(bool condition, uint8_t *&p, const T &v)
|
||||
{
|
||||
@ -155,31 +109,29 @@ inline void PopFromBinary2(bool condition, uint8_t *&p, T1 &v1, T2 &v2)
|
||||
}
|
||||
|
||||
// PerfEventRecord
|
||||
PerfEventRecord::PerfEventRecord(perf_event_type type, bool inKernel, const std::string &name)
|
||||
: name_(name)
|
||||
void PerfEventRecord::Init(perf_event_type type, bool inKernel)
|
||||
{
|
||||
header.type = type;
|
||||
header.misc = inKernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER;
|
||||
header.size = sizeof(header);
|
||||
header_.type = type;
|
||||
header_.misc = inKernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER;
|
||||
header_.size = sizeof(header_);
|
||||
};
|
||||
|
||||
void PerfEventRecord::Init(perf_event_hiperf_ext_type type)
|
||||
{
|
||||
header_.type = type;
|
||||
header_.misc = PERF_RECORD_MISC_USER;
|
||||
header_.size = sizeof(header_);
|
||||
}
|
||||
|
||||
PerfEventRecord::PerfEventRecord(perf_event_hiperf_ext_type type, const std::string &name)
|
||||
: name_(name)
|
||||
{
|
||||
header.type = type;
|
||||
header.misc = PERF_RECORD_MISC_USER;
|
||||
header.size = sizeof(header);
|
||||
}
|
||||
|
||||
PerfEventRecord::PerfEventRecord(uint8_t *p, const std::string &name) : name_(name)
|
||||
void PerfEventRecord::InitHeader(uint8_t* p)
|
||||
{
|
||||
if (p == nullptr) {
|
||||
header.type = PERF_RECORD_MMAP;
|
||||
header.misc = PERF_RECORD_MISC_USER;
|
||||
header.size = 0;
|
||||
header_.type = PERF_RECORD_MMAP;
|
||||
header_.misc = PERF_RECORD_MISC_USER;
|
||||
header_.size = 0;
|
||||
return;
|
||||
}
|
||||
header = *(reinterpret_cast<perf_event_header *>(p));
|
||||
header_ = *(reinterpret_cast<perf_event_header*>(p));
|
||||
}
|
||||
|
||||
void PerfEventRecord::GetHeaderBinary(std::vector<uint8_t> &buf) const
|
||||
@ -188,7 +140,7 @@ void PerfEventRecord::GetHeaderBinary(std::vector<uint8_t> &buf) const
|
||||
buf.resize(GetHeaderSize());
|
||||
}
|
||||
uint8_t *p = buf.data();
|
||||
*(reinterpret_cast<perf_event_header *>(p)) = header;
|
||||
*(reinterpret_cast<perf_event_header*>(p)) = header_;
|
||||
}
|
||||
|
||||
void PerfEventRecord::Dump(int indent, std::string outputFilename, FILE *outputDump) const
|
||||
@ -204,14 +156,14 @@ void PerfEventRecord::Dump(int indent, std::string outputFilename, FILE *outputD
|
||||
}
|
||||
}
|
||||
PRINT_INDENT(indent, "\n");
|
||||
PRINT_INDENT(indent, "record %s: type %u, misc %u, size %zu\n", GetName().c_str(), GetType(),
|
||||
PRINT_INDENT(indent, "record %s: type %u, misc %u, size %zu\n", GetName(), GetType(),
|
||||
GetMisc(), GetSize());
|
||||
DumpData(indent + 1);
|
||||
}
|
||||
|
||||
void PerfEventRecord::DumpLog(const std::string &prefix) const
|
||||
{
|
||||
HLOGV("%s: record %s: type %u, misc %u, size %zu\n", prefix.c_str(), GetName().c_str(),
|
||||
HLOGV("%s: record %s: type %u, misc %u, size %zu\n", prefix.c_str(), GetName(),
|
||||
GetType(), GetMisc(), GetSize());
|
||||
}
|
||||
|
||||
@ -219,22 +171,15 @@ std::vector<u64> PerfRecordSample::ips_ = {};
|
||||
std::vector<DfxFrame> PerfRecordSample::callFrames_ = {};
|
||||
std::vector<pid_t> PerfRecordSample::serverPidMap_ = {};
|
||||
|
||||
PerfRecordAuxtrace::PerfRecordAuxtrace(uint8_t *p) : PerfEventRecord(p, "auxtrace")
|
||||
void PerfRecordAuxtrace::Init(uint8_t* data, const perf_event_attr& attr)
|
||||
{
|
||||
if (header.size >= sizeof(header)) {
|
||||
size_t copySize = header.size - sizeof(header);
|
||||
if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
|
||||
HLOGE("memcpy_s retren failed !!!");
|
||||
}
|
||||
} else {
|
||||
HLOGE("PerfRecordAuxtrace retren failed !!!");
|
||||
}
|
||||
rawData_ = p + header.size;
|
||||
PerfEventRecordTemplate::Init(data);
|
||||
rawData_ = data + header_.size;
|
||||
}
|
||||
|
||||
PerfRecordAuxtrace::PerfRecordAuxtrace(u64 size, u64 offset, u64 reference, u32 idx, u32 tid, u32 cpu, u32 pid)
|
||||
: PerfEventRecord(PERF_RECORD_AUXTRACE, "auxtrace")
|
||||
{
|
||||
PerfEventRecord::Init(PERF_RECORD_AUXTRACE);
|
||||
data_.size = size;
|
||||
data_.offset = offset;
|
||||
data_.reference = reference;
|
||||
@ -243,19 +188,19 @@ PerfRecordAuxtrace::PerfRecordAuxtrace(u64 size, u64 offset, u64 reference, u32
|
||||
data_.cpu = cpu;
|
||||
data_.reserved__ = pid;
|
||||
|
||||
header.size = sizeof(header) + sizeof(data_);
|
||||
header_.size = sizeof(header_) + sizeof(data_);
|
||||
}
|
||||
|
||||
bool PerfRecordAuxtrace::GetBinary1(std::vector<uint8_t> &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<const uint8_t *>(&data_), copySize) != 0) {
|
||||
HLOGE("memcpy_s return failed");
|
||||
return false;
|
||||
@ -272,12 +217,12 @@ bool PerfRecordAuxtrace::GetBinary(std::vector<uint8_t> &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<const uint8_t *>(&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<uint8_t *>(rawData_), data_.size) != 0) {
|
||||
HLOGE("memcpy_s return failed");
|
||||
return false;
|
||||
@ -304,13 +249,13 @@ void PerfRecordAuxtrace::DumpLog(const std::string &prefix) const
|
||||
|
||||
size_t PerfRecordAuxtrace::GetSize() const
|
||||
{
|
||||
return header.size + data_.size;
|
||||
return header_.size + data_.size;
|
||||
}
|
||||
|
||||
void PerfRecordSample::DumpLog(const std::string &prefix) const
|
||||
{
|
||||
HLOGV("%s: SAMPLE: id= %llu size %d pid %u tid %u ips %llu regs %llu, stacks %llu time %llu",
|
||||
prefix.c_str(), data_.sample_id, header.size, data_.pid, data_.tid, data_.nr,
|
||||
prefix.c_str(), data_.sample_id, header_.size, data_.pid, data_.tid, data_.nr,
|
||||
data_.reg_nr, data_.dyn_size, data_.time);
|
||||
}
|
||||
|
||||
@ -339,7 +284,7 @@ void PerfRecordSample::ReplaceWithCallStack(size_t originalSize)
|
||||
const size_t beginIpsSize = ips_.size();
|
||||
bool ret = std::all_of(callFrames_.begin(), callFrames_.end(), [&](const DfxFrame &frame) {
|
||||
ips_.emplace_back(frame.pc);
|
||||
if (originalSize != 0 and (originalSize != callFrames_.size()) and
|
||||
if (originalSize != 0 && (originalSize != callFrames_.size()) &&
|
||||
ips_.size() == (originalSize + beginIpsSize)) {
|
||||
// just for debug
|
||||
// so we can see which frame begin is expand call frames
|
||||
@ -354,15 +299,15 @@ void PerfRecordSample::ReplaceWithCallStack(size_t originalSize)
|
||||
}
|
||||
|
||||
if (sampleType_ & PERF_SAMPLE_REGS_USER) {
|
||||
header.size -= data_.reg_nr * sizeof(u64);
|
||||
header_.size -= data_.reg_nr * sizeof(u64);
|
||||
data_.reg_nr = 0;
|
||||
data_.user_abi = 0;
|
||||
}
|
||||
|
||||
if (sampleType_ & PERF_SAMPLE_STACK_USER) {
|
||||
// 1. remove the user stack
|
||||
header.size -= data_.stack_size;
|
||||
header.size -= sizeof(data_.dyn_size);
|
||||
header_.size -= data_.stack_size;
|
||||
header_.size -= sizeof(data_.dyn_size);
|
||||
|
||||
// 2. clean the size
|
||||
data_.stack_size = 0;
|
||||
@ -373,11 +318,11 @@ void PerfRecordSample::ReplaceWithCallStack(size_t originalSize)
|
||||
HLOGV("ips change from %llu -> %zu", data_.nr, ips_.size());
|
||||
|
||||
// 3. remove the nr size
|
||||
header.size -= data_.nr * sizeof(u64);
|
||||
header_.size -= data_.nr * sizeof(u64);
|
||||
|
||||
// 4. add new nr size
|
||||
data_.nr = ips_.size();
|
||||
header.size += data_.nr * sizeof(u64);
|
||||
header_.size += data_.nr * sizeof(u64);
|
||||
|
||||
// 5. change ips potin to our ips array and hold it.
|
||||
data_.ips = ips_.data();
|
||||
@ -388,20 +333,21 @@ void PerfRecordSample::ReplaceWithCallStack(size_t originalSize)
|
||||
}
|
||||
}
|
||||
|
||||
PerfRecordSample::PerfRecordSample(uint8_t *p, const perf_event_attr &attr)
|
||||
: PerfEventRecord(p, "sample")
|
||||
void PerfRecordSample::Init(uint8_t *p, const perf_event_attr &attr)
|
||||
{
|
||||
if (p == nullptr) {
|
||||
HLOG_ASSERT(p);
|
||||
return;
|
||||
}
|
||||
// clear the static vector data
|
||||
PerfEventRecord::InitHeader(p);
|
||||
|
||||
HLOG_ASSERT(p != nullptr);
|
||||
// clear the vector data
|
||||
Clean();
|
||||
sampleType_ = attr.sample_type;
|
||||
|
||||
skipKernel_ = 0;
|
||||
skipPid_ = 0;
|
||||
stackId_ = {0};
|
||||
removeStack_ = false;
|
||||
data_ = {};
|
||||
uint8_t *start = p;
|
||||
|
||||
p += sizeof(header);
|
||||
p += sizeof(header_);
|
||||
|
||||
// parse record according SAMPLE_TYPE
|
||||
PopFromBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id);
|
||||
@ -448,7 +394,7 @@ PerfRecordSample::PerfRecordSample(uint8_t *p, const perf_event_attr &attr)
|
||||
p += data_.stack_size;
|
||||
PopFromBinary(true, p, data_.dyn_size);
|
||||
}
|
||||
uint32_t remain = header.size - (p - start);
|
||||
uint32_t remain = header_.size - (p - start);
|
||||
if (data_.nr == 0 && dumpRemoveStack_ && remain == sizeof(stackId_)) {
|
||||
PopFromBinary(true, p, stackId_.value);
|
||||
}
|
||||
@ -605,23 +551,11 @@ void PerfRecordSample::Clean()
|
||||
serverPidMap_.clear();
|
||||
}
|
||||
|
||||
PerfRecordMmap::PerfRecordMmap(uint8_t *p) : PerfEventRecord(p, "mmap")
|
||||
{
|
||||
size_t dataSize = GetSize();
|
||||
if (dataSize >= sizeof(header)) {
|
||||
size_t copySize = dataSize - sizeof(header);
|
||||
if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
|
||||
HLOGE("memcpy_s retren failed !!!");
|
||||
}
|
||||
} else {
|
||||
HLOGE("PerfRecordMmap retren failed !!!");
|
||||
}
|
||||
}
|
||||
|
||||
PerfRecordMmap::PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff,
|
||||
const std::string &filename)
|
||||
: PerfEventRecord(PERF_RECORD_MMAP, inKernel, "mmap")
|
||||
{
|
||||
PerfEventRecord::Init(PERF_RECORD_MMAP, inKernel);
|
||||
|
||||
data_.pid = pid;
|
||||
data_.tid = tid;
|
||||
data_.addr = addr;
|
||||
@ -631,7 +565,7 @@ PerfRecordMmap::PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 le
|
||||
HLOGE("strncpy_s failed");
|
||||
}
|
||||
|
||||
header.size = sizeof(header) + sizeof(data_) - KILO + filename.size() + 1;
|
||||
header_.size = sizeof(header_) + sizeof(data_) - KILO + filename.size() + 1;
|
||||
}
|
||||
|
||||
bool PerfRecordMmap::GetBinary(std::vector<uint8_t> &buf) const
|
||||
@ -663,27 +597,14 @@ void PerfRecordMmap::DumpData(int indent) const
|
||||
void PerfRecordMmap::DumpLog(const std::string &prefix) const
|
||||
{
|
||||
HLOGV("%s: MMAP: size %d pid %u tid %u dso '%s' (0x%llx-0x%llx)@0x%llx", prefix.c_str(),
|
||||
header.size, data_.pid, data_.tid, data_.filename, data_.addr, data_.addr + data_.len, data_.pgoff);
|
||||
}
|
||||
|
||||
PerfRecordMmap2::PerfRecordMmap2(uint8_t *p) : PerfEventRecord(p, "mmap2")
|
||||
{
|
||||
size_t dataSize = GetSize();
|
||||
if (dataSize >= sizeof(header)) {
|
||||
size_t copySize = dataSize - sizeof(header);
|
||||
if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
|
||||
HLOGE("memcpy_s retren failed !!!");
|
||||
}
|
||||
} else {
|
||||
HLOGE("PerfRecordMmap2 retren failed !!!");
|
||||
}
|
||||
header_.size, data_.pid, data_.tid, data_.filename, data_.addr, data_.addr + data_.len, data_.pgoff);
|
||||
}
|
||||
|
||||
PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff,
|
||||
u32 maj, u32 min, u64 ino, u32 prot, u32 flags,
|
||||
const std::string &filename)
|
||||
: PerfEventRecord(PERF_RECORD_MMAP2, inKernel, "mmap2")
|
||||
{
|
||||
PerfEventRecord::Init(PERF_RECORD_MMAP2, inKernel);
|
||||
data_.pid = pid;
|
||||
data_.tid = tid;
|
||||
data_.addr = addr;
|
||||
@ -699,12 +620,12 @@ PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, u64 addr, u64
|
||||
HLOGE("strncpy_s failed");
|
||||
}
|
||||
|
||||
header.size = sizeof(header) + sizeof(data_) - KILO + filename.size() + 1;
|
||||
header_.size = sizeof(header_) + sizeof(data_) - KILO + filename.size() + 1;
|
||||
}
|
||||
|
||||
PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, std::shared_ptr<DfxMap> item)
|
||||
: PerfEventRecord(PERF_RECORD_MMAP2, inKernel, "mmap2")
|
||||
{
|
||||
PerfEventRecord::Init(PERF_RECORD_MMAP2, inKernel);
|
||||
data_.pid = pid;
|
||||
data_.tid = tid;
|
||||
if (item != nullptr) {
|
||||
@ -722,7 +643,7 @@ PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, std::shared_pt
|
||||
HLOGE("strncpy_s failed");
|
||||
}
|
||||
|
||||
header.size = sizeof(header) + sizeof(data_) - KILO + item->name.size() + 1;
|
||||
header_.size = sizeof(header_) + sizeof(data_) - KILO + item->name.size() + 1;
|
||||
} else {
|
||||
data_.addr = 0;
|
||||
data_.len = 0;
|
||||
@ -765,26 +686,14 @@ void PerfRecordMmap2::DumpData(int indent) const
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void PerfRecordMmap2::DumpLog(const std::string &prefix) const
|
||||
{
|
||||
HLOGV("%s: MMAP2: size %d pid %u tid %u dso '%s' (0x%llx-0x%llx)@0x%llx", prefix.c_str(),
|
||||
header.size, data_.pid, data_.tid, data_.filename, data_.addr, data_.addr + data_.len,
|
||||
header_.size, data_.pid, data_.tid, data_.filename, data_.addr, data_.addr + data_.len,
|
||||
data_.pgoff);
|
||||
}
|
||||
|
||||
PerfRecordLost::PerfRecordLost(uint8_t *p) : PerfEventRecord(p, "lost")
|
||||
{
|
||||
size_t dataSize = GetSize();
|
||||
if (dataSize >= sizeof(header)) {
|
||||
size_t copySize = dataSize - sizeof(header);
|
||||
if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
|
||||
HLOGE("memcpy_s retren failed !!!");
|
||||
}
|
||||
} else {
|
||||
HLOGE("PerfRecordLost retren failed !!!");
|
||||
}
|
||||
}
|
||||
|
||||
bool PerfRecordLost::GetBinary(std::vector<uint8_t> &buf) const
|
||||
{
|
||||
if (buf.size() < GetSize()) {
|
||||
@ -805,29 +714,17 @@ void PerfRecordLost::DumpData(int indent) const
|
||||
PRINT_INDENT(indent, "id %llu, lost %llu\n", data_.id, data_.lost);
|
||||
}
|
||||
|
||||
PerfRecordComm::PerfRecordComm(uint8_t *p) : PerfEventRecord(p, "comm")
|
||||
{
|
||||
size_t dataSize = GetSize();
|
||||
if (dataSize >= sizeof(header)) {
|
||||
size_t copySize = dataSize - sizeof(header);
|
||||
if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
|
||||
HLOGE("memcpy_s retren failed !!!");
|
||||
}
|
||||
} else {
|
||||
HLOGE("PerfRecordComm retren failed !!!");
|
||||
}
|
||||
}
|
||||
|
||||
PerfRecordComm::PerfRecordComm(bool inKernel, u32 pid, u32 tid, const std::string &comm)
|
||||
: PerfEventRecord(PERF_RECORD_COMM, inKernel, "comm")
|
||||
{
|
||||
PerfEventRecord::Init(PERF_RECORD_COMM, inKernel);
|
||||
data_.pid = pid;
|
||||
data_.tid = tid;
|
||||
if (strncpy_s(data_.comm, KILO, comm.c_str(), comm.size()) != 0) {
|
||||
HLOGE("strncpy_s failed !!!");
|
||||
}
|
||||
|
||||
header.size = sizeof(header) + sizeof(data_) - KILO + comm.size() + 1;
|
||||
header_.size = sizeof(header_) + sizeof(data_) - KILO + comm.size() + 1;
|
||||
}
|
||||
|
||||
bool PerfRecordComm::GetBinary(std::vector<uint8_t> &buf) const
|
||||
@ -856,17 +753,31 @@ void PerfRecordComm::DumpLog(const std::string &prefix) const
|
||||
HLOGV("pid %u, tid %u, comm %s\n", data_.pid, data_.tid, data_.comm);
|
||||
}
|
||||
|
||||
PerfRecordExit::PerfRecordExit(uint8_t *p) : PerfEventRecord(p, "exit")
|
||||
PerfRecordSample::PerfRecordSample(const PerfRecordSample& sample)
|
||||
{
|
||||
size_t dataSize = GetSize();
|
||||
if (dataSize >= sizeof(header)) {
|
||||
size_t copySize = dataSize - sizeof(header);
|
||||
if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
|
||||
HLOGE("memcpy_s retren failed !!!");
|
||||
}
|
||||
} else {
|
||||
HLOGE("PerfRecordExit retren failed !!!");
|
||||
}
|
||||
header_ = sample.header_;
|
||||
data_ = sample.data_;
|
||||
|
||||
sampleType_ = sample.sampleType_;
|
||||
skipKernel_ = sample.skipKernel_;
|
||||
skipPid_ = sample.skipPid_;
|
||||
|
||||
ips_ = sample.ips_;
|
||||
callFrames_ = sample.callFrames_;
|
||||
serverPidMap_ = sample.serverPidMap_;
|
||||
|
||||
stackId_ = sample.stackId_;
|
||||
removeStack_ = sample.removeStack_;
|
||||
}
|
||||
|
||||
void PerfRecordSample::SetDumpRemoveStack(bool dumpRemoveStack)
|
||||
{
|
||||
dumpRemoveStack_ = dumpRemoveStack;
|
||||
}
|
||||
|
||||
bool PerfRecordSample::IsDumpRemoveStack()
|
||||
{
|
||||
return dumpRemoveStack_;
|
||||
}
|
||||
|
||||
bool PerfRecordExit::GetBinary(std::vector<uint8_t> &buf) const
|
||||
@ -889,19 +800,6 @@ void PerfRecordExit::DumpData(int indent) const
|
||||
data_.tid, data_.ptid, data_.time);
|
||||
}
|
||||
|
||||
PerfRecordThrottle::PerfRecordThrottle(uint8_t *p) : PerfEventRecord(p, "throttle")
|
||||
{
|
||||
size_t dataSize = GetSize();
|
||||
if (dataSize >= sizeof(header)) {
|
||||
size_t copySize = dataSize - sizeof(header);
|
||||
if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
|
||||
HLOGE("memcpy_s retren failed !!!");
|
||||
}
|
||||
} else {
|
||||
HLOGE("PerfRecordThrottle retren failed !!!");
|
||||
}
|
||||
}
|
||||
|
||||
bool PerfRecordThrottle::GetBinary(std::vector<uint8_t> &buf) const
|
||||
{
|
||||
if (buf.size() < GetSize()) {
|
||||
@ -922,19 +820,6 @@ void PerfRecordThrottle::DumpData(int indent) const
|
||||
data_.stream_id);
|
||||
}
|
||||
|
||||
PerfRecordUnthrottle::PerfRecordUnthrottle(uint8_t *p) : PerfEventRecord(p, "unthrottle")
|
||||
{
|
||||
size_t dataSize = GetSize();
|
||||
if (dataSize >= sizeof(header)) {
|
||||
size_t copySize = dataSize - sizeof(header);
|
||||
if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
|
||||
HLOGE("memcpy_s retren failed !!!");
|
||||
}
|
||||
} else {
|
||||
HLOGE("PerfRecordUnthrottle retren failed !!!");
|
||||
}
|
||||
}
|
||||
|
||||
bool PerfRecordUnthrottle::GetBinary(std::vector<uint8_t> &buf) const
|
||||
{
|
||||
if (buf.size() < GetSize()) {
|
||||
@ -948,25 +833,13 @@ bool PerfRecordUnthrottle::GetBinary(std::vector<uint8_t> &buf) const
|
||||
*pDest = data_;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PerfRecordUnthrottle::DumpData(int indent) const
|
||||
{
|
||||
PRINT_INDENT(indent, "time 0x%llx, id %llx, stream_id %llx\n", data_.time, data_.id,
|
||||
data_.stream_id);
|
||||
}
|
||||
|
||||
PerfRecordFork::PerfRecordFork(uint8_t *p) : PerfEventRecord(p, "fork")
|
||||
{
|
||||
size_t dataSize = GetSize();
|
||||
if (dataSize >= sizeof(header)) {
|
||||
size_t copySize = dataSize - sizeof(header);
|
||||
if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
|
||||
HLOGE("memcpy_s retren failed !!!");
|
||||
}
|
||||
} else {
|
||||
HLOGE("PerfRecordFork retren failed !!!");
|
||||
}
|
||||
}
|
||||
|
||||
bool PerfRecordFork::GetBinary(std::vector<uint8_t> &buf) const
|
||||
{
|
||||
if (buf.size() < GetSize()) {
|
||||
@ -987,19 +860,6 @@ void PerfRecordFork::DumpData(int indent) const
|
||||
data_.ptid);
|
||||
}
|
||||
|
||||
PerfRecordRead::PerfRecordRead(uint8_t *p) : PerfEventRecord(p, "read")
|
||||
{
|
||||
size_t dataSize = GetSize();
|
||||
if (dataSize >= sizeof(header)) {
|
||||
size_t copySize = dataSize - sizeof(header);
|
||||
if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
|
||||
HLOGE("memcpy_s retren failed !!!");
|
||||
}
|
||||
} else {
|
||||
HLOGE("PerfRecordRead retren failed !!!");
|
||||
}
|
||||
}
|
||||
|
||||
bool PerfRecordRead::GetBinary(std::vector<uint8_t> &buf) const
|
||||
{
|
||||
if (buf.size() < GetSize()) {
|
||||
@ -1021,19 +881,6 @@ void PerfRecordRead::DumpData(int indent) const
|
||||
data_.values.value, data_.values.timeEnabled, data_.values.timeRunning, data_.values.id);
|
||||
}
|
||||
|
||||
PerfRecordAux::PerfRecordAux(uint8_t *p) : PerfEventRecord(p, "aux")
|
||||
{
|
||||
size_t dataSize = GetSize();
|
||||
if (dataSize >= sizeof(header)) {
|
||||
size_t copySize = dataSize - sizeof(header);
|
||||
if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
|
||||
HLOGE("memcpy_s retren failed !!!");
|
||||
}
|
||||
} else {
|
||||
HLOGE("PerfRecordAux retren failed !!!");
|
||||
}
|
||||
}
|
||||
|
||||
bool PerfRecordAux::GetBinary(std::vector<uint8_t> &buf) const
|
||||
{
|
||||
if (buf.size() < GetSize()) {
|
||||
@ -1063,19 +910,6 @@ void PerfRecordAux::DumpData(int indent) const
|
||||
data_.sample_id.time);
|
||||
}
|
||||
|
||||
PerfRecordItraceStart::PerfRecordItraceStart(uint8_t *p) : PerfEventRecord(p, "itraceStart")
|
||||
{
|
||||
size_t dataSize = GetSize();
|
||||
if (dataSize >= sizeof(header)) {
|
||||
size_t copySize = dataSize - sizeof(header);
|
||||
if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
|
||||
HLOGE("memcpy_s retren failed !!!");
|
||||
}
|
||||
} else {
|
||||
HLOGE("PerfRecordItraceStart retren failed !!!");
|
||||
}
|
||||
}
|
||||
|
||||
bool PerfRecordItraceStart::GetBinary(std::vector<uint8_t> &buf) const
|
||||
{
|
||||
if (buf.size() < GetSize()) {
|
||||
@ -1095,19 +929,6 @@ void PerfRecordItraceStart::DumpData(int indent) const
|
||||
PRINT_INDENT(indent, "pid %u, tid %u\n", data_.pid, data_.tid);
|
||||
}
|
||||
|
||||
PerfRecordLostSamples::PerfRecordLostSamples(uint8_t *p) : PerfEventRecord(p, "lostSamples")
|
||||
{
|
||||
size_t dataSize = GetSize();
|
||||
if (dataSize >= sizeof(header)) {
|
||||
size_t copySize = dataSize - sizeof(header);
|
||||
if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
|
||||
HLOGE("memcpy_s retren failed !!!");
|
||||
}
|
||||
} else {
|
||||
HLOGE("PerfRecordLostSamples retren failed !!!");
|
||||
}
|
||||
}
|
||||
|
||||
bool PerfRecordLostSamples::GetBinary(std::vector<uint8_t> &buf) const
|
||||
{
|
||||
if (buf.size() < GetSize()) {
|
||||
@ -1127,19 +948,6 @@ void PerfRecordLostSamples::DumpData(int indent) const
|
||||
PRINT_INDENT(indent, "lost %llu\n", data_.lost);
|
||||
}
|
||||
|
||||
PerfRecordSwitch::PerfRecordSwitch(uint8_t *p) : PerfEventRecord(p, "switch")
|
||||
{
|
||||
size_t dataSize = GetSize();
|
||||
if (dataSize >= sizeof(header)) {
|
||||
size_t copySize = dataSize - sizeof(header);
|
||||
if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
|
||||
HLOGE("memcpy_s retren failed !!!");
|
||||
}
|
||||
} else {
|
||||
HLOGE("PerfRecordSwitch retren failed !!!");
|
||||
}
|
||||
}
|
||||
|
||||
bool PerfRecordSwitch::GetBinary(std::vector<uint8_t> &buf) const
|
||||
{
|
||||
if (buf.size() < GetSize()) {
|
||||
@ -1154,19 +962,6 @@ bool PerfRecordSwitch::GetBinary(std::vector<uint8_t> &buf) const
|
||||
return true;
|
||||
}
|
||||
|
||||
PerfRecordSwitchCpuWide::PerfRecordSwitchCpuWide(uint8_t *p) : PerfEventRecord(p, "switchCpuWide")
|
||||
{
|
||||
size_t dataSize = GetSize();
|
||||
if (dataSize >= sizeof(header)) {
|
||||
size_t copySize = dataSize - sizeof(header);
|
||||
if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
|
||||
HLOGE("memcpy_s retren failed !!!");
|
||||
}
|
||||
} else {
|
||||
HLOGE("PerfRecordSwitchCpuWide retren failed !!!");
|
||||
}
|
||||
}
|
||||
|
||||
bool PerfRecordSwitchCpuWide::GetBinary(std::vector<uint8_t> &buf) const
|
||||
{
|
||||
if (buf.size() < GetSize()) {
|
||||
@ -1246,6 +1041,23 @@ pid_t PerfRecordSample::GetServerPidof(unsigned int ipNr)
|
||||
return serverPidMap_[ipNr];
|
||||
}
|
||||
}
|
||||
|
||||
PerfEventRecord& PerfEventRecordFactory::GetPerfEventRecord(PerfRecordType type, uint8_t* data,
|
||||
const perf_event_attr &attr)
|
||||
{
|
||||
HLOG_ASSERT(data != nullptr);
|
||||
PerfEventRecord* record = nullptr;
|
||||
auto it = recordMap_.find(type);
|
||||
if (it == recordMap_.end()) {
|
||||
record = CreatePerfEventRecord(type);
|
||||
recordMap_.emplace(type, record);
|
||||
} else {
|
||||
record = it->second;
|
||||
}
|
||||
record->Init(data, attr);
|
||||
return *record;
|
||||
}
|
||||
|
||||
} // namespace HiPerf
|
||||
} // namespace Developtools
|
||||
} // namespace OHOS
|
||||
|
@ -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_;
|
||||
@ -412,7 +412,7 @@ void PerfEvents::SetConfig(std::map<const std::string, unsigned long long> &speO
|
||||
bool PerfEvents::AddEvent(perf_type_id type, __u64 config, bool excludeUser, bool excludeKernel,
|
||||
bool followGroup)
|
||||
{
|
||||
HLOG_ASSERT(!excludeUser or !excludeKernel);
|
||||
HLOG_ASSERT(!excludeUser || !excludeKernel);
|
||||
CHECK_TRUE(followGroup && eventGroupItem_.empty(), false, 1, "no group leader create before");
|
||||
// found the event name
|
||||
CHECK_TRUE(!IsEventSupport(type, config), false, 0, "");
|
||||
@ -1624,7 +1624,7 @@ void PerfEvents::ReadRecordFromBuf()
|
||||
const auto readingStartTime_ = steady_clock::now();
|
||||
#endif
|
||||
#if !HIDEBUG_SKIP_CALLBACK
|
||||
recordCallBack_(GetPerfSampleFromCache(*type, p, *attr));
|
||||
recordCallBack_(PerfEventRecordFactory::GetPerfEventRecord(*type, p, *attr));
|
||||
#endif
|
||||
recordEventCount_++;
|
||||
#ifdef HIPERF_DEBUG_TIME
|
||||
@ -1643,7 +1643,7 @@ void PerfEvents::ReadRecordFromBuf()
|
||||
const auto readingStartTime_ = steady_clock::now();
|
||||
#endif
|
||||
#if !HIDEBUG_SKIP_CALLBACK
|
||||
recordCallBack_(GetPerfSampleFromCache(*type, p, *attr));
|
||||
recordCallBack_(PerfEventRecordFactory::GetPerfEventRecord(*type, p, *attr));
|
||||
#endif
|
||||
recordEventCount_++;
|
||||
#ifdef HIPERF_DEBUG_TIME
|
||||
|
@ -134,12 +134,13 @@ bool PerfFileSection::Read(std::string &value)
|
||||
CHECK_TRUE(!Read(size), false, 0, "");
|
||||
// if size large than buf size or 0 size ?
|
||||
// don't assert for fuzz test
|
||||
CHECK_TRUE(size == 0 or size > maxSize_, false, 0, "");
|
||||
char buf[size];
|
||||
CHECK_TRUE(size == 0 || size > maxSize_, false, 0, "");
|
||||
char *buf = new char[size];
|
||||
CHECK_TRUE(!Read(buf, size), false, 0, "");
|
||||
CHECK_TRUE(buf[size - 1] != 0, false, 0, "");
|
||||
value = buf;
|
||||
HLOGDUMMY("Read String size %u buf : %s", size, value.c_str());
|
||||
delete []buf;
|
||||
return true;
|
||||
}
|
||||
void PerfFileSection::Skip(size_t size)
|
||||
|
@ -46,7 +46,9 @@ std::unique_ptr<PerfFileReader> PerfFileReader::Instance(const std::string &file
|
||||
if (!reader->ReadFileHeader()) {
|
||||
// Fail to read header, maybe its compressed
|
||||
if (reader->IsGzipFile()) {
|
||||
fclose(fp);
|
||||
if (fp != nullptr) {
|
||||
fclose(fp);
|
||||
}
|
||||
reader->fp_ = nullptr;
|
||||
|
||||
CHECK_TRUE(!UncompressFile(fileName, UNCOMPRESS_TMP_FILE), nullptr, 1,
|
||||
@ -80,7 +82,7 @@ PerfFileReader::PerfFileReader(const std::string &fileName, FILE *fp) : fp_(fp),
|
||||
featureSectionOffset_ = 0;
|
||||
struct stat fileStat;
|
||||
if (fp != nullptr) {
|
||||
if (fstat(fileno(fp), &fileStat) != -1 and fileStat.st_size > 0) {
|
||||
if (fstat(fileno(fp), &fileStat) != -1 && fileStat.st_size > 0) {
|
||||
fileSize_ = fileStat.st_size;
|
||||
}
|
||||
}
|
||||
@ -110,7 +112,7 @@ bool PerfFileReader::IsValidDataFile()
|
||||
|
||||
bool PerfFileReader::IsGzipFile()
|
||||
{
|
||||
return header_.magic[0] == '\x1f' and header_.magic[1] == '\x8b';
|
||||
return header_.magic[0] == '\x1f' && header_.magic[1] == '\x8b';
|
||||
}
|
||||
|
||||
bool PerfFileReader::ReadFileHeader()
|
||||
@ -276,20 +278,20 @@ bool PerfFileReader::ReadRecord(ProcessRecordCB &callback)
|
||||
}
|
||||
}
|
||||
uint8_t *data = buf;
|
||||
std::unique_ptr<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.GetName() == nullptr) {
|
||||
return false;
|
||||
} else {
|
||||
HLOGV("record type %u", record->GetType());
|
||||
HLOGV("record type %u", record.GetType());
|
||||
}
|
||||
remainingSize = remainingSize - header->size - speSize;
|
||||
#ifdef HIPERF_DEBUG_TIME
|
||||
const auto startCallbackTime = steady_clock::now();
|
||||
#endif
|
||||
// call callback to process, then destroy record
|
||||
callback(std::move(record));
|
||||
callback(record);
|
||||
recordNumber++;
|
||||
#ifdef HIPERF_DEBUG_TIME
|
||||
readCallbackTime_ +=
|
||||
@ -404,7 +406,7 @@ bool PerfFileReader::ReadFeatureSection()
|
||||
HLOGV("process feature %d:%s", feature, PerfFileSection::GetFeatureName(feature).c_str());
|
||||
HLOGV(" sectionHeader -> read offset '0x%" PRIx64 " size '0x%" PRIx64 "'",
|
||||
sectionHeader.offset, sectionHeader.size);
|
||||
CHECK_TRUE(sectionHeader.size == 0 or sectionHeader.size > fileSize_, false, 1,
|
||||
CHECK_TRUE(sectionHeader.size == 0 || sectionHeader.size > fileSize_, false, 1,
|
||||
"sectionHeader.size %" PRIu64 " is not correct", sectionHeader.size);
|
||||
|
||||
std::vector<char> buf(sectionHeader.size);
|
||||
@ -423,7 +425,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.GetName(), record.GetSize());
|
||||
|
||||
CHECK_TRUE(record.GetSize() > RECORD_SIZE_LIMIT_SPE, false, 1,
|
||||
"%s record size exceed limit", record.GetName().c_str());
|
||||
"%s record size exceed limit", record.GetName());
|
||||
// signal 7 (SIGBUS), code 1 (BUS_ADRALN), fault addr 0xb64eb195
|
||||
static std::vector<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),
|
||||
data, defaultEventAttr_);
|
||||
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.GetName() == nullptr, true, 0, "");
|
||||
remainingSize = remainingSize - header->size - speSize;
|
||||
// call callback to process, do not destroy the record
|
||||
callback(std::move(record));
|
||||
callback(record);
|
||||
recordNumber++;
|
||||
}
|
||||
} else {
|
||||
@ -214,6 +214,11 @@ bool PerfFileWriter::Read(void *buf, size_t len)
|
||||
return true;
|
||||
}
|
||||
|
||||
void PerfFileWriter::SetWriteRecordStat(bool isWrite)
|
||||
{
|
||||
isWritingRecord = isWrite;
|
||||
}
|
||||
|
||||
uint64_t PerfFileWriter::GetDataSize() const
|
||||
{
|
||||
return dataSection_.size;
|
||||
|
@ -63,7 +63,7 @@ uint64_t GetSupportedRegMask(ArchType arch)
|
||||
break;
|
||||
default:
|
||||
result = std::numeric_limits<uint64_t>::max();
|
||||
HLOGE("unsupport arch %d", arch);
|
||||
HLOGE("unsupport arch %u", arch);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
@ -272,7 +272,7 @@ ArchType GetDeviceArch()
|
||||
|
||||
void UpdateRegForABI(ArchType arch, u64 *regs)
|
||||
{
|
||||
if (g_deviceArchType == ArchType::ARCH_ARM64 and arch == ArchType::ARCH_ARM) {
|
||||
if (g_deviceArchType == ArchType::ARCH_ARM64 && arch == ArchType::ARCH_ARM) {
|
||||
// arm in arm64
|
||||
regs[PERF_REG_ARM_PC] = regs[PERF_REG_ARM64_PC];
|
||||
}
|
||||
|
@ -41,49 +41,47 @@ void Report::AddReportItem(const PerfRecordSample &sample, bool includeCallStack
|
||||
configIndex, sample.data_.id);
|
||||
VirtualThread &thread = virtualRuntime_.GetThread(sample.data_.pid, sample.data_.tid);
|
||||
HLOG_ASSERT(sample.callFrames_.size() > 0);
|
||||
if (sample.callFrames_.size() > 0) {
|
||||
// if we need callstack ?
|
||||
if (includeCallStack) {
|
||||
// we will use caller mode , from last to first
|
||||
auto frameIt = sample.callFrames_.rbegin();
|
||||
// if we need callstack ?
|
||||
if (includeCallStack) {
|
||||
// we will use caller mode , from last to first
|
||||
auto frameIt = sample.callFrames_.rbegin();
|
||||
ReportItem &item = configs_[configIndex].reportItems_.emplace_back(
|
||||
sample.data_.pid, sample.data_.tid, thread.name_, frameIt->mapName,
|
||||
frameIt->funcName, frameIt->funcOffset, sample.data_.period);
|
||||
HLOGD("ReportItem: %s", item.ToDebugString().c_str());
|
||||
HLOG_ASSERT(!item.func_.empty());
|
||||
|
||||
std::vector<ReportItemCallFrame> *currentCallFrames = &item.callStacks_;
|
||||
for (frameIt = sample.callFrames_.rbegin(); frameIt != sample.callFrames_.rend();
|
||||
frameIt++) {
|
||||
HLOG_ASSERT(frameIt->pc < PERF_CONTEXT_MAX);
|
||||
// in add items case , right one should only have 1 callstack
|
||||
// so just new callfames and move to next level
|
||||
ReportItemCallFrame &nextCallFrame = currentCallFrames->emplace_back(
|
||||
frameIt->funcName, frameIt->funcOffset, frameIt->mapName,
|
||||
sample.data_.period,
|
||||
(std::next(frameIt) == sample.callFrames_.rend()) ? sample.data_.period : 0);
|
||||
HLOGV("add callframe %s", nextCallFrame.ToDebugString().c_str());
|
||||
currentCallFrames = &nextCallFrame.childs;
|
||||
}
|
||||
HLOGV("callstack %zu", item.callStacks_.size());
|
||||
if (item.callStacks_.size() > 0) {
|
||||
HLOGV("callstack 2nd level %zu", item.callStacks_[0].childs.size());
|
||||
}
|
||||
} else {
|
||||
auto frameIt = sample.callFrames_.begin();
|
||||
if (frameIt != sample.callFrames_.end()) {
|
||||
HLOG_ASSERT(frameIt->pc < PERF_CONTEXT_MAX);
|
||||
// for arkjs frame, skip the stub.an frame
|
||||
if (StringEndsWith(frameIt->mapName, "stub.an") && sample.callFrames_.size() > 1) {
|
||||
HLOGV("stub.an frame, go to next, mapname %s", frameIt->mapName.c_str());
|
||||
frameIt++;
|
||||
}
|
||||
ReportItem &item = configs_[configIndex].reportItems_.emplace_back(
|
||||
sample.data_.pid, sample.data_.tid, thread.name_, frameIt->mapName,
|
||||
frameIt->funcName, frameIt->funcOffset, sample.data_.period);
|
||||
HLOGD("ReportItem: %s", item.ToDebugString().c_str());
|
||||
HLOGV("%s", item.ToDebugString().c_str());
|
||||
HLOG_ASSERT(!item.func_.empty());
|
||||
|
||||
std::vector<ReportItemCallFrame> *currentCallFrames = &item.callStacks_;
|
||||
for (frameIt = sample.callFrames_.rbegin(); frameIt != sample.callFrames_.rend();
|
||||
frameIt++) {
|
||||
HLOG_ASSERT(frameIt->pc < PERF_CONTEXT_MAX);
|
||||
// in add items case , right one should only have 1 callstack
|
||||
// so just new callfames and move to next level
|
||||
ReportItemCallFrame &nextCallFrame = currentCallFrames->emplace_back(
|
||||
frameIt->funcName, frameIt->funcOffset, frameIt->mapName,
|
||||
sample.data_.period,
|
||||
(std::next(frameIt) == sample.callFrames_.rend()) ? sample.data_.period : 0);
|
||||
HLOGV("add callframe %s", nextCallFrame.ToDebugString().c_str());
|
||||
currentCallFrames = &nextCallFrame.childs;
|
||||
}
|
||||
HLOGV("callstack %zu", item.callStacks_.size());
|
||||
if (item.callStacks_.size() > 0) {
|
||||
HLOGV("callstack 2nd level %zu", item.callStacks_[0].childs.size());
|
||||
}
|
||||
} else {
|
||||
auto frameIt = sample.callFrames_.begin();
|
||||
if (frameIt != sample.callFrames_.end()) {
|
||||
HLOG_ASSERT(frameIt->pc < PERF_CONTEXT_MAX);
|
||||
// for arkjs frame, skip the stub.an frame
|
||||
if (StringEndsWith(frameIt->mapName, "stub.an") && sample.callFrames_.size() > 1) {
|
||||
HLOGV("stub.an frame, go to next, mapname %s", frameIt->mapName.c_str());
|
||||
frameIt++;
|
||||
}
|
||||
ReportItem &item = configs_[configIndex].reportItems_.emplace_back(
|
||||
sample.data_.pid, sample.data_.tid, thread.name_, frameIt->mapName,
|
||||
frameIt->funcName, frameIt->funcOffset, sample.data_.period);
|
||||
HLOGV("%s", item.ToDebugString().c_str());
|
||||
HLOG_ASSERT(!item.func_.empty());
|
||||
}
|
||||
}
|
||||
}
|
||||
configs_[configIndex].sampleCount_++;
|
||||
@ -321,7 +319,7 @@ bool Report::MultiLevelSorting(const ReportItem &a, const ReportItem &b)
|
||||
#ifdef HIPERF_DEBUG
|
||||
if (DebugLogger::GetInstance()->GetLogLevel() <= LEVEL_VERBOSE) {
|
||||
bool result2 = MultiLevelCompare(b, a) > 0;
|
||||
if (result and result == result2) {
|
||||
if (result && result == result2) {
|
||||
HLOGE("MultiLevelSorting a->b %d vs b->a %d", result, result2);
|
||||
HLOGE("left %s", a.ToDebugString().c_str());
|
||||
HLOGE("right %s", b.ToDebugString().c_str());
|
||||
@ -456,14 +454,14 @@ void Report::OutputStdCallFrames(int indent, const ReportItemCallFrame &callFram
|
||||
NO_RETVAL, 0, "");
|
||||
|
||||
// print it self
|
||||
if (callFrame.selfEventCount_ != 0 and callFrame.selfEventCount_ != callFrame.eventCount_) {
|
||||
if (callFrame.selfEventCount_ != 0 && callFrame.selfEventCount_ != callFrame.eventCount_) {
|
||||
OutputStdCallFrame(indent + CALLSTACK_INDENT, "[run in self function]",
|
||||
callFrame.selfEventCount_, callFrame.eventCount_);
|
||||
}
|
||||
|
||||
// printf children
|
||||
// if only one children
|
||||
if (callFrame.childs.size() == 1u and
|
||||
if (callFrame.childs.size() == 1u &&
|
||||
callFrame.childs[0].eventCount_ == callFrame.eventCount_) {
|
||||
HLOGV("childCallFream %*c %s", indent, ' ', callFrame.childs[0].func_.data());
|
||||
// don't indent if same count (only one 100% children)
|
||||
@ -519,7 +517,7 @@ void Report::OutputStdContentItem(const ReportItem &reportItem)
|
||||
|
||||
void Report::OutputStdItemHeating(float heat, float heat2)
|
||||
{
|
||||
if (heat == heat2 and heat == 0.0f) {
|
||||
if (heat == heat2 && heat == 0.0f) {
|
||||
fprintf(output_, "something error , all it is end.\n");
|
||||
} else if (heat2 == 0) {
|
||||
// only have first
|
||||
@ -560,7 +558,7 @@ void Report::OutputStdContentDiff(ReportEventConfigItem &left, ReportEventConfig
|
||||
if (MultiLevelSame(*it, *it2)) {
|
||||
// we found the same item
|
||||
// output the diff heating
|
||||
if (it->heat > option_.heatLimit_ and it2->heat > option_.heatLimit_) {
|
||||
if (it->heat > option_.heatLimit_ && it2->heat > option_.heatLimit_) {
|
||||
OutputStdItemHeating(it->heat, it2->heat);
|
||||
OutputStdContentItem(*it);
|
||||
}
|
||||
|
@ -215,7 +215,7 @@ int ReportProtobufFileReader::Read(void *buffer, int size)
|
||||
|
||||
return protobufFileStream_->gcount();
|
||||
}
|
||||
printf("read file %d bytes failed %s : %s\n", size, fileName_.c_str(), readErr.what());
|
||||
HLOGW("read file %d bytes failed %s : %s\n", size, fileName_.c_str(), readErr.what());
|
||||
}
|
||||
} else {
|
||||
printf("no file open for read (request %d bytes).\n", size);
|
||||
|
@ -41,7 +41,7 @@ size_t RingBuffer::GetFreeSize() const
|
||||
|
||||
uint8_t *RingBuffer::AllocForWrite(size_t writeSize)
|
||||
{
|
||||
if (buf_ == nullptr || buf_.get() == nullptr) {
|
||||
if (buf_ == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
size_t writeHead = head_.load(std::memory_order_relaxed);
|
||||
@ -57,7 +57,7 @@ uint8_t *RingBuffer::AllocForWrite(size_t writeSize)
|
||||
if (writePos + writeSize > readPos) {
|
||||
return nullptr;
|
||||
}
|
||||
} else if (writePos == readPos and writeHead != readHead) {
|
||||
} else if (writePos == readPos && writeHead != readHead) {
|
||||
// writePos catch up with readPos, but buffer is full
|
||||
return nullptr;
|
||||
} else {
|
||||
|
@ -259,7 +259,9 @@ static int SpePktOutString(int *err, char **bufPtr, size_t *bufLen,
|
||||
if (err && *err) {
|
||||
return *err;
|
||||
}
|
||||
|
||||
if (*bufLen - 1 < 0) {
|
||||
HLOGW("SpePktOutString failed, bufLen: %d", static_cast<int>(*bufLen));
|
||||
}
|
||||
va_start(args, fmt);
|
||||
ret = vsnprintf_s(*bufPtr, *bufLen, *bufLen - 1, fmt, args);
|
||||
va_end(args);
|
||||
@ -268,6 +270,7 @@ static int SpePktOutString(int *err, char **bufPtr, size_t *bufLen,
|
||||
if (err && !*err) {
|
||||
*err = ret;
|
||||
}
|
||||
HLOGW("vsnprintf_s failed: %d\n", ret);
|
||||
|
||||
/*
|
||||
* If the return value is *bufLen or greater, the output was
|
||||
@ -627,21 +630,6 @@ static u64 SpeCalcIp(int index, u64 payload)
|
||||
return payload;
|
||||
}
|
||||
|
||||
struct SpeDecoder *SpeDecoderNew(struct SpeParams *params)
|
||||
{
|
||||
CHECK_TRUE(params == nullptr, nullptr, 1, "Invalid pointer!");
|
||||
struct SpeDecoder *decoder;
|
||||
|
||||
decoder = static_cast<struct SpeDecoder*>(malloc(sizeof(struct SpeDecoder)));
|
||||
if (!decoder) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
decoder->data = params->data;
|
||||
|
||||
return decoder;
|
||||
}
|
||||
|
||||
void SpeDecoderFree(struct SpeDecoder *decoder)
|
||||
{
|
||||
CHECK_TRUE(decoder == nullptr, NO_RETVAL, 1, "Invalid pointer!");
|
||||
@ -1009,14 +997,32 @@ void DumpSpeReportData(int indent, FILE *outputDump)
|
||||
for (auto it = AuxRawDataMap_.begin(); it != AuxRawDataMap_.end(); it++) {
|
||||
u64 count = typeCount[it->first];
|
||||
DumpSpeReportHead(indent, it->first, count);
|
||||
std::vector<ReportItemAuxRawData> auxRawData;
|
||||
for (auto& it2 : it->second) {
|
||||
PRINT_INDENT(indent + 1, "%*.2f%% ", FULL_PERCENTAGE_LEN, it2.second.heating);
|
||||
PRINT_INDENT(indent + 1, "%-*llu ", FULL_PERCENTAGE_LEN, it2.second.count);
|
||||
PRINT_INDENT(indent + 1, "%-*s ", SPE_PERCENTAGE_COMM_LEN, it2.second.comm.c_str());
|
||||
PRINT_INDENT(indent + 1, "0x%-*llx ", SPE_PERCENTAGE_PC_LEN, it2.second.pc);
|
||||
PRINT_INDENT(indent + 1, "%-*s ", SPE_PERCENTAGE_DSO_LEN, it2.second.SharedObject.c_str());
|
||||
PRINT_INDENT(indent + 1, "%-*s", SPE_PERCENTAGE_FUNC_LEN, it2.second.Symbol.c_str());
|
||||
PRINT_INDENT(indent + 1, "0x%llx\n", it2.second.offset);
|
||||
struct ReportItemAuxRawData reportItem = {
|
||||
it2.second.type,
|
||||
it2.second.heating,
|
||||
it2.second.count,
|
||||
it2.second.comm,
|
||||
it2.second.pc,
|
||||
it2.second.SharedObject,
|
||||
it2.second.Symbol,
|
||||
it2.second.offset
|
||||
};
|
||||
auxRawData.emplace_back(reportItem);
|
||||
}
|
||||
std::sort(auxRawData.begin(), auxRawData.end(), [](const ReportItemAuxRawData& lhs,
|
||||
const ReportItemAuxRawData& rhs) {
|
||||
return lhs.count > rhs.count;
|
||||
});
|
||||
for (auto& it3 : auxRawData) {
|
||||
PRINT_INDENT(indent + 1, "%*.2f%% ", FULL_PERCENTAGE_LEN, it3.heating);
|
||||
PRINT_INDENT(indent + 1, "%-*llu ", FULL_PERCENTAGE_LEN, it3.count);
|
||||
PRINT_INDENT(indent + 1, "%-*s ", SPE_PERCENTAGE_COMM_LEN, it3.comm.c_str());
|
||||
PRINT_INDENT(indent + 1, "0x%-*llx ", SPE_PERCENTAGE_PC_LEN, it3.pc);
|
||||
PRINT_INDENT(indent + 1, "%-*s ", SPE_PERCENTAGE_DSO_LEN, it3.SharedObject.c_str());
|
||||
PRINT_INDENT(indent + 1, "%-*s", SPE_PERCENTAGE_FUNC_LEN, it3.Symbol.c_str());
|
||||
PRINT_INDENT(indent + 1, "0x%llx\n", it3.offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include "debug_logger.h"
|
||||
#include "option.h"
|
||||
|
||||
using namespace std;
|
||||
namespace OHOS {
|
||||
namespace Developtools {
|
||||
namespace HiPerf {
|
||||
@ -146,7 +145,7 @@ void SubCommand::ExcludeThreadsFromSelectTids(const std::vector<std::string> &ex
|
||||
}
|
||||
}
|
||||
|
||||
bool SubCommand::RegisterSubCommand(std::string cmdName, std::unique_ptr<SubCommand> subCommand)
|
||||
bool SubCommand::RegisterSubCommand(const std::string& cmdName, std::unique_ptr<SubCommand> subCommand)
|
||||
{
|
||||
HLOGV("%s", cmdName.c_str());
|
||||
if (cmdName.empty()) {
|
||||
@ -158,7 +157,7 @@ bool SubCommand::RegisterSubCommand(std::string cmdName, std::unique_ptr<SubComm
|
||||
return false;
|
||||
}
|
||||
|
||||
if (g_SubCommandsMap.count(cmdName) == 0) {
|
||||
if (g_SubCommandsMap.find(cmdName) == g_SubCommandsMap.end()) {
|
||||
std::lock_guard<std::mutex> lock(g_subCommandMutex);
|
||||
g_SubCommandsMap.insert(std::make_pair(cmdName, std::move(subCommand)));
|
||||
return true;
|
||||
|
@ -381,13 +381,15 @@ void SubCommandDump::DumpAttrPortion(int indent)
|
||||
|
||||
void SubCommandDump::ExprotUserStack(const PerfRecordSample &recordSample)
|
||||
{
|
||||
if (recordSample.data_.reg_nr > 0 and recordSample.data_.dyn_size > 0) {
|
||||
if (recordSample.data_.reg_nr > 0 && recordSample.data_.dyn_size > 0) {
|
||||
// <pid>_<tid>_user_regs_<time>
|
||||
std::string userRegs =
|
||||
StringPrintf("hiperf_%d_%d_user_regs_%zu.dump", recordSample.data_.pid,
|
||||
recordSample.data_.tid, exportSampleIndex_);
|
||||
std::string resolvedPath = CanonicalizeSpecPath(userRegs.c_str());
|
||||
std::unique_ptr<FILE, decltype(&fclose)> fpUserRegs(fopen(resolvedPath.c_str(), "wb"), fclose);
|
||||
FILE *userRegsFp = fopen(resolvedPath.c_str(), "wb");
|
||||
CHECK_TRUE(userRegsFp == nullptr, NO_RETVAL, 1, "open userRegs failed");
|
||||
std::unique_ptr<FILE, decltype(&fclose)> fpUserRegs(userRegsFp, fclose);
|
||||
fwrite(recordSample.data_.user_regs, sizeof(u64), recordSample.data_.reg_nr,
|
||||
fpUserRegs.get());
|
||||
|
||||
@ -395,19 +397,21 @@ void SubCommandDump::ExprotUserStack(const PerfRecordSample &recordSample)
|
||||
StringPrintf("hiperf_%d_%d_user_data_%zu.dump", recordSample.data_.pid,
|
||||
recordSample.data_.tid, exportSampleIndex_);
|
||||
std::string resolvePath = CanonicalizeSpecPath(userData.c_str());
|
||||
std::unique_ptr<FILE, decltype(&fclose)> fpUserData(fopen(resolvePath.c_str(), "wb"), fclose);
|
||||
FILE *UserDataFp = fopen(resolvePath.c_str(), "wb");
|
||||
CHECK_TRUE(UserDataFp == nullptr, NO_RETVAL, 1, "open UserData failed");
|
||||
std::unique_ptr<FILE, decltype(&fclose)> fpUserData(UserDataFp, fclose);
|
||||
fwrite(recordSample.data_.stack_data, sizeof(u8), recordSample.data_.dyn_size,
|
||||
fpUserData.get());
|
||||
}
|
||||
}
|
||||
|
||||
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 +427,14 @@ void SubCommandDump::ExprotUserData(std::unique_ptr<PerfEventRecord> &record)
|
||||
}
|
||||
}
|
||||
|
||||
void SubCommandDump::DumpCallChain(int indent, std::unique_ptr<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) {
|
||||
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 +443,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.GetName() == nullptr, false, 0, ""); // return false in callback can stop the read process
|
||||
|
||||
// for UT
|
||||
if (exportSampleIndex_ > 0) {
|
||||
@ -448,15 +452,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;
|
||||
@ -592,7 +594,7 @@ void SubCommandDump::SetHM()
|
||||
if (isHM_) {
|
||||
pid_t devhost = -1;
|
||||
std::string str = reader_->GetFeatureString(FEATURE::HIPERF_HM_DEVHOST);
|
||||
if (str != EMPTY_STRING) {
|
||||
if (IsNumeric(str)) {
|
||||
devhost = std::stoll(str);
|
||||
}
|
||||
vr_.SetDevhostPid(devhost);
|
||||
|
@ -15,7 +15,6 @@
|
||||
|
||||
#include "subcommand_help.h"
|
||||
#include "debug_logger.h"
|
||||
using namespace std;
|
||||
|
||||
namespace OHOS {
|
||||
namespace Developtools {
|
||||
|
@ -181,7 +181,7 @@ bool SubCommandRecord::GetSpeOptions()
|
||||
for (auto item: valueExpressions) {
|
||||
std::vector<std::string> expressions = StringSplit(item, "=");
|
||||
size_t itemNum = 2;
|
||||
if (expressions.size() == itemNum) {
|
||||
if (expressions.size() == itemNum && IsNumeric(expressions[1])) {
|
||||
std::string name = expressions[0];
|
||||
unsigned long long num = std::stoull(expressions[1]);
|
||||
if (speOptMap_.find(name) != speOptMap_.end()) {
|
||||
@ -397,7 +397,12 @@ bool SubCommandRecord::CheckDataLimitOption()
|
||||
bool SubCommandRecord::CheckSelectCpuPidOption()
|
||||
{
|
||||
if (!selectCpus_.empty()) {
|
||||
int maxCpuid = sysconf(_SC_NPROCESSORS_CONF) - 1;
|
||||
int cpuCount = sysconf(_SC_NPROCESSORS_CONF);
|
||||
if (cpuCount == -1) {
|
||||
printf("sysconf failed.\n");
|
||||
return false;
|
||||
}
|
||||
int maxCpuid = cpuCount - 1;
|
||||
for (auto cpu : selectCpus_) {
|
||||
if (cpu < 0 || cpu > maxCpuid) {
|
||||
printf("Invalid -c value '%d', the CPU ID should be in 0~%d \n", cpu, maxCpuid);
|
||||
@ -539,7 +544,7 @@ bool SubCommandRecord::CheckTargetProcessOptions()
|
||||
}
|
||||
hasTarget = true;
|
||||
}
|
||||
if (!hasTarget and (controlCmd_.empty() or controlCmd_ == CONTROL_CMD_PREPARE)) {
|
||||
if (!hasTarget && (controlCmd_.empty() || controlCmd_ == CONTROL_CMD_PREPARE)) {
|
||||
printf("please select a target process\n");
|
||||
return false;
|
||||
}
|
||||
@ -596,11 +601,11 @@ bool SubCommandRecord::ParseDataLimitOption(const std::string &str)
|
||||
{
|
||||
uint unit = 1;
|
||||
char c = str.at(str.size() >= 1 ? str.size() - 1 : 0);
|
||||
if (c == 'K' or c == 'k') {
|
||||
if (c == 'K' || c == 'k') {
|
||||
unit = KILO;
|
||||
} else if (c == 'm' or c == 'M') {
|
||||
} else if (c == 'm' || c == 'M') {
|
||||
unit = KILO * KILO;
|
||||
} else if (c == 'g' or c == 'G') {
|
||||
} else if (c == 'g' || c == 'G') {
|
||||
unit = KILO * KILO * KILO;
|
||||
} else {
|
||||
return false;
|
||||
@ -692,8 +697,8 @@ bool SubCommandRecord::ParseBranchSampleType(const std::vector<std::string> &vec
|
||||
|
||||
bool SubCommandRecord::ParseControlCmd(const std::string cmd)
|
||||
{
|
||||
if (cmd.empty() or cmd == CONTROL_CMD_PREPARE or cmd == CONTROL_CMD_START or
|
||||
cmd == CONTROL_CMD_PAUSE or cmd == CONTROL_CMD_RESUME or cmd == CONTROL_CMD_STOP) {
|
||||
if (cmd.empty() || cmd == CONTROL_CMD_PREPARE || cmd == CONTROL_CMD_START ||
|
||||
cmd == CONTROL_CMD_PAUSE || cmd == CONTROL_CMD_RESUME || cmd == CONTROL_CMD_STOP) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -778,7 +783,7 @@ bool SubCommandRecord::TraceOffCpu()
|
||||
int enable = -1;
|
||||
std::string node = SCHED_SWITCH;
|
||||
const std::string nodeDebug = SCHED_SWITCH_DEBUG;
|
||||
CHECK_TRUE(!ReadIntFromProcFile(node.c_str(), enable) and !ReadIntFromProcFile(nodeDebug.c_str(), enable),
|
||||
CHECK_TRUE(!ReadIntFromProcFile(node.c_str(), enable) && !ReadIntFromProcFile(nodeDebug.c_str(), enable),
|
||||
false, LOG_TYPE_PRINTF, "Cannot trace off CPU, event sched:sched_switch is not available (%s or %s)\n",
|
||||
node.c_str(), nodeDebug.c_str());
|
||||
|
||||
@ -806,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);
|
||||
|
||||
@ -892,15 +897,15 @@ 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);
|
||||
|
||||
// do some config for virtualRuntime_
|
||||
virtualRuntime_.SetCallStackExpend(disableCallstackExpend_ ? 0 : 1);
|
||||
// these is same for virtual runtime
|
||||
virtualRuntime_.SetDisableUnwind(disableUnwind_ or delayUnwind_);
|
||||
virtualRuntime_.SetDisableUnwind(disableUnwind_ || delayUnwind_);
|
||||
virtualRuntime_.EnableDebugInfoSymbolic(enableDebugInfoSymbolic_);
|
||||
if (!symbolDir_.empty()) {
|
||||
if (!virtualRuntime_.SetSymbolsPaths(symbolDir_)) {
|
||||
@ -1084,7 +1089,7 @@ bool SubCommandRecord::CreateFifoServer()
|
||||
{
|
||||
char errInfo[ERRINFOLEN] = { 0 };
|
||||
const mode_t fifoMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
|
||||
if (mkfifo(CONTROL_FIFO_FILE_S2C.c_str(), fifoMode) != 0 or
|
||||
if (mkfifo(CONTROL_FIFO_FILE_S2C.c_str(), fifoMode) != 0 ||
|
||||
mkfifo(CONTROL_FIFO_FILE_C2S.c_str(), fifoMode) != 0) {
|
||||
if (errno == EEXIST) {
|
||||
printf("another sampling service is running.\n");
|
||||
@ -1129,7 +1134,7 @@ bool SubCommandRecord::CreateFifoServer()
|
||||
if (fd != -1) {
|
||||
WaitFifoReply(fd, CONTROL_WAITREPY_TOMEOUT, reply);
|
||||
}
|
||||
if (fd == -1 or reply != HiperfClient::ReplyOK) {
|
||||
if (fd == -1 || reply != HiperfClient::ReplyOK) {
|
||||
if (reply != HiperfClient::ReplyOK) {
|
||||
printf("%s\n", reply.c_str());
|
||||
}
|
||||
@ -1220,7 +1225,7 @@ bool SubCommandRecord::OnSubCommand(std::vector<std::string> &args)
|
||||
}
|
||||
|
||||
// prepare PerfEvents
|
||||
if (!PrepareSysKernel() or !PreparePerfEvent()) {
|
||||
if (!PrepareSysKernel() || !PreparePerfEvent()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1260,6 +1265,10 @@ bool SubCommandRecord::OnSubCommand(std::vector<std::string> &args)
|
||||
}
|
||||
HIPERF_HILOGI(MODULE_DEFAULT, "SubCommandRecord perfEvents tracking finish");
|
||||
|
||||
if (isSpe_) {
|
||||
HLOGD("stop write spe record");
|
||||
fileWriter_->SetWriteRecordStat(false);
|
||||
}
|
||||
startSaveFileTimes_ = steady_clock::now();
|
||||
if (!FinishWriteRecordFile()) {
|
||||
HLOGE("Fail to finish record file %s", outputFilename_.c_str());
|
||||
@ -1314,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.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
|
||||
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
|
||||
@ -1336,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;
|
||||
}
|
||||
@ -1349,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(const 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
|
||||
@ -1380,22 +1375,22 @@ bool SubCommandRecord::SaveRecord(std::unique_ptr<PerfEventRecord> record, bool
|
||||
}
|
||||
}
|
||||
|
||||
if (record) {
|
||||
if (record.GetName() != 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.GetName());
|
||||
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.GetName());
|
||||
#ifdef HIPERF_DEBUG_TIME
|
||||
saveRecordTimes_ += duration_cast<microseconds>(steady_clock::now() - saveTime);
|
||||
#endif
|
||||
@ -1611,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.GetName() == 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);
|
||||
@ -1660,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.GetName() == 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);
|
||||
}
|
||||
|
||||
@ -1685,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?
|
||||
@ -1745,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
|
||||
|
@ -123,14 +123,14 @@ void SubCommandReport::DumpOptions() const
|
||||
bool SubCommandReport::VerifyDisplayOption()
|
||||
{
|
||||
for (std::string &number : reportOption_.displayPids_) {
|
||||
if (!IsDigits(number) or number.front() == '-') {
|
||||
if (!IsDigits(number) || number.front() == '-') {
|
||||
printf("error number for pid '%s'\n", number.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::string &number : reportOption_.displayTids_) {
|
||||
if (!IsDigits(number) or number.front() == '-') {
|
||||
if (!IsDigits(number) || number.front() == '-') {
|
||||
printf("error number for tid '%s'\n", number.c_str());
|
||||
return false;
|
||||
}
|
||||
@ -151,11 +151,11 @@ bool SubCommandReport::VerifyOption()
|
||||
}
|
||||
const float min = 0.0;
|
||||
const float max = 100.0;
|
||||
if (reportOption_.heatLimit_ < min or reportOption_.heatLimit_ > max) {
|
||||
if (reportOption_.heatLimit_ < min || reportOption_.heatLimit_ > max) {
|
||||
printf("head limit error. must in (0 <= limit < 100).\n");
|
||||
return false;
|
||||
}
|
||||
if (reportOption_.callStackHeatLimit_ < min or reportOption_.callStackHeatLimit_ > max) {
|
||||
if (reportOption_.callStackHeatLimit_ < min || reportOption_.callStackHeatLimit_ > max) {
|
||||
printf("head limit error. must in (0 <= limit < 100).\n");
|
||||
return false;
|
||||
}
|
||||
@ -164,7 +164,7 @@ bool SubCommandReport::VerifyOption()
|
||||
return false;
|
||||
}
|
||||
if (!recordFile_[SECOND].empty()) {
|
||||
if (protobufFormat_ or jsonFormat_ or showCallStack_) {
|
||||
if (protobufFormat_ || jsonFormat_ || showCallStack_) {
|
||||
printf("diff don't support any export mode(like json , flame or proto)\n");
|
||||
} else {
|
||||
diffMode_ = true;
|
||||
@ -223,13 +223,14 @@ 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
|
||||
= std::make_unique<PerfRecordSample>(static_cast<PerfRecordSample&>(record));
|
||||
std::unique_ptr<PerfRecordSample> prevSample = nullptr;
|
||||
if (cpuOffMode_) {
|
||||
auto prevIt = prevSampleCache_.find(sample->data_.tid);
|
||||
@ -256,7 +257,7 @@ bool SubCommandReport::RecordCallBack(std::unique_ptr<PerfEventRecord> record)
|
||||
HLOGV("current sample period %llu ", sample->data_.period);
|
||||
}
|
||||
}
|
||||
if (cpuOffMode_ and cpuOffids_.size() > 0 and cpuOffids_.count(sample->data_.id) > 0) {
|
||||
if (cpuOffMode_ && cpuOffids_.size() > 0 && cpuOffids_.count(sample->data_.id) > 0) {
|
||||
BroadcastSample(sample);
|
||||
} else {
|
||||
ProcessSample(sample);
|
||||
@ -264,7 +265,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
|
||||
}
|
||||
@ -360,7 +361,7 @@ void SubCommandReport::LoadEventDesc()
|
||||
{
|
||||
const PerfFileSection *featureSection =
|
||||
recordFileReader_->GetFeatureSection(FEATURE::EVENT_DESC);
|
||||
CHECK_TRUE(featureSection == nullptr, NO_RETVAL, 0, "");
|
||||
CHECK_TRUE(featureSection == nullptr, NO_RETVAL, 1, "featureSection invalid");
|
||||
const PerfFileSectionEventDesc §ionEventdesc =
|
||||
*static_cast<const PerfFileSectionEventDesc *>(featureSection);
|
||||
HLOGV("Event descriptions: %zu", sectionEventdesc.eventDesces_.size());
|
||||
@ -369,7 +370,7 @@ void SubCommandReport::LoadEventDesc()
|
||||
|
||||
HLOGV("event name[%zu]: %s ids: %s", i, fileAttr.name.c_str(),
|
||||
VectorToString(fileAttr.ids).c_str());
|
||||
if (cpuOffMode_ and fileAttr.name == cpuOffEventName) {
|
||||
if (cpuOffMode_ && fileAttr.name == cpuOffEventName) {
|
||||
// found cpuoff event id
|
||||
std::set<uint64_t> cpuOffids(fileAttr.ids.begin(), fileAttr.ids.end());
|
||||
cpuOffids_ = cpuOffids;
|
||||
@ -440,7 +441,7 @@ void SubCommandReport::FlushCacheRecord()
|
||||
for (auto &pair : prevSampleCache_) {
|
||||
std::unique_ptr<PerfRecordSample> sample = std::move(pair.second);
|
||||
sample->data_.period = 1u;
|
||||
if (cpuOffMode_ and cpuOffids_.size() > 0 and cpuOffids_.count(sample->data_.id) > 0) {
|
||||
if (cpuOffMode_ && cpuOffids_.size() > 0 && cpuOffids_.count(sample->data_.id) > 0) {
|
||||
BroadcastSample(sample);
|
||||
} else {
|
||||
ProcessSample(sample);
|
||||
@ -478,8 +479,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();
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include "utilities.h"
|
||||
|
||||
const uint16_t ONE_HUNDRED = 100;
|
||||
const uint16_t THOUSNADS_SEPARATOR = 3;
|
||||
const uint16_t THOUSANDS_SEPARATOR = 3;
|
||||
namespace OHOS {
|
||||
namespace Developtools {
|
||||
namespace HiPerf {
|
||||
@ -56,7 +56,7 @@ void SubCommandStat::DumpOptions() const
|
||||
|
||||
bool SubCommandStat::ParseOption(std::vector<std::string> &args)
|
||||
{
|
||||
if (args.size() == 1 and args[0] == "-h") {
|
||||
if (args.size() == 1 && args[0] == "-h") {
|
||||
args.clear();
|
||||
helpOption_ = true;
|
||||
PrintUsage();
|
||||
@ -203,7 +203,7 @@ void SubCommandStat::PrintPerValue(const std::unique_ptr<PerfEvents::ReportSum>
|
||||
// print value
|
||||
std::string strEventCount = std::to_string(reportSum->eventCountSum);
|
||||
for (size_t i = strEventCount.size() >= 1 ? strEventCount.size() - 1 : 0, j = 1; i > 0; --i, ++j) {
|
||||
if (j == THOUSNADS_SEPARATOR) {
|
||||
if (j == THOUSANDS_SEPARATOR) {
|
||||
j = 0;
|
||||
strEventCount.insert(strEventCount.begin() + i, ',');
|
||||
}
|
||||
@ -306,7 +306,7 @@ void SubCommandStat::ReportNormal(
|
||||
std::string comment = comments[configName];
|
||||
std::string strEventCount = std::to_string(it->second->eventCount);
|
||||
for (size_t i = strEventCount.size() >= 1 ? strEventCount.size() - 1 : 0, j = 1; i > 0; --i, ++j) {
|
||||
if (j == THOUSNADS_SEPARATOR) {
|
||||
if (j == THOUSANDS_SEPARATOR) {
|
||||
strEventCount.insert(strEventCount.begin() + i, ',');
|
||||
j = 0;
|
||||
}
|
||||
@ -351,7 +351,7 @@ std::string SubCommandStat::GetCommentConfigName(
|
||||
const std::unique_ptr<PerfEvents::CountEvent> &countEvent, std::string eventName)
|
||||
{
|
||||
std::string commentConfigName = "";
|
||||
CHECK_TRUE(countEvent == nullptr || eventName.length() == 0, commentConfigName, 0, "");
|
||||
CHECK_TRUE(countEvent == nullptr || eventName.length() == 0, commentConfigName, 1, "countEvent is nullptr");
|
||||
if (countEvent->userOnly) {
|
||||
commentConfigName = eventName + ":u";
|
||||
} else if (countEvent->kernelOnly) {
|
||||
@ -610,7 +610,9 @@ bool SubCommandStat::CheckOptionPid(std::vector<pid_t> pids)
|
||||
}
|
||||
|
||||
for (auto pid : pids) {
|
||||
if (!IsDir("/proc/" + std::to_string(pid))) {
|
||||
std::ostringstream oss;
|
||||
oss << "/proc/" << pid;
|
||||
if (!IsDir(oss.str())) {
|
||||
printf("not exit pid %d\n", pid);
|
||||
return false;
|
||||
}
|
||||
@ -651,6 +653,10 @@ bool SubCommandStat::OnSubCommand(std::vector<std::string> &args)
|
||||
HLOGV("CheckAppIsRunning() failed");
|
||||
return false;
|
||||
}
|
||||
if (!CheckOptionPid(selectPids_)) {
|
||||
HLOGV("CheckOptionPid() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
perfEvents_.SetCpu(selectCpus_);
|
||||
std::vector<pid_t> pids;
|
||||
|
@ -43,9 +43,6 @@
|
||||
#include "utilities.h"
|
||||
#include "ipc_utilities.h"
|
||||
|
||||
using namespace OHOS::HiviewDFX;
|
||||
using namespace std::chrono;
|
||||
|
||||
namespace OHOS {
|
||||
namespace Developtools {
|
||||
namespace HiPerf {
|
||||
@ -98,10 +95,14 @@ std::string SymbolsFile::SearchReadableFile(const std::vector<std::string> &sear
|
||||
const std::string &filePath) const
|
||||
{
|
||||
if (filePath.empty()) {
|
||||
HLOGW("nothing to found");
|
||||
HLOGW("filePath is empty, nothing to found");
|
||||
return filePath;
|
||||
}
|
||||
for (auto searchPath : searchPaths) {
|
||||
if (searchPath.empty()) {
|
||||
HLOGW("searchPath is empty.");
|
||||
continue;
|
||||
}
|
||||
if (searchPath.back() != PATH_SEPARATOR) {
|
||||
searchPath += PATH_SEPARATOR;
|
||||
}
|
||||
@ -150,7 +151,7 @@ const std::string SymbolsFile::FindSymbolFile(
|
||||
|
||||
// only access the patch in onRecording_
|
||||
// in report mode we don't load any thing in runtime path
|
||||
if (foundPath.empty() and onRecording_) {
|
||||
if (foundPath.empty() && onRecording_) {
|
||||
// try access direct at last
|
||||
if (CheckPathReadable(symboleFilePath)) {
|
||||
// found direct folder
|
||||
@ -307,7 +308,7 @@ private:
|
||||
bool GetHDRSectionInfo(uint64_t &ehFrameHdrElfOffset, uint64_t &fdeTableElfOffset,
|
||||
uint64_t &fdeTableSize) override
|
||||
{
|
||||
CHECK_TRUE(elfFile_ == nullptr, false, 0, "");
|
||||
CHECK_TRUE(elfFile_ == nullptr, false, 1, "elfFile_ is nullptr");
|
||||
ShdrInfo shinfo;
|
||||
if (!elfFile_->GetSectionInfo(shinfo, ".eh_frame_hdr")) {
|
||||
return false;
|
||||
@ -795,7 +796,7 @@ public:
|
||||
bool LoadSymbols(std::shared_ptr<DfxMap> map, const std::string &symbolFilePath) override
|
||||
{
|
||||
symbolsLoaded_ = true;
|
||||
if (module_ == filePath_ and onRecording_) {
|
||||
if (module_ == filePath_ && onRecording_) {
|
||||
// file name still not convert to ko file path
|
||||
// this is in record mode
|
||||
HLOGV("find ko name %s", module_.c_str());
|
||||
|
@ -106,9 +106,14 @@ bool TrackedCommand::StartCommand()
|
||||
// send start signal to start execution of command
|
||||
ssize_t nbyte {0};
|
||||
char startSignal {1};
|
||||
int loopCount = 0;
|
||||
while (true) {
|
||||
nbyte = write(startFd_, &startSignal, 1);
|
||||
if (nbyte == -1) {
|
||||
if (loopCount++ > MAX_LOOP_COUNT) {
|
||||
HLOGE("read failed.");
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
@ -117,9 +122,14 @@ bool TrackedCommand::StartCommand()
|
||||
// check execution state of command
|
||||
// read acknowledgement signal
|
||||
char ackSignal {0};
|
||||
loopCount = 0;
|
||||
while (true) {
|
||||
nbyte = read(ackFd_, &ackSignal, 1);
|
||||
if (nbyte == -1 and (errno == EINTR or errno == EIO)) {
|
||||
if (nbyte == -1 && (errno == EINTR || errno == EIO)) {
|
||||
if (loopCount++ > MAX_LOOP_COUNT) {
|
||||
HLOGE("read failed.");
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
HLOGE("*** nbyte: %zd, ackSignal: %d ***\n", nbyte, ackSignal);
|
||||
@ -142,9 +152,14 @@ void TrackedCommand::ExecuteCommand(const int &startFd, const int &ackFd)
|
||||
// waiting start signal
|
||||
char startSignal {0};
|
||||
ssize_t nbyte {0};
|
||||
int loopCount = 0;
|
||||
while (true) {
|
||||
nbyte = read(startFd, &startSignal, 1);
|
||||
if (nbyte == -1) {
|
||||
if (loopCount++ > MAX_LOOP_COUNT) {
|
||||
HLOGE("read failed.");
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
@ -164,9 +179,14 @@ void TrackedCommand::ExecuteCommand(const int &startFd, const int &ackFd)
|
||||
}
|
||||
// execv() or execvp() failed, send failure signal
|
||||
char ackSignal {1};
|
||||
loopCount = 0;
|
||||
while (true) {
|
||||
nbyte = write(ackFd, &ackSignal, 1);
|
||||
if (nbyte == -1) {
|
||||
if (loopCount++ > MAX_LOOP_COUNT) {
|
||||
HLOGE("read failed.");
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
@ -182,7 +202,7 @@ bool TrackedCommand::WaitCommand(int &wstatus)
|
||||
pid_t pid = waitpid(childPid_, &wstatus, WNOHANG);
|
||||
if (pid == 0) {
|
||||
return false;
|
||||
} else { // pid == childPid_ or pid == -1
|
||||
} else { // pid == childPid_ || pid == -1
|
||||
childPid_ = -1;
|
||||
state_ = State::COMMAND_STOPPED;
|
||||
return true;
|
||||
|
@ -182,8 +182,8 @@ bool UniqueStackTable::GetIpsByStackId(StackId stackId, std::vector<u64>& ips)
|
||||
|
||||
bool UniqueStackTable::ImportNode(uint32_t index, const Node& node)
|
||||
{
|
||||
Node *tableHead = reinterpret_cast<Node *>(tableBuf_.get());
|
||||
CHECK_TRUE(index >= tableSize_, false, 0, "");
|
||||
Node *tableHead = reinterpret_cast<Node *>(tableBuf_.get());
|
||||
tableHead[index].value = node.value;
|
||||
return true;
|
||||
}
|
||||
|
@ -280,7 +280,7 @@ std::string ReadFileToString(const std::string &fileName)
|
||||
{
|
||||
std::string resolvedPath = CanonicalizeSpecPath(fileName.c_str());
|
||||
std::ifstream inputString(resolvedPath, std::ios::in);
|
||||
if (!inputString or !inputString.is_open()) {
|
||||
if (!inputString || !inputString.is_open()) {
|
||||
return EMPTY_STRING;
|
||||
}
|
||||
std::istreambuf_iterator<char> firstIt = {inputString};
|
||||
@ -494,11 +494,13 @@ std::vector<pid_t> GetSubthreadIDs(const pid_t pid)
|
||||
auto tids = GetSubDirs(path);
|
||||
std::vector<pid_t> res {};
|
||||
for (auto tidStr : tids) {
|
||||
pid_t tid = static_cast<pid_t>(std::stoul(tidStr, nullptr));
|
||||
if (tid == pid) {
|
||||
continue;
|
||||
if (!tidStr.empty()) {
|
||||
pid_t tid = static_cast<pid_t>(std::stoul(tidStr, nullptr));
|
||||
if (tid == pid) {
|
||||
continue;
|
||||
}
|
||||
res.push_back(tid);
|
||||
}
|
||||
res.push_back(tid);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@ -842,6 +844,20 @@ bool IsHiviewCall()
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IsNumeric(const std::string& str)
|
||||
{
|
||||
std::istringstream iss(str);
|
||||
int number;
|
||||
char trailingCharacter;
|
||||
if (!(iss >> number)) {
|
||||
return false;
|
||||
}
|
||||
if (iss >> trailingCharacter) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace HiPerf
|
||||
} // namespace Developtools
|
||||
} // namespace OHOS
|
||||
|
@ -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);
|
||||
}
|
||||
@ -248,7 +248,11 @@ void VirtualRuntime::UpdateKernelModulesSpaceMaps()
|
||||
while (getline(ifs, line)) {
|
||||
uint64_t addr = 0;
|
||||
uint64_t size = 0;
|
||||
char module[line.size()];
|
||||
uint64_t lineSize = line.size();
|
||||
if (lineSize > 4096) { // 4096: line length
|
||||
continue;
|
||||
}
|
||||
char *module = new char[lineSize];
|
||||
/*
|
||||
name size load map
|
||||
hi_mipi_rx 53248 0 - Live 0xbf109000 (O)
|
||||
@ -262,7 +266,7 @@ void VirtualRuntime::UpdateKernelModulesSpaceMaps()
|
||||
hi3516cv500_base,sys_config,hi_proc,hi_irq,Live 0xbf000000 (O)
|
||||
*/
|
||||
int ret = sscanf_s(line.c_str(), "%s%" PRIu64 "%*u%*s%*s 0x%" PRIx64 "", module,
|
||||
sizeof(module), &size, &addr, sizeof(addr));
|
||||
lineSize, &size, &addr, sizeof(addr));
|
||||
constexpr int numSlices {3};
|
||||
if (ret == numSlices) {
|
||||
auto &map = koMaps.emplace_back(addr, addr + size, 0, "", std::string(module));
|
||||
@ -270,6 +274,7 @@ void VirtualRuntime::UpdateKernelModulesSpaceMaps()
|
||||
} else {
|
||||
HLOGE("unknown line %d: '%s'", ret, line.c_str());
|
||||
}
|
||||
delete []module;
|
||||
}
|
||||
|
||||
if (std::all_of(koMaps.begin(), koMaps.end(),
|
||||
@ -281,7 +286,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 +299,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 +338,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 +395,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 +558,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 +575,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 +661,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 +671,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 +715,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 +727,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 +769,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, "");
|
||||
}
|
||||
}
|
||||
@ -1062,13 +1067,13 @@ const DfxSymbol VirtualRuntime::GetUserSymbol(uint64_t ip, const VirtualThread &
|
||||
bool VirtualRuntime::GetSymbolCache(uint64_t fileVaddr, DfxSymbol &symbol,
|
||||
const perf_callchain_context &context)
|
||||
{
|
||||
if (context == PERF_CONTEXT_MAX and kThreadSymbolCache_.count(fileVaddr)) {
|
||||
if (context == PERF_CONTEXT_MAX && kThreadSymbolCache_.count(fileVaddr)) {
|
||||
CHECK_TRUE(kThreadSymbolCache_.find(symbol.fileVaddr_) == kThreadSymbolCache_.end(), false, 0, "");
|
||||
symbol = kThreadSymbolCache_[symbol.fileVaddr_];
|
||||
symbol.hit_++;
|
||||
HLOGV("hit kernel thread cache 0x%" PRIx64 " %d", fileVaddr, symbol.hit_);
|
||||
return true;
|
||||
} else if (context != PERF_CONTEXT_USER and kernelSymbolCache_.count(fileVaddr)) {
|
||||
} else if (context != PERF_CONTEXT_USER && kernelSymbolCache_.count(fileVaddr)) {
|
||||
CHECK_TRUE(kernelSymbolCache_.find(symbol.fileVaddr_) == kernelSymbolCache_.end(), false, 0, "");
|
||||
symbol = kernelSymbolCache_[symbol.fileVaddr_];
|
||||
symbol.hit_++;
|
||||
@ -1110,7 +1115,7 @@ DfxSymbol VirtualRuntime::GetSymbol(uint64_t ip, pid_t pid, pid_t tid, const per
|
||||
}
|
||||
}
|
||||
|
||||
if (context == PERF_CONTEXT_USER or (context == PERF_CONTEXT_MAX and !symbol.IsValid())) {
|
||||
if (context == PERF_CONTEXT_USER || (context == PERF_CONTEXT_MAX && !symbol.IsValid())) {
|
||||
// check userspace memmap
|
||||
symbol = GetUserSymbol(ip, GetThread(pid, tid));
|
||||
if (userSymbolCache_.find(symbol.fileVaddr_) == userSymbolCache_.end()) {
|
||||
@ -1121,7 +1126,7 @@ DfxSymbol VirtualRuntime::GetSymbol(uint64_t ip, pid_t pid, pid_t tid, const per
|
||||
userSymbolCache_[symbol.fileVaddr_].ToDebugString().c_str());
|
||||
}
|
||||
|
||||
if (context == PERF_CONTEXT_KERNEL or (context == PERF_CONTEXT_MAX and !symbol.IsValid())) {
|
||||
if (context == PERF_CONTEXT_KERNEL || (context == PERF_CONTEXT_MAX && !symbol.IsValid())) {
|
||||
// check kernelspace
|
||||
HLOGM("try found addr in kernelspace %zu maps", kernelSpaceMemMaps_.size());
|
||||
symbol = GetKernelSymbol(ip, kernelSpaceMemMaps_, GetThread(pid, tid));
|
||||
@ -1253,7 +1258,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 +1296,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -366,7 +366,7 @@ void VirtualThread::SortMemMaps()
|
||||
{
|
||||
for (int currPos = 1; currPos < static_cast<int>(memMaps_.size()); ++currPos) {
|
||||
int targetPos = currPos - 1;
|
||||
while (targetPos >= 0 and memMaps_[memMapsIndexs_[currPos]]->end < memMaps_[memMapsIndexs_[targetPos]]->end) {
|
||||
while (targetPos >= 0 && memMaps_[memMapsIndexs_[currPos]]->end < memMaps_[memMapsIndexs_[targetPos]]->end) {
|
||||
--targetPos;
|
||||
}
|
||||
if (targetPos < currPos - 1) {
|
||||
|
@ -73,7 +73,7 @@ bool FuzzPerfFileReader(const uint8_t *data, size_t size)
|
||||
}
|
||||
|
||||
reader->ReadFeatureSection();
|
||||
auto recordCallback = [&](const std::unique_ptr<PerfEventRecord> &record) {
|
||||
auto recordCallback = [&](PerfEventRecord& record) {
|
||||
// nothing to do
|
||||
return true;
|
||||
};
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "perf_event_record_test.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <thread>
|
||||
|
||||
using namespace testing::ext;
|
||||
using namespace std;
|
||||
@ -80,7 +81,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 +117,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 +156,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 +179,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 +202,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 +226,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 +250,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 +273,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 +428,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 +449,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 +483,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<u64> ips = {};
|
||||
@ -498,7 +510,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 +540,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 +567,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 +590,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 +614,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 +638,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 +662,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 +686,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 +714,84 @@ HWTEST_F(PerfEventRecordTest, GetPerfEventRecord, TestSize.Level1)
|
||||
if (type == PERF_RECORD_SAMPLE) {
|
||||
continue;
|
||||
}
|
||||
std::unique_ptr<PerfEventRecord> perfEventRecord =
|
||||
GetPerfEventRecord(static_cast<perf_event_type>(type), reinterpret_cast<uint8_t *>(&data), attr);
|
||||
PerfEventRecord& perfEventRecord =
|
||||
PerfEventRecordFactory::GetPerfEventRecord(static_cast<perf_event_type>(type),
|
||||
reinterpret_cast<uint8_t *>(&data), attr);
|
||||
if (type < PERF_RECORD_NAMESPACES) {
|
||||
ASSERT_EQ(perfEventRecord != nullptr, true);
|
||||
ASSERT_EQ(perfEventRecord.GetName() != nullptr, true);
|
||||
}
|
||||
}
|
||||
std::unique_ptr<PerfEventRecord> perfEventRecord =
|
||||
GetPerfEventRecord(static_cast<perf_event_type>(PERF_RECORD_AUXTRACE),
|
||||
reinterpret_cast<uint8_t *>(&data), attr);
|
||||
ASSERT_EQ(perfEventRecord != nullptr, true);
|
||||
PerfEventRecord& perfEventRecord =
|
||||
PerfEventRecordFactory::GetPerfEventRecord(static_cast<perf_event_type>(PERF_RECORD_AUXTRACE),
|
||||
reinterpret_cast<uint8_t *>(&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_event_type>(PERF_RECORD_AUXTRACE),
|
||||
reinterpret_cast<uint8_t *>(&data), attr);
|
||||
PerfEventRecord& perfEventRecord2 =
|
||||
PerfEventRecordFactory::GetPerfEventRecord(static_cast<perf_event_type>(PERF_RECORD_AUXTRACE),
|
||||
reinterpret_cast<uint8_t *>(&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_event_type>(PERF_RECORD_AUXTRACE),
|
||||
reinterpret_cast<uint8_t *>(&data), attr);
|
||||
PerfEventRecord& perfEventRecord2 =
|
||||
PerfEventRecordFactory::GetPerfEventRecord(INT32_MAX,
|
||||
reinterpret_cast<uint8_t *>(&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_event_type>(PERF_RECORD_AUXTRACE),
|
||||
reinterpret_cast<uint8_t *>(&data), attr);
|
||||
|
||||
std::thread t1([&perfEventRecord1, &data, attr]() {
|
||||
PerfEventRecord& perfEventRecord2 =
|
||||
PerfEventRecordFactory::GetPerfEventRecord(static_cast<perf_event_type>(PERF_RECORD_AUXTRACE),
|
||||
reinterpret_cast<uint8_t *>(&data), attr);
|
||||
ASSERT_TRUE(&perfEventRecord1 != &perfEventRecord2);
|
||||
});
|
||||
t1.join();
|
||||
}
|
||||
} // namespace HiPerf
|
||||
} // namespace Developtools
|
||||
|
@ -41,7 +41,7 @@ public:
|
||||
static void TestCodeThread(void);
|
||||
static void RunTestThreads(std::vector<std::thread> &threads);
|
||||
static void SetAllConfig(PerfEvents &event);
|
||||
static bool RecordCount(std::unique_ptr<PerfEventRecord> record);
|
||||
static bool RecordCount(PerfEventRecord& record);
|
||||
static void StatCount(
|
||||
const std::map<std::string, std::unique_ptr<PerfEvents::CountEvent>> &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<PerfEventRecord> 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;
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ using namespace OHOS::HiviewDFX;
|
||||
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)>;
|
||||
class PerfFileReaderTest : public testing::Test {
|
||||
public:
|
||||
static void SetUpTestCase(void);
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <algorithm>
|
||||
#include <cinttypes>
|
||||
#include <condition_variable>
|
||||
#include <cstdlib>
|
||||
#include <mutex>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
@ -2245,10 +2246,24 @@ HWTEST_F(SubCommandStatTest, TestOnSubCommand_app_running, TestSize.Level1)
|
||||
*/
|
||||
HWTEST_F(SubCommandStatTest, CheckPidAndApp, TestSize.Level1)
|
||||
{
|
||||
pid_t existPid = -1;
|
||||
const std::string basePath {"/proc/"};
|
||||
std::vector<std::string> subDirs = GetSubDirs(basePath);
|
||||
for (const auto &subDir : subDirs) {
|
||||
if (!IsDigits(subDir)) {
|
||||
continue;
|
||||
}
|
||||
pid_t pid = std::stoll(subDir);
|
||||
existPid = max(existPid, pid);
|
||||
}
|
||||
std::string cmd = "stat -p " + std::to_string(existPid + rand() % 100 + 1) + " -d 2";
|
||||
EXPECT_EQ(Command::DispatchCommand(cmd), false);
|
||||
|
||||
StdoutRecord stdoutRecord;
|
||||
stdoutRecord.Start();
|
||||
const auto startTime = chrono::steady_clock::now();
|
||||
EXPECT_EQ(Command::DispatchCommand("stat -p 700001 -d 2"), true);
|
||||
std::string existCmd = "stat -p " + std::to_string(existPid) + " -d 2";
|
||||
EXPECT_EQ(Command::DispatchCommand(existCmd), true);
|
||||
const auto costMs = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
chrono::steady_clock::now() - startTime);
|
||||
EXPECT_LE(costMs.count(), defaultRunTimeoutMs);
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include <hilog/log.h>
|
||||
|
||||
#include "symbols_file_test.h"
|
||||
#include "test_utilities.h"
|
||||
|
||||
using namespace testing::ext;
|
||||
using namespace std;
|
||||
@ -42,7 +41,7 @@ public:
|
||||
void LogLevelTest(std::vector<std::string> args, DebugLevel level);
|
||||
default_random_engine rnd_;
|
||||
std::unique_ptr<VirtualRuntime> runtime_;
|
||||
bool RecordCallBack(std::unique_ptr<PerfEventRecord> record);
|
||||
bool RecordCallBack(PerfEventRecord& record);
|
||||
size_t callbackCount_ = 0;
|
||||
|
||||
void PrepareKernelSymbol();
|
||||
@ -70,10 +69,10 @@ void VirtualRuntimeTest::TearDown()
|
||||
runtime_.release();
|
||||
}
|
||||
|
||||
bool VirtualRuntimeTest::RecordCallBack(std::unique_ptr<PerfEventRecord> 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;
|
||||
}
|
||||
|
||||
@ -372,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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user