hmperf: Add server pid

Signed-off-by: Chen Zhongjin <chenzhongjin@huawei.com>
This commit is contained in:
Chen Zhongjin 2023-10-30 11:52:43 +08:00
parent 8cc7cfd3f0
commit 4d61d1b86d
8 changed files with 112 additions and 12 deletions

View File

@ -239,6 +239,7 @@ public:
// used for data_.ips replace (ReplaceWithCallStack)
std::vector<u64> ips_;
std::vector<CallFrame> callFrames_;
std::vector<pid_t> serverPidMap_;
// referenced input(p) in PerfRecordSample, require caller keep input(p) together
PerfRecordSample(uint8_t *p, const perf_event_attr &attr);
@ -261,6 +262,8 @@ public:
data_.id = 0;
header.size = sizeof(header) + sizeof(data_);
};
pid_t GetServerPidof(unsigned int ip_nr);
};
class PerfRecordExit : public PerfEventRecord {

View File

@ -26,6 +26,7 @@ namespace HiPerf {
// description from https://man7.org/linux/man-pages/man2/perf_event_open.2.html
#define SAMPLE_ID_ALL 0
#define PERF_SAMPLE_SERVER_PID (1U << 31)
struct sample_id {
u32 pid;
@ -171,6 +172,8 @@ struct PerfRecordSampleData {
u64 intr_regs[0]; /* if PERF_SAMPLE_REGS_INTR */
u64 phys_addr; /* if PERF_SAMPLE_PHYS_ADDR */
u64 cgroup; /* if PERF_SAMPLE_CGROUP */
u64 server_nr; /* if PERF_SAMPLE_SERVER_PID */
u64 *server_pids; /* if PERF_SAMPLE_SERVER_PID */
};
/*

View File

@ -177,7 +177,7 @@ private:
std::unordered_set<uint64_t> missedRuntimeVaddr_;
#endif
void SymbolicCallFrame(PerfRecordSample &recordSample, uint64_t ip,
perf_callchain_context context);
pid_t server_pid, perf_callchain_context context);
std::vector<std::string> symbolsPaths_;

View File

@ -282,6 +282,11 @@ PerfRecordSample::PerfRecordSample(uint8_t *p, const perf_event_attr &attr)
data_.user_regs = reinterpret_cast<u64 *>(p);
p += data_.reg_nr * sizeof(u64);
}
PopFromBinary(sampleType_ & PERF_SAMPLE_SERVER_PID, p, data_.server_nr);
if (data_.server_nr > 0) {
data_.server_pids = reinterpret_cast<u64 *>(p);
p += data_.server_nr * sizeof(u64);
}
PopFromBinary(sampleType_ & PERF_SAMPLE_STACK_USER, p, data_.stack_size);
if (data_.stack_size > 0) {
data_.stack_data = p;
@ -328,6 +333,11 @@ bool PerfRecordSample::GetBinary(std::vector<uint8_t> &buf) const
std::copy(data_.user_regs, data_.user_regs + data_.reg_nr, reinterpret_cast<u64 *>(p));
p += data_.reg_nr * sizeof(u64);
}
PushToBinary(sampleType_ & PERF_SAMPLE_SERVER_PID, p, data_.server_nr);
if (data_.server_nr > 0) {
std::copy(data_.server_pids, data_.server_pids + data_.server_nr, reinterpret_cast<u64 *>(p));
p += data_.server_nr * sizeof(u64);
}
PushToBinary(sampleType_ & PERF_SAMPLE_STACK_USER, p, data_.stack_size);
if (data_.stack_size > 0) {
std::copy(data_.stack_data, data_.stack_data + data_.stack_size, p);
@ -408,6 +418,12 @@ void PerfRecordSample::DumpData(int indent) const
PrintIndent(indent + 1, "0x%llx\n", data_.user_regs[i]);
}
}
if (sampleType_ & PERF_SAMPLE_SERVER_PID) {
PrintIndent(indent, "server nr=%lld\n", data_.server_nr);
for (uint64_t i = 0; i < data_.server_nr; ++i) {
PrintIndent(indent + 1, "pid: %llu\n", data_.server_pids[i]);
}
}
if (sampleType_ & PERF_SAMPLE_STACK_USER) {
PrintIndent(indent, "user stack: size %llu dyn_size %lld\n", data_.stack_size,
data_.dyn_size);
@ -897,6 +913,48 @@ void PerfRecordSwitchCpuWide::DumpData(int indent) const
PrintIndent(indent, "next_prev_pid %u, next_prev_tid %u\n", data_.next_prev_pid,
data_.next_prev_tid);
}
pid_t PerfRecordSample::GetServerPidof(unsigned int ip_nr)
{
if (!data_.server_nr) {
return data_.pid;
}
// init serverPidMap_
if (!serverPidMap_.size()) {
size_t curr_server = 0;
// ip_nr == 0: server_pid of data_.ip
serverPidMap_.emplace_back(data_.server_pids[curr_server]);
// ip_nr == 1...nr: server_pid of data_.ips[nr]
for (size_t i = 1; i < data_.nr; i++) {
// context change, use next server pid
if (data_.ips[i] >= PERF_CONTEXT_MAX) {
curr_server++;
}
if (curr_server >= data_.server_nr) {
HLOGE("callchain server pid nr %zu out of range", curr_server);
break;
}
serverPidMap_.emplace_back(data_.server_pids[curr_server]);
}
// ip_nr == nr + 1: server_pid of ustack
curr_server++;
if (data_.stack_size) {
if (curr_server >= data_.server_nr) {
HLOGE("ustack server pid nr %zu out of range", curr_server);
} else {
serverPidMap_.emplace_back(data_.server_pids[curr_server]);
}
}
}
// return server pid
if (ip_nr >= serverPidMap_.size()) {
return data_.pid;
} else {
return serverPidMap_[ip_nr];
}
}
} // namespace HiPerf
} // namespace Developtools
} // namespace OHOS

View File

@ -354,6 +354,10 @@ bool PerfEvents::AddEvent(perf_type_id type, __u64 config, bool excludeUser, boo
} else {
eventItem.attr.sample_type = SAMPLE_TYPE;
}
if (isHM_) {
eventItem.attr.sample_type |= PERF_SAMPLE_SERVER_PID;
}
}
// set clock id
@ -1287,6 +1291,11 @@ size_t PerfEvents::GetStackSizePosInSampleRecord(MmapFd &mmap)
pos += reg_nr * sizeof(uint64_t);
}
}
if (mmap.attr->sample_type & PERF_SAMPLE_SERVER_PID) {
uint64_t server_nr = 0;
GetRecordFieldFromMmap(mmap, &server_nr, mmap.mmapPage->data_tail + pos, sizeof(server_nr));
pos += (sizeof(server_nr) + server_nr * sizeof(uint64_t));
}
return pos;
}

View File

@ -297,6 +297,7 @@ static std::map<int, std::string> g_sampleTypeNames = {
{PERF_SAMPLE_IDENTIFIER, "identifier"},
{PERF_SAMPLE_TRANSACTION, "transaction"},
{PERF_SAMPLE_REGS_INTR, "reg_intr"},
{PERF_SAMPLE_SERVER_PID, "server_pid"},
};
void SubCommandDump::DumpSampleType(uint64_t sampleType, int indent)

View File

@ -1491,14 +1491,16 @@ bool SubCommandRecord::CollectionSymbol(std::unique_ptr<PerfEventRecord> record)
#if USE_COLLECT_SYMBOLIC
perf_callchain_context context = record->inKernel() ? PERF_CONTEXT_KERNEL
: PERF_CONTEXT_USER;
pid_t server_pid;
// if no nr use ip
if (sample->data_.nr == 0) {
if (virtualRuntime_.IsKernelThread(sample->data_.pid)) {
kernelThreadSymbolsHits_[sample->data_.pid].insert(sample->data_.ip);
server_pid = sample->GetServerPidof(0);
if (virtualRuntime_.IsKernelThread(server_pid)) {
kernelThreadSymbolsHits_[server_pid].insert(sample->data_.ip);
} else if (context == PERF_CONTEXT_KERNEL) {
kernelSymbolsHits_.insert(sample->data_.ip);
} else {
userSymbolsHits_[sample->data_.pid].insert(sample->data_.ip);
userSymbolsHits_[server_pid].insert(sample->data_.ip);
}
} else {
for (u64 i = 0; i < sample->data_.nr; i++) {
@ -1509,12 +1511,13 @@ bool SubCommandRecord::CollectionSymbol(std::unique_ptr<PerfEventRecord> record)
context = PERF_CONTEXT_USER;
}
} else {
if (virtualRuntime_.IsKernelThread(sample->data_.pid)) {
kernelThreadSymbolsHits_[sample->data_.pid].insert(sample->data_.ips[i]);
server_pid = sample->GetServerPidof(i);
if (virtualRuntime_.IsKernelThread(server_pid)) {
kernelThreadSymbolsHits_[server_pid].insert(sample->data_.ips[i]);
} else if (context == PERF_CONTEXT_KERNEL) {
kernelSymbolsHits_.insert(sample->data_.ips[i]);
} else {
userSymbolsHits_[sample->data_.pid].insert(sample->data_.ips[i]);
userSymbolsHits_[server_pid].insert(sample->data_.ips[i]);
}
}
}

View File

@ -316,9 +316,14 @@ void VirtualRuntime::MakeCallFrame(DfxSymbol &symbol, CallFrame &callFrame)
}
void VirtualRuntime::SymbolicCallFrame(PerfRecordSample &recordSample, uint64_t ip,
perf_callchain_context context)
pid_t server_pid, perf_callchain_context context)
{
auto symbol = GetSymbol(ip, recordSample.data_.pid, recordSample.data_.tid, context);
pid_t pid = recordSample.data_.pid;
pid_t tid = recordSample.data_.tid;
if (server_pid != pid) {
pid = tid = server_pid;
}
auto symbol = GetSymbol(ip, pid, tid, context);
MakeCallFrame(symbol, recordSample.callFrames_.emplace_back(ip, 0));
HLOGV(" (%zu)unwind symbol: %*s%s", recordSample.callFrames_.size(),
static_cast<int>(recordSample.callFrames_.size()), "",
@ -333,8 +338,10 @@ void VirtualRuntime::SymbolicRecord(PerfRecordSample &recordSample)
// Symbolic the Call Stack
recordSample.callFrames_.clear();
perf_callchain_context context = PERF_CONTEXT_MAX;
pid_t server_pid;
if (recordSample.data_.nr == 0) {
SymbolicCallFrame(recordSample, recordSample.data_.ip, PERF_CONTEXT_MAX);
server_pid = recordSample.GetServerPidof(0);
SymbolicCallFrame(recordSample, recordSample.data_.ip, server_pid, PERF_CONTEXT_MAX);
}
for (u64 i = 0; i < recordSample.data_.nr; i++) {
uint64_t ip = recordSample.data_.ips[i];
@ -346,7 +353,8 @@ void VirtualRuntime::SymbolicRecord(PerfRecordSample &recordSample)
// ip 0 or 1 or less than 0
continue;
}
SymbolicCallFrame(recordSample, ip, context);
server_pid = recordSample.GetServerPidof(i);
SymbolicCallFrame(recordSample, ip, server_pid, context);
}
#ifdef HIPERF_DEBUG_TIME
auto usedTime = duration_cast<microseconds>(steady_clock::now() - startTime);
@ -366,7 +374,13 @@ void VirtualRuntime::UnwindFromRecord(PerfRecordSample &recordSample)
HLOGV("unwind record (time:%llu)", recordSample.data_.time);
// if we have userstack ?
if (recordSample.data_.stack_size > 0) {
auto &thread = UpdateThread(recordSample.data_.pid, recordSample.data_.tid);
pid_t server_pid = recordSample.GetServerPidof(recordSample.data_.nr + 1);
pid_t pid = recordSample.data_.pid;
pid_t tid = recordSample.data_.tid;
if (server_pid != pid) {
pid = tid = server_pid;
}
auto &thread = UpdateThread(pid, tid);
callstack_.UnwindCallStack(thread, recordSample.data_.user_abi == PERF_SAMPLE_REGS_ABI_32,
recordSample.data_.user_regs, recordSample.data_.reg_nr,
recordSample.data_.stack_data, recordSample.data_.dyn_size,
@ -381,6 +395,8 @@ void VirtualRuntime::UnwindFromRecord(PerfRecordSample &recordSample)
recordSample.callFrames_.size() - oldSize);
recordSample.ReplaceWithCallStack(oldSize);
// callchain updated, flush server pid map
recordSample.serverPidMap_.clear();
}
#ifdef HIPERF_DEBUG_TIME
@ -398,6 +414,13 @@ void VirtualRuntime::UnwindFromRecord(PerfRecordSample &recordSample)
void VirtualRuntime::UpdateFromRecord(PerfRecordSample &recordSample)
{
UpdateThread(recordSample.data_.pid, recordSample.data_.tid);
if (recordSample.data_.server_nr) {
// update all server threads
for (size_t i = 0; i < recordSample.data_.server_nr; i++) {
pid_t pid = recordSample.data_.server_pids[i];
UpdateThread(pid, pid);
}
}
// unwind
if (disableUnwind_) {
return;