mirror of
https://gitee.com/openharmony/developtools_hiperf
synced 2024-11-23 23:49:58 +00:00
97cb157d7a
Signed-off-by:wenlong12<wenlong12@huawei.com> Signed-off-by: wenlong12 <wenlong12@huawei.com>
436 lines
13 KiB
C++
Executable File
436 lines
13 KiB
C++
Executable File
/*
|
|
* Copyright (c) 2021 Huawei Device Co., Ltd.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#ifndef HIPERF_PERF_EVENT_RECORD_H
|
|
#define HIPERF_PERF_EVENT_RECORD_H
|
|
|
|
#include <atomic>
|
|
#include <chrono>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <stdint.h>
|
|
#include <string>
|
|
#include <sys/types.h>
|
|
#include <unique_fd.h>
|
|
#include <variant>
|
|
#include <vector>
|
|
#include <linux/perf_event.h>
|
|
#include <linux/types.h>
|
|
|
|
#include "debug_logger.h"
|
|
#include "mem_map_item.h"
|
|
#include "perf_record_format.h"
|
|
#include "utilities.h"
|
|
|
|
namespace OHOS {
|
|
namespace Developtools {
|
|
namespace HiPerf {
|
|
static constexpr uint32_t RECORD_SIZE_LIMIT = 65535;
|
|
|
|
enum perf_event_hiperf_ext_type {
|
|
PERF_RECORD_HIPERF_CALLSTACK = UINT32_MAX / 2,
|
|
};
|
|
|
|
struct CallFrame {
|
|
uint64_t ip_ = 0;
|
|
uint64_t sp_ = 0;
|
|
|
|
uint64_t vaddrInFile_ = 0; // in symbol file vaddr
|
|
int32_t symbolIndex_ = -1; // symbols index , should update after sort
|
|
std::string_view symbolName_;
|
|
std::string_view filePath_; // 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;
|
|
if (vaddrInFile_ != 0) {
|
|
output = StringPrintf("va: 0x%016llx(%llx) ", vaddrInFile_, ip_);
|
|
} else {
|
|
output = StringPrintf("ip: 0x%016llx ", ip_);
|
|
}
|
|
output.append(": ");
|
|
output.append(symbolName_);
|
|
|
|
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;
|
|
std::string name; // will be empty in GetAttrSection
|
|
};
|
|
|
|
class PerfEventRecord {
|
|
public:
|
|
PerfEventRecord(const PerfEventRecord &) = delete;
|
|
PerfEventRecord &operator=(const PerfEventRecord &) = delete;
|
|
|
|
struct perf_event_header header;
|
|
const std::string name_ {};
|
|
|
|
PerfEventRecord(perf_event_type type, bool in_kernel, 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 size_t GetSize() const
|
|
{
|
|
return header.size;
|
|
};
|
|
size_t GetHeaderSize() const
|
|
{
|
|
return sizeof(header);
|
|
};
|
|
void GetHeaderBinary(std::vector<uint8_t> &buf) const;
|
|
|
|
uint32_t GetType() const
|
|
{
|
|
return header.type;
|
|
};
|
|
uint16_t GetMisc() const
|
|
{
|
|
return header.misc;
|
|
};
|
|
bool inKernel()
|
|
{
|
|
return header.misc & PERF_RECORD_MISC_KERNEL;
|
|
}
|
|
bool inUser()
|
|
{
|
|
return header.misc & PERF_RECORD_MISC_USER;
|
|
}
|
|
const std::string &GetName() const
|
|
{
|
|
return name_;
|
|
};
|
|
|
|
// to support --exclude-hiperf, return sample_id.pid to filter record,
|
|
virtual pid_t GetPid() const
|
|
{
|
|
return 0;
|
|
};
|
|
|
|
virtual bool GetBinary(std::vector<uint8_t> &buf) const = 0;
|
|
void Dump(int indent = 0) const;
|
|
virtual void DumpData(int indent) const = 0;
|
|
virtual void DumpLog(const std::string &prefix) const;
|
|
};
|
|
|
|
// define convert from linux/perf_event.h
|
|
// description from https://man7.org/linux/man-pages/man2/perf_event_open.2.html
|
|
|
|
constexpr __u64 SAMPLE_ID = PERF_SAMPLE_TID | PERF_SAMPLE_TIME | PERF_SAMPLE_ID |
|
|
PERF_SAMPLE_STREAM_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER;
|
|
|
|
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 PerfRecordMmap : public PerfEventRecord {
|
|
public:
|
|
PerfRecordMmapData data_;
|
|
|
|
PerfRecordMmap(uint8_t *p);
|
|
|
|
PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff,
|
|
const std::string &filename);
|
|
|
|
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
|
virtual void DumpData(int indent) const override;
|
|
virtual void DumpLog(const std::string &prefix) const override;
|
|
};
|
|
|
|
class PerfRecordMmap2 : public PerfEventRecord {
|
|
public:
|
|
PerfRecordMmap2Data data_;
|
|
|
|
PerfRecordMmap2(uint8_t *p);
|
|
|
|
PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff, u32 maj, u32 min,
|
|
u64 ino, u32 prot, u32 flags, const std::string &filename);
|
|
|
|
PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, const MemMapItem &item);
|
|
|
|
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
|
virtual void DumpData(int indent) const override;
|
|
virtual void DumpLog(const std::string &prefix) const override;
|
|
};
|
|
|
|
class PerfRecordLost : public PerfEventRecord {
|
|
public:
|
|
PerfRecordLostData data_;
|
|
|
|
PerfRecordLost(uint8_t *p);
|
|
|
|
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
|
virtual void DumpData(int indent) const override;
|
|
|
|
// only for UT
|
|
PerfRecordLost(bool inKernel, u64 id, u64 lost)
|
|
: PerfEventRecord(PERF_RECORD_LOST, inKernel, "lost")
|
|
{
|
|
data_.id = id;
|
|
data_.lost = lost;
|
|
header.size = sizeof(header) + sizeof(data_);
|
|
}
|
|
};
|
|
|
|
class PerfRecordComm : public PerfEventRecord {
|
|
public:
|
|
PerfRecordCommData data_;
|
|
|
|
PerfRecordComm(uint8_t *p);
|
|
|
|
PerfRecordComm(bool inKernel, u32 pid, u32 tid, const std::string &comm);
|
|
|
|
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
|
virtual void DumpData(int indent) const override;
|
|
void DumpLog(const std::string &prefix) const override;
|
|
};
|
|
|
|
class PerfRecordSample : public PerfEventRecord {
|
|
public:
|
|
PerfRecordSampleData data_ = {};
|
|
uint64_t sampleType_ = SAMPLE_TYPE;
|
|
|
|
// extend
|
|
// hold the new ips memory (after unwind)
|
|
// used for data_.ips replace (ReplaceWithCallStack)
|
|
std::vector<u64> ips_;
|
|
std::vector<CallFrame> callFrames_;
|
|
|
|
// referenced input(p) in PerfRecordSample, require caller keep input(p) together
|
|
PerfRecordSample(uint8_t *p, const perf_event_attr &attr);
|
|
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
|
virtual void DumpData(int indent = 0) const override;
|
|
virtual void DumpLog(const std::string &prefix) const override;
|
|
|
|
// originalSize is use for expand callstack
|
|
void ReplaceWithCallStack(size_t originalSize = 0);
|
|
pid_t GetPid() const override;
|
|
|
|
// 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")
|
|
{
|
|
data_.pid = pid;
|
|
data_.tid = tid;
|
|
data_.period = period;
|
|
data_.time = time;
|
|
data_.id = 0;
|
|
header.size = sizeof(header) + sizeof(data_);
|
|
};
|
|
};
|
|
|
|
class PerfRecordExit : public PerfEventRecord {
|
|
public:
|
|
PerfRecordExitData data_;
|
|
|
|
PerfRecordExit(uint8_t *p);
|
|
|
|
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
|
virtual void DumpData(int indent) const override;
|
|
};
|
|
|
|
class PerfRecordThrottle : public PerfEventRecord {
|
|
public:
|
|
PerfRecordThrottleData data_;
|
|
|
|
PerfRecordThrottle(uint8_t *p);
|
|
|
|
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
|
virtual void DumpData(int indent) const override;
|
|
};
|
|
|
|
class PerfRecordUnthrottle : public PerfEventRecord {
|
|
public:
|
|
PerfRecordThrottleData data_;
|
|
|
|
PerfRecordUnthrottle(uint8_t *p);
|
|
|
|
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
|
virtual void DumpData(int indent) const override;
|
|
};
|
|
|
|
class PerfRecordFork : public PerfEventRecord {
|
|
public:
|
|
PerfRecordForkData data_;
|
|
|
|
PerfRecordFork(uint8_t *p);
|
|
|
|
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
|
virtual void DumpData(int indent) const override;
|
|
};
|
|
|
|
/*
|
|
This record indicates a read event.
|
|
*/
|
|
class PerfRecordRead : public PerfEventRecord {
|
|
public:
|
|
PerfRecordReadData data_;
|
|
|
|
PerfRecordRead(uint8_t *p);
|
|
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
|
virtual void DumpData(int indent) const override;
|
|
};
|
|
|
|
/*
|
|
This record reports that new data is available in the
|
|
separate AUX buffer region.
|
|
|
|
aux_offset
|
|
offset in the AUX mmap region where the new
|
|
data begins.
|
|
aux_size
|
|
size of the data made available.
|
|
flags describes the AUX update.
|
|
PERF_AUX_FLAG_TRUNCATED
|
|
if set, then the data returned was
|
|
truncated to fit the available buffer
|
|
size.
|
|
|
|
PERF_AUX_FLAG_OVERWRITE
|
|
if set, then the data returned has
|
|
overwritten previous data.
|
|
*/
|
|
class PerfRecordAux : public PerfEventRecord {
|
|
public:
|
|
PerfRecordAuxData data_;
|
|
|
|
PerfRecordAux(uint8_t *p);
|
|
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
|
virtual void DumpData(int indent) const override;
|
|
};
|
|
|
|
/*
|
|
This record indicates which process has initiated an
|
|
instruction trace event, allowing tools to properly
|
|
correlate the instruction addresses in the AUX buffer
|
|
with the proper executable.
|
|
|
|
pid process ID of the thread starting an
|
|
instruction trace.
|
|
tid thread ID of the thread starting an instruction
|
|
trace.
|
|
*/
|
|
class PerfRecordItraceStart : public PerfEventRecord {
|
|
public:
|
|
PerfRecordItraceStartData data_;
|
|
|
|
PerfRecordItraceStart(uint8_t *p);
|
|
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
|
virtual void DumpData(int indent) const override;
|
|
};
|
|
|
|
/*
|
|
When using hardware sampling (such as Intel PEBS) this
|
|
record indicates some number of samples that may have
|
|
been lost.
|
|
*/
|
|
class PerfRecordLostSamples : public PerfEventRecord {
|
|
public:
|
|
PerfRecordLostSamplesData data_;
|
|
|
|
PerfRecordLostSamples(uint8_t *p);
|
|
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
|
virtual void DumpData(int indent) const override;
|
|
};
|
|
|
|
/*
|
|
This record indicates a context switch has happened.
|
|
The PERF_RECORD_MISC_SWITCH_OUT bit in the misc field
|
|
indicates whether it was a context switch into or away
|
|
from the current process.
|
|
*/
|
|
class PerfRecordSwitch : public PerfEventRecord {
|
|
public:
|
|
PerfRecordSwitchData data_;
|
|
PerfRecordSwitch(uint8_t *p);
|
|
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
|
virtual void DumpData([[maybe_unused]] int indent) const override {};
|
|
};
|
|
|
|
/*
|
|
As with PERF_RECORD_SWITCH this record indicates a
|
|
context switch has happened, but it only occurs when
|
|
sampling in CPU-wide mode and provides additional
|
|
information on the process being switched to/from.
|
|
The PERF_RECORD_MISC_SWITCH_OUT bit in the misc field
|
|
indicates whether it was a context switch into or away
|
|
from the current process.
|
|
|
|
next_prev_pid
|
|
The process ID of the previous (if switching
|
|
in) or next (if switching out) process on the
|
|
CPU.
|
|
|
|
next_prev_tid
|
|
The thread ID of the previous (if switching in)
|
|
or next (if switching out) thread on the CPU.
|
|
*/
|
|
class PerfRecordSwitchCpuWide : public PerfEventRecord {
|
|
public:
|
|
PerfRecordSwitchCpuWideData data_;
|
|
PerfRecordSwitchCpuWide(uint8_t *p);
|
|
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
|
virtual void DumpData(int indent) const override;
|
|
};
|
|
|
|
std::unique_ptr<PerfEventRecord> GetPerfEventRecord(const int type, uint8_t *data,
|
|
const perf_event_attr &attr);
|
|
|
|
template<typename T>
|
|
void PushToBinary(bool condition, uint8_t *&p, const T &v);
|
|
|
|
template<typename T1, typename T2>
|
|
void PushToBinary2(bool condition, uint8_t *&p, const T1 &v1, const T2 &v2);
|
|
|
|
template<typename T>
|
|
void PopFromBinary(bool condition, uint8_t *&p, T &v);
|
|
|
|
template<typename T1, typename T2>
|
|
void PopFromBinary2(bool condition, uint8_t *&p, T1 &v1, T2 &v2);
|
|
} // namespace HiPerf
|
|
} // namespace Developtools
|
|
} // namespace OHOS
|
|
#endif |