• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #define HILOG_TAG "PerfRecord"
16 
17 #include "perf_event_record.h"
18 #include <cinttypes>
19 
20 #include "utilities.h"
21 
22 using namespace OHOS::HiviewDFX;
23 using namespace std;
24 namespace OHOS {
25 namespace Developtools {
26 namespace HiPerf {
27 
28 void *g_sampleMemCache = nullptr; // for read record from buf thread
29 void *g_sampleMemCacheMain = nullptr; // for main thread:collecttionsymbol
30 constexpr size_t SAMPLE_CACHE_SIZE = 4 * 1024;
31 
GetPerfEventRecord(const int type,uint8_t * p,const perf_event_attr & attr)32 std::unique_ptr<PerfEventRecord> GetPerfEventRecord(const int type, uint8_t *p,
33                                                     const perf_event_attr &attr)
34 {
35     HLOG_ASSERT(p);
36     uint8_t *data = p;
37 
38     // check kernel
39     switch (type) {
40         case PERF_RECORD_SAMPLE:
41             return std::make_unique<PerfRecordSample>(data, attr);
42         case PERF_RECORD_MMAP:
43             return std::make_unique<PerfRecordMmap>(data);
44         case PERF_RECORD_MMAP2:
45             return std::make_unique<PerfRecordMmap2>(data);
46         case PERF_RECORD_LOST:
47             return std::make_unique<PerfRecordLost>(data);
48         case PERF_RECORD_COMM:
49             return std::make_unique<PerfRecordComm>(data);
50         case PERF_RECORD_EXIT:
51             return std::make_unique<PerfRecordExit>(data);
52         case PERF_RECORD_THROTTLE:
53             return std::make_unique<PerfRecordThrottle>(data);
54         case PERF_RECORD_UNTHROTTLE:
55             return std::make_unique<PerfRecordUnthrottle>(data);
56         case PERF_RECORD_FORK:
57             return std::make_unique<PerfRecordFork>(data);
58         case PERF_RECORD_READ:
59             return std::make_unique<PerfRecordRead>(data);
60         case PERF_RECORD_AUX:
61             return std::make_unique<PerfRecordAux>(data);
62         case PERF_RECORD_ITRACE_START:
63             return std::make_unique<PerfRecordItraceStart>(data);
64         case PERF_RECORD_LOST_SAMPLES:
65             return std::make_unique<PerfRecordLostSamples>(data);
66         case PERF_RECORD_SWITCH:
67             return std::make_unique<PerfRecordSwitch>(data);
68         case PERF_RECORD_SWITCH_CPU_WIDE:
69             return std::make_unique<PerfRecordSwitchCpuWide>(data);
70         default:
71             HLOGE("unknown record type %d\n", type);
72             return nullptr;
73     }
74 }
75 
GetPerfSampleFromCache(const int type,uint8_t * p,const perf_event_attr & attr)76 std::unique_ptr<PerfEventRecord> GetPerfSampleFromCache(const int type, uint8_t *p,
77                                                         const perf_event_attr &attr)
78 {
79     HLOG_ASSERT(p);
80     uint8_t *data = p;
81 
82     if (type == PERF_RECORD_SAMPLE) {
83         if (g_sampleMemCache != nullptr) {
84             memset_s(g_sampleMemCache, SAMPLE_CACHE_SIZE, 0, SAMPLE_CACHE_SIZE);
85             return std::unique_ptr<PerfEventRecord>(new (g_sampleMemCache) PerfRecordSample(data, attr));
86         } else {
87             g_sampleMemCache = std::malloc(SAMPLE_CACHE_SIZE);
88             memset_s(g_sampleMemCache, SAMPLE_CACHE_SIZE, 0, SAMPLE_CACHE_SIZE);
89             return std::unique_ptr<PerfEventRecord>(new (g_sampleMemCache) PerfRecordSample(data, attr));
90         }
91     }
92     return GetPerfEventRecord(type, p, attr);
93 }
94 
GetPerfSampleFromCacheMain(const int type,uint8_t * p,const perf_event_attr & attr)95 std::unique_ptr<PerfEventRecord> GetPerfSampleFromCacheMain(const int type, uint8_t *p,
96                                                             const perf_event_attr &attr)
97 {
98     HLOG_ASSERT(p);
99     uint8_t *data = p;
100 
101     if (type == PERF_RECORD_SAMPLE) {
102         if (g_sampleMemCacheMain != nullptr) {
103             memset_s(g_sampleMemCacheMain, SAMPLE_CACHE_SIZE, 0, SAMPLE_CACHE_SIZE);
104             return std::unique_ptr<PerfEventRecord>(new (g_sampleMemCacheMain) PerfRecordSample(data, attr));
105         } else {
106             g_sampleMemCacheMain = std::malloc(SAMPLE_CACHE_SIZE);
107             memset_s(g_sampleMemCacheMain, SAMPLE_CACHE_SIZE, 0, SAMPLE_CACHE_SIZE);
108             return std::unique_ptr<PerfEventRecord>(new (g_sampleMemCacheMain) PerfRecordSample(data, attr));
109         }
110     }
111     return GetPerfEventRecord(type, p, attr);
112 }
113 
114 template<typename T>
PushToBinary(bool condition,uint8_t * & p,const T & v)115 inline void PushToBinary(bool condition, uint8_t *&p, const T &v)
116 {
117     if (condition) {
118         *(reinterpret_cast<T *>(p)) = v;
119         p += sizeof(T);
120     }
121 }
122 
123 template<typename T1, typename T2>
PushToBinary2(bool condition,uint8_t * & p,const T1 & v1,const T2 & v2)124 inline void PushToBinary2(bool condition, uint8_t *&p, const T1 &v1, const T2 &v2)
125 {
126     if (condition) {
127         *(reinterpret_cast<T1 *>(p)) = v1;
128         p += sizeof(T1);
129         *(reinterpret_cast<T2 *>(p)) = v2;
130         p += sizeof(T2);
131     }
132 }
133 
134 template<typename T>
PopFromBinary(bool condition,uint8_t * & p,T & v)135 inline void PopFromBinary(bool condition, uint8_t *&p, T &v)
136 {
137     if (condition) {
138         v = *(reinterpret_cast<const T *>(p));
139         p += sizeof(T);
140     }
141 }
142 
143 template<typename T1, typename T2>
PopFromBinary2(bool condition,uint8_t * & p,T1 & v1,T2 & v2)144 inline void PopFromBinary2(bool condition, uint8_t *&p, T1 &v1, T2 &v2)
145 {
146     if (condition) {
147         v1 = *(reinterpret_cast<const T1 *>(p));
148         p += sizeof(T1);
149         v2 = *(reinterpret_cast<const T2 *>(p));
150         p += sizeof(T2);
151     }
152 }
153 
154 // PerfEventRecord
PerfEventRecord(perf_event_type type,bool inKernel,const std::string & name)155 PerfEventRecord::PerfEventRecord(perf_event_type type, bool inKernel, const std::string &name)
156     : name_(name)
157 {
158     header.type = type;
159     header.misc = inKernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER;
160     header.size = sizeof(header);
161 }
162 
PerfEventRecord(perf_event_hiperf_ext_type type,const std::string & name)163 PerfEventRecord::PerfEventRecord(perf_event_hiperf_ext_type type, const std::string &name)
164     : name_(name)
165 {
166     header.type = type;
167     header.misc = PERF_RECORD_MISC_USER;
168     header.size = sizeof(header);
169 }
170 
PerfEventRecord(uint8_t * p,const std::string & name)171 PerfEventRecord::PerfEventRecord(uint8_t *p, const std::string &name) : name_(name)
172 {
173     header = *(reinterpret_cast<perf_event_header *>(p));
174 }
175 
GetHeaderBinary(std::vector<uint8_t> & buf) const176 void PerfEventRecord::GetHeaderBinary(std::vector<uint8_t> &buf) const
177 {
178     if (buf.size() < GetHeaderSize()) {
179         buf.resize(GetHeaderSize());
180     }
181     uint8_t *p = buf.data();
182     *(reinterpret_cast<perf_event_header *>(p)) = header;
183 }
184 
Dump(int indent,std::string outputFilename,FILE * outputDump) const185 void PerfEventRecord::Dump(int indent, std::string outputFilename, FILE *outputDump) const
186 {
187     if (outputDump != nullptr) {
188         g_outputDump = outputDump;
189     } else if (!outputFilename.empty() && g_outputDump == nullptr) {
190         std::string resolvedPath = CanonicalizeSpecPath(outputFilename.c_str());
191         g_outputDump = fopen(resolvedPath.c_str(), "w");
192         if (g_outputDump == nullptr) {
193             printf("unable open file to '%s' because '%d'\n", outputFilename.c_str(), errno);
194             return;
195         }
196     }
197     PRINT_INDENT(indent, "\n");
198     PRINT_INDENT(indent, "record %s: type %u, misc %u, size %zu\n", GetName().c_str(), GetType(),
199                  GetMisc(), GetSize());
200     DumpData(indent + 1);
201 }
202 
DumpLog(const std::string & prefix) const203 void PerfEventRecord::DumpLog(const std::string &prefix) const
204 {
205     HLOGV("%s: record %s: type %u, misc %u, size %zu\n", prefix.c_str(), GetName().c_str(),
206           GetType(), GetMisc(), GetSize());
207 }
208 
209 std::vector<u64> PerfRecordSample::ips_ = {};
210 std::vector<DfxFrame> PerfRecordSample::callFrames_ = {};
211 std::vector<pid_t> PerfRecordSample::serverPidMap_ = {};
212 
DumpLog(const std::string & prefix) const213 void PerfRecordSample::DumpLog(const std::string &prefix) const
214 {
215     HLOGV("%s: SAMPLE: id= %llu size %d pid %u tid %u ips %llu regs %llu, stacks %llu time %llu",
216           prefix.c_str(), data_.sample_id, header.size, data_.pid, data_.tid, data_.nr,
217           data_.reg_nr, data_.dyn_size, data_.time);
218 }
219 
RecoverCallStack()220 void PerfRecordSample::RecoverCallStack()
221 {
222     data_.ips = ips_.data();
223     data_.nr = ips_.size();
224     removeStack_ = true;
225 }
226 
ReplaceWithCallStack(size_t originalSize)227 void PerfRecordSample::ReplaceWithCallStack(size_t originalSize)
228 {
229     // first we check if we have some user unwind stack need to merge ?
230     if (callFrames_.size() != 0) {
231         // when we have some kernel ips , we cp it first
232         // new size is user call frames + kernel call frames
233         // + PERF_CONTEXT_USER(last + 1) + expand mark(also PERF_CONTEXT_USER)
234         const unsigned int perfContextSize = 2;
235         ips_.reserve(data_.nr + callFrames_.size() + perfContextSize);
236         if (data_.nr > 0) {
237             ips_.assign(data_.ips, data_.ips + data_.nr);
238         }
239         // add user context mark
240         ips_.emplace_back(PERF_CONTEXT_USER);
241         // we also need make a expand mark just for debug only
242         const size_t beginIpsSize = ips_.size();
243         bool ret = std::all_of(callFrames_.begin(), callFrames_.end(), [&](const DfxFrame &frame) {
244             ips_.emplace_back(frame.pc);
245             if (originalSize != 0 and (originalSize != callFrames_.size()) and
246                 ips_.size() == (originalSize + beginIpsSize)) {
247                 // just for debug
248                 // so we can see which frame begin is expand call frames
249                 ips_.emplace_back(PERF_CONTEXT_USER);
250             }
251             return true;
252         });
253         if (ret) {
254             HLOGV("combed %zu", callFrames_.size());
255         } else {
256             HLOGV("failed to combed %zu", callFrames_.size());
257         }
258 
259         if (sampleType_ & PERF_SAMPLE_REGS_USER) {
260             header.size -= data_.reg_nr * sizeof(u64);
261             data_.reg_nr = 0;
262             data_.user_abi = 0;
263         }
264 
265         if (sampleType_ & PERF_SAMPLE_STACK_USER) {
266             // 1. remove the user stack
267             header.size -= data_.stack_size;
268             header.size -= sizeof(data_.dyn_size);
269 
270             // 2. clean the size
271             data_.stack_size = 0;
272             data_.dyn_size = 0;
273         }
274 
275         if (sampleType_ & PERF_SAMPLE_CALLCHAIN) {
276             HLOGV("ips change from %llu -> %zu", data_.nr, ips_.size());
277 
278             // 3. remove the nr size
279             header.size -= data_.nr * sizeof(u64);
280 
281             // 4. add new nr size
282             data_.nr = ips_.size();
283             header.size += data_.nr * sizeof(u64);
284 
285             // 5. change ips potin to our ips array and hold it.
286             data_.ips = ips_.data();
287         }
288     } else {
289         // nothing need change
290         return;
291     }
292 }
293 
PerfRecordSample(uint8_t * p,const perf_event_attr & attr)294 PerfRecordSample::PerfRecordSample(uint8_t *p, const perf_event_attr &attr)
295     : PerfEventRecord(p, "sample")
296 {
297     if (p == nullptr) {
298         HLOG_ASSERT(p);
299         return;
300     }
301     // clear the static vector data
302     Clean();
303     sampleType_ = attr.sample_type;
304 
305     uint8_t *start = p;
306 
307     p += sizeof(header);
308 
309     // parse record according SAMPLE_TYPE
310     PopFromBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id);
311     PopFromBinary(sampleType_ & PERF_SAMPLE_IP, p, data_.ip);
312     PopFromBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.pid, data_.tid);
313     PopFromBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.time);
314     PopFromBinary(sampleType_ & PERF_SAMPLE_ADDR, p, data_.addr);
315     PopFromBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.id);
316     PopFromBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.stream_id);
317     PopFromBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.cpu, data_.res);
318     PopFromBinary(sampleType_ & PERF_SAMPLE_PERIOD, p, data_.period);
319     PopFromBinary(sampleType_ & PERF_SAMPLE_CALLCHAIN, p, data_.nr);
320     if (data_.nr > 0) {
321         // the pointer is from input(p), require caller keep input(p) with *this together
322         // think it in next time
323         data_.ips = reinterpret_cast<u64 *>(p);
324         p += data_.nr * sizeof(u64);
325     }
326     PopFromBinary(sampleType_ & PERF_SAMPLE_RAW, p, data_.raw_size);
327     if (data_.raw_size > 0) {
328         data_.raw_data = p;
329         p += data_.raw_size * sizeof(u8);
330     }
331     PopFromBinary(sampleType_ & PERF_SAMPLE_BRANCH_STACK, p, data_.bnr);
332     if (data_.bnr > 0) {
333         data_.lbr = reinterpret_cast<perf_branch_entry *>(p);
334         p += data_.bnr * sizeof(perf_branch_entry);
335     }
336     PopFromBinary(sampleType_ & PERF_SAMPLE_REGS_USER, p, data_.user_abi);
337     if (data_.user_abi > 0) {
338         data_.reg_mask = attr.sample_regs_user;
339         data_.reg_nr = __builtin_popcountll(data_.reg_mask);
340         data_.user_regs = reinterpret_cast<u64 *>(p);
341         p += data_.reg_nr * sizeof(u64);
342     }
343     PopFromBinary(sampleType_ & PERF_SAMPLE_SERVER_PID, p, data_.server_nr);
344     if (data_.server_nr > 0) {
345         data_.server_pids = reinterpret_cast<u64 *>(p);
346         p += data_.server_nr * sizeof(u64);
347     }
348     PopFromBinary(sampleType_ & PERF_SAMPLE_STACK_USER, p, data_.stack_size);
349     if (data_.stack_size > 0) {
350         data_.stack_data = p;
351         p += data_.stack_size;
352         PopFromBinary(true, p, data_.dyn_size);
353     }
354     uint32_t remain = header.size - (p - start);
355     if (data_.nr == 0 && dumpRemoveStack_ && remain == sizeof(stackId_)) {
356         PopFromBinary(true, p, stackId_.value);
357     }
358 }
359 
GetBinary(std::vector<uint8_t> & buf) const360 bool PerfRecordSample::GetBinary(std::vector<uint8_t> &buf) const
361 {
362     if (buf.size() < GetSize()) {
363         buf.resize(GetSize());
364     }
365 
366     GetHeaderBinary(buf);
367     uint8_t *p = buf.data() + GetHeaderSize();
368 
369     PushToBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id);
370     PushToBinary(sampleType_ & PERF_SAMPLE_IP, p, data_.ip);
371     PushToBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.pid, data_.tid);
372     PushToBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.time);
373     PushToBinary(sampleType_ & PERF_SAMPLE_ADDR, p, data_.addr);
374     PushToBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.id);
375     PushToBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.stream_id);
376     PushToBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.cpu, data_.res);
377     PushToBinary(sampleType_ & PERF_SAMPLE_PERIOD, p, data_.period);
378     PushToBinary(sampleType_ & PERF_SAMPLE_CALLCHAIN, p, data_.nr);
379     if (data_.nr > 0 && !removeStack_) {
380         std::copy(data_.ips + skipKernel_, data_.ips + data_.nr + skipKernel_,
381                   reinterpret_cast<u64 *>(p));
382         p += data_.nr * sizeof(u64);
383     }
384     PushToBinary(sampleType_ & PERF_SAMPLE_RAW, p, data_.raw_size);
385     if (data_.raw_size > 0) {
386         std::copy(data_.raw_data, data_.raw_data + data_.raw_size, p);
387         p += data_.raw_size * sizeof(u8);
388     }
389     PushToBinary(sampleType_ & PERF_SAMPLE_BRANCH_STACK, p, data_.bnr);
390     if (data_.bnr > 0) {
391         std::copy(data_.lbr, data_.lbr + data_.bnr, reinterpret_cast<perf_branch_entry *>(p));
392         p += data_.bnr * sizeof(perf_branch_entry);
393     }
394     PushToBinary(sampleType_ & PERF_SAMPLE_REGS_USER, p, data_.user_abi);
395     if (data_.user_abi > 0 && data_.reg_nr > 0) {
396         std::copy(data_.user_regs, data_.user_regs + data_.reg_nr, reinterpret_cast<u64 *>(p));
397         p += data_.reg_nr * sizeof(u64);
398     }
399     PushToBinary(sampleType_ & PERF_SAMPLE_SERVER_PID, p, data_.server_nr);
400     if (data_.server_nr > 0) {
401         std::copy(data_.server_pids + skipPid_, data_.server_pids + data_.server_nr + skipPid_,
402                   reinterpret_cast<u64 *>(p));
403         p += data_.server_nr * sizeof(u64);
404     }
405     PushToBinary(sampleType_ & PERF_SAMPLE_STACK_USER, p, data_.stack_size);
406     if (data_.stack_size > 0) {
407         std::copy(data_.stack_data, data_.stack_data + data_.stack_size, p);
408         p += data_.stack_size * sizeof(u8);
409         PushToBinary(true, p, data_.dyn_size);
410     }
411     PushToBinary(removeStack_, p, stackId_.value);
412     return true;
413 }
414 
DumpData(int indent) const415 void PerfRecordSample::DumpData(int indent) const
416 {
417     PRINT_INDENT(indent, "sample_type: 0x%" PRIx64 "\n", sampleType_);
418 
419     // dump record according sampleType
420     if (sampleType_ & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) {
421         PRINT_INDENT(indent, "ID %" PRIu64 "\n", static_cast<uint64_t>(data_.sample_id));
422     }
423     if (sampleType_ & PERF_SAMPLE_IP) {
424         PRINT_INDENT(indent, "ip %llx\n", data_.ip);
425     }
426     if (sampleType_ & PERF_SAMPLE_TID) {
427         PRINT_INDENT(indent, "pid %u, tid %u\n", data_.pid, data_.tid);
428     }
429     if (sampleType_ & PERF_SAMPLE_TIME) {
430         PRINT_INDENT(indent, "time %llu\n", data_.time);
431     }
432     if (sampleType_ & PERF_SAMPLE_ADDR) {
433         PRINT_INDENT(indent, "addr %p\n", reinterpret_cast<void *>(data_.addr));
434     }
435     if (sampleType_ & PERF_SAMPLE_STREAM_ID) {
436         PRINT_INDENT(indent, "stream_id %" PRIu64 "\n", static_cast<uint64_t>(data_.stream_id));
437     }
438     if (sampleType_ & PERF_SAMPLE_CPU) {
439         PRINT_INDENT(indent, "cpu %u, res %u\n", data_.cpu, data_.res);
440     }
441     if (sampleType_ & PERF_SAMPLE_PERIOD) {
442         PRINT_INDENT(indent, "period %" PRIu64 "\n", static_cast<uint64_t>(data_.period));
443     }
444     if (stackId_.section.id > 0) {
445         PRINT_INDENT(indent, "stackid %" PRIu64 "\n", static_cast<uint64_t>(stackId_.section.id));
446     }
447     if (sampleType_ & PERF_SAMPLE_CALLCHAIN) {
448         bool userContext = false;
449         PRINT_INDENT(indent, "callchain nr=%lld\n", data_.nr);
450         for (uint64_t i = 0; i < data_.nr; ++i) {
451             std::string_view supplement = "";
452             if ((sampleType_ & PERF_SAMPLE_STACK_USER) == 0 || data_.ips[i] != PERF_CONTEXT_USER) {
453                 PRINT_INDENT(indent + 1, "0x%llx%s\n", data_.ips[i], supplement.data());
454                 continue;
455             }
456             // is PERF_SAMPLE_STACK_USER type and is PERF_CONTEXT_USER
457             if (!userContext) {
458                 userContext = true;
459                 supplement = " <unwind callstack>";
460             } else {
461                 supplement = " <expand callstack>";
462             }
463             PRINT_INDENT(indent + 1, "0x%llx%s\n", data_.ips[i], supplement.data());
464         }
465     }
466     if (sampleType_ & PERF_SAMPLE_RAW) {
467         PRINT_INDENT(indent, "raw size=%u\n", data_.raw_size);
468         const uint32_t *data = reinterpret_cast<const uint32_t *>(data_.raw_data);
469         size_t size = data_.raw_size / sizeof(uint32_t);
470         for (size_t i = 0; i < size; ++i) {
471             PRINT_INDENT(indent + 1, "0x%08x (%x)\n", data[i], data[i]);
472         }
473     }
474     if (sampleType_ & PERF_SAMPLE_BRANCH_STACK) {
475         PRINT_INDENT(indent, "branch_stack nr=%lld\n", data_.bnr);
476         for (uint64_t i = 0; i < data_.bnr; ++i) {
477             auto &item = data_.lbr[i];
478             PRINT_INDENT(indent + 1, "from 0x%llx, to 0x%llx %s%s\n", item.from, item.to,
479                          item.mispred ? "mispred" : "", item.predicted ? "predicted" : "");
480         }
481     }
482     if (sampleType_ & PERF_SAMPLE_REGS_USER) {
483         PRINT_INDENT(indent, "user regs: abi=%lld, reg_nr=%lld\n", data_.user_abi, data_.reg_nr);
484         for (uint64_t i = 0; i < data_.reg_nr; ++i) {
485             PRINT_INDENT(indent + 1, "0x%llx\n", data_.user_regs[i]);
486         }
487     }
488     if (sampleType_ & PERF_SAMPLE_SERVER_PID) {
489         PRINT_INDENT(indent, "server nr=%lld\n", data_.server_nr);
490         for (uint64_t i = 0; i < data_.server_nr; ++i) {
491             PRINT_INDENT(indent + 1, "pid: %llu\n", data_.server_pids[i]);
492         }
493     }
494     if (sampleType_ & PERF_SAMPLE_STACK_USER) {
495         PRINT_INDENT(indent, "user stack: size %llu dyn_size %lld\n", data_.stack_size,
496                      data_.dyn_size);
497     }
498 }
499 
GetPid() const500 inline pid_t PerfRecordSample::GetPid() const
501 {
502     return data_.pid;
503 }
504 
Clean()505 void PerfRecordSample::Clean()
506 {
507     ips_.clear();
508     callFrames_.clear();
509     serverPidMap_.clear();
510 }
511 
PerfRecordMmap(uint8_t * p)512 PerfRecordMmap::PerfRecordMmap(uint8_t *p) : PerfEventRecord(p, "mmap")
513 {
514     size_t copySize = GetSize() - sizeof(header);
515     if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
516         HLOGE("memcpy_s retren failed !!!");
517     }
518 }
519 
PerfRecordMmap(bool inKernel,u32 pid,u32 tid,u64 addr,u64 len,u64 pgoff,const std::string & filename)520 PerfRecordMmap::PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff,
521                                const std::string &filename)
522     : PerfEventRecord(PERF_RECORD_MMAP, inKernel, "mmap")
523 {
524     data_.pid = pid;
525     data_.tid = tid;
526     data_.addr = addr;
527     data_.len = len;
528     data_.pgoff = pgoff;
529     if (strncpy_s(data_.filename, KILO, filename.c_str(), filename.size()) != 0) {
530         HLOGE("strncpy_s failed");
531     }
532 
533     header.size = sizeof(header) + sizeof(data_) - KILO + filename.size() + 1;
534 }
535 
GetBinary(std::vector<uint8_t> & buf) const536 bool PerfRecordMmap::GetBinary(std::vector<uint8_t> &buf) const
537 {
538     if (buf.size() < GetSize()) {
539         buf.resize(GetSize());
540     }
541 
542     GetHeaderBinary(buf);
543     uint8_t *p = buf.data() + GetHeaderSize();
544 
545     // data_.filename[] is variable-length
546     std::copy(reinterpret_cast<const uint8_t *>(&data_),
547               reinterpret_cast<const uint8_t *>(&data_) + GetSize() - GetHeaderSize(), p);
548     return true;
549 }
550 
DumpData(int indent) const551 void PerfRecordMmap::DumpData(int indent) const
552 {
553     PRINT_INDENT(indent, "pid %u, tid %u, addr 0x%llx, len 0x%llx\n", data_.pid, data_.tid,
554                  data_.addr, data_.len);
555     PRINT_INDENT(indent, "pgoff 0x%llx, filename %s\n", data_.pgoff, data_.filename);
556 }
557 
DumpLog(const std::string & prefix) const558 void PerfRecordMmap::DumpLog(const std::string &prefix) const
559 {
560     HLOGV("%s:  MMAP: size %d pid %u tid %u dso '%s' (0x%llx-0x%llx)@0x%llx", prefix.c_str(),
561           header.size, data_.pid, data_.tid, data_.filename, data_.addr, data_.addr + data_.len, data_.pgoff);
562 }
563 
PerfRecordMmap2(uint8_t * p)564 PerfRecordMmap2::PerfRecordMmap2(uint8_t *p) : PerfEventRecord(p, "mmap2")
565 {
566     size_t copySize = GetSize() - sizeof(header);
567     if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
568         HLOGE("memcpy_s retren failed !!!");
569     }
570 }
571 
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)572 PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff,
573                                  u32 maj, u32 min, u64 ino, u32 prot, u32 flags,
574                                  const std::string &filename)
575     : PerfEventRecord(PERF_RECORD_MMAP2, inKernel, "mmap2")
576 {
577     data_.pid = pid;
578     data_.tid = tid;
579     data_.addr = addr;
580     data_.len = len;
581     data_.pgoff = pgoff;
582     data_.maj = maj;
583     data_.min = min;
584     data_.ino = ino;
585     data_.ino_generation = 0;
586     data_.prot = prot;
587     data_.flags = flags;
588     if (strncpy_s(data_.filename, KILO, filename.c_str(), filename.size()) != 0) {
589         HLOGE("strncpy_s failed");
590     }
591 
592     header.size = sizeof(header) + sizeof(data_) - KILO + filename.size() + 1;
593 }
594 
PerfRecordMmap2(bool inKernel,u32 pid,u32 tid,std::shared_ptr<DfxMap> item)595 PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, std::shared_ptr<DfxMap> item)
596     : PerfEventRecord(PERF_RECORD_MMAP2, inKernel, "mmap2")
597 {
598     data_.pid = pid;
599     data_.tid = tid;
600     if (item != nullptr) {
601         data_.addr = item->begin;
602         data_.len = item->end - item->begin;
603         data_.pgoff = item->offset;
604         data_.maj = item->major;
605         data_.min = item->minor;
606         data_.ino = item->inode;
607         data_.ino_generation = 0;
608         // r--p 00000000 103:3e 12307                         /data/storage/el1/bundle/entry.hap
609         // why prot get from this is 7. rwxp
610         DfxMap::PermsToProts(item->perms, data_.prot, data_.flags);
611         if (strncpy_s(data_.filename, KILO, item->name.c_str(), item->name.size()) != 0) {
612             HLOGE("strncpy_s failed");
613         }
614 
615         header.size = sizeof(header) + sizeof(data_) - KILO + item->name.size() + 1;
616     } else {
617         data_.addr = 0;
618         data_.len = 0;
619         data_.pgoff = 0;
620         data_.maj = 0;
621         data_.min = 0;
622         data_.ino = 0;
623         data_.ino_generation = 0;
624         if (memset_s(data_.filename, KILO, 0, KILO) != EOK) {
625             HLOGE("memset_s failed");
626         }
627     }
628 }
629 
GetBinary(std::vector<uint8_t> & buf) const630 bool PerfRecordMmap2::GetBinary(std::vector<uint8_t> &buf) const
631 {
632     if (buf.size() < GetSize()) {
633         buf.resize(GetSize());
634     }
635 
636     GetHeaderBinary(buf);
637     uint8_t *p = buf.data() + GetHeaderSize();
638 
639     // data_.filename[] is variable-length
640     std::copy(reinterpret_cast<const uint8_t *>(&data_),
641               reinterpret_cast<const uint8_t *>(&data_) + GetSize() - GetHeaderSize(), p);
642     return true;
643 }
644 
DumpData(int indent) const645 void PerfRecordMmap2::DumpData(int indent) const
646 {
647     PRINT_INDENT(indent, "pid %u, tid %u, addr 0x%llx, len 0x%llx\n", data_.pid, data_.tid,
648                  data_.addr, data_.len);
649     PRINT_INDENT(indent, "pgoff 0x%llx, maj %u, min %u, ino %llu, ino_generation %llu\n",
650                  data_.pgoff, data_.maj, data_.min, data_.ino, data_.ino_generation);
651     PRINT_INDENT(indent, "prot %u, flags %u, filename %s\n", data_.prot, data_.flags,
652                  data_.filename);
653 }
DumpLog(const std::string & prefix) const654 void PerfRecordMmap2::DumpLog(const std::string &prefix) const
655 {
656     HLOGV("%s:  MMAP2: size %d pid %u tid %u dso '%s' (0x%llx-0x%llx)@0x%llx", prefix.c_str(),
657           header.size, data_.pid, data_.tid, data_.filename, data_.addr, data_.addr + data_.len,
658           data_.pgoff);
659 }
660 
PerfRecordLost(uint8_t * p)661 PerfRecordLost::PerfRecordLost(uint8_t *p) : PerfEventRecord(p, "lost")
662 {
663     size_t copySize = GetSize() - sizeof(header);
664     if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
665         HLOGE("memcpy_s retren failed !!!");
666     }
667 }
668 
GetBinary(std::vector<uint8_t> & buf) const669 bool PerfRecordLost::GetBinary(std::vector<uint8_t> &buf) const
670 {
671     if (buf.size() < GetSize()) {
672         buf.resize(GetSize());
673     }
674 
675     GetHeaderBinary(buf);
676     uint8_t *p = buf.data() + GetHeaderSize();
677 
678     auto pDest = reinterpret_cast<PerfRecordLostData *>(p);
679     *pDest = data_;
680 
681     return true;
682 }
683 
DumpData(int indent) const684 void PerfRecordLost::DumpData(int indent) const
685 {
686     PRINT_INDENT(indent, "id %llu, lost %llu\n", data_.id, data_.lost);
687 }
688 
PerfRecordComm(uint8_t * p)689 PerfRecordComm::PerfRecordComm(uint8_t *p) : PerfEventRecord(p, "comm")
690 {
691     size_t copySize = GetSize() - sizeof(header);
692     if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
693         HLOGE("memcpy_s retren failed !!!");
694     }
695 }
696 
PerfRecordComm(bool inKernel,u32 pid,u32 tid,const std::string & comm)697 PerfRecordComm::PerfRecordComm(bool inKernel, u32 pid, u32 tid, const std::string &comm)
698     : PerfEventRecord(PERF_RECORD_COMM, inKernel, "comm")
699 {
700     data_.pid = pid;
701     data_.tid = tid;
702     if (strncpy_s(data_.comm, KILO, comm.c_str(), comm.size()) != 0) {
703         HLOGE("strncpy_s failed !!!");
704     }
705 
706     header.size = sizeof(header) + sizeof(data_) - KILO + comm.size() + 1;
707 }
708 
GetBinary(std::vector<uint8_t> & buf) const709 bool PerfRecordComm::GetBinary(std::vector<uint8_t> &buf) const
710 {
711     if (buf.size() < GetSize()) {
712         buf.resize(GetSize());
713     }
714 
715     GetHeaderBinary(buf);
716     uint8_t *p = buf.data() + GetHeaderSize();
717 
718     // data_.comm[] is variable-length
719     std::copy(reinterpret_cast<const uint8_t *>(&data_),
720               reinterpret_cast<const uint8_t *>(&data_) + GetSize() - GetHeaderSize(), p);
721 
722     return true;
723 }
724 
DumpData(int indent) const725 void PerfRecordComm::DumpData(int indent) const
726 {
727     PRINT_INDENT(indent, "pid %u, tid %u, comm %s\n", data_.pid, data_.tid, data_.comm);
728 }
729 
DumpLog(const std::string & prefix) const730 void PerfRecordComm::DumpLog(const std::string &prefix) const
731 {
732     HLOGV("pid %u, tid %u, comm %s\n", data_.pid, data_.tid, data_.comm);
733 }
734 
PerfRecordExit(uint8_t * p)735 PerfRecordExit::PerfRecordExit(uint8_t *p) : PerfEventRecord(p, "exit")
736 {
737     size_t copySize = GetSize() - sizeof(header);
738     if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
739         HLOGE("memcpy_s retren failed !!!");
740     }
741 }
742 
GetBinary(std::vector<uint8_t> & buf) const743 bool PerfRecordExit::GetBinary(std::vector<uint8_t> &buf) const
744 {
745     if (buf.size() < GetSize()) {
746         buf.resize(GetSize());
747     }
748 
749     GetHeaderBinary(buf);
750     uint8_t *p = buf.data() + GetHeaderSize();
751 
752     auto pDest = reinterpret_cast<PerfRecordExitData *>(p);
753     *pDest = data_;
754     return true;
755 }
756 
DumpData(int indent) const757 void PerfRecordExit::DumpData(int indent) const
758 {
759     PRINT_INDENT(indent, "pid %u, ppid %u, tid %u, ptid %u time 0x%llx\n", data_.pid, data_.ppid,
760                  data_.tid, data_.ptid, data_.time);
761 }
762 
PerfRecordThrottle(uint8_t * p)763 PerfRecordThrottle::PerfRecordThrottle(uint8_t *p) : PerfEventRecord(p, "throttle")
764 {
765     size_t copySize = GetSize() - sizeof(header);
766     if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
767         HLOGE("memcpy_s retren failed !!!");
768     }
769 }
770 
GetBinary(std::vector<uint8_t> & buf) const771 bool PerfRecordThrottle::GetBinary(std::vector<uint8_t> &buf) const
772 {
773     if (buf.size() < GetSize()) {
774         buf.resize(GetSize());
775     }
776 
777     GetHeaderBinary(buf);
778     uint8_t *p = buf.data() + GetHeaderSize();
779 
780     auto pDest = reinterpret_cast<PerfRecordThrottleData *>(p);
781     *pDest = data_;
782     return true;
783 }
784 
DumpData(int indent) const785 void PerfRecordThrottle::DumpData(int indent) const
786 {
787     PRINT_INDENT(indent, "time 0x%llx, id %llx, stream_id %llx\n", data_.time, data_.id,
788                  data_.stream_id);
789 }
790 
PerfRecordUnthrottle(uint8_t * p)791 PerfRecordUnthrottle::PerfRecordUnthrottle(uint8_t *p) : PerfEventRecord(p, "unthrottle")
792 {
793     size_t copySize = GetSize() - sizeof(header);
794     if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
795         HLOGE("memcpy_s retren failed !!!");
796     }
797 }
798 
GetBinary(std::vector<uint8_t> & buf) const799 bool PerfRecordUnthrottle::GetBinary(std::vector<uint8_t> &buf) const
800 {
801     if (buf.size() < GetSize()) {
802         buf.resize(GetSize());
803     }
804 
805     GetHeaderBinary(buf);
806     uint8_t *p = buf.data() + GetHeaderSize();
807 
808     auto pDest = reinterpret_cast<PerfRecordThrottleData *>(p);
809     *pDest = data_;
810     return true;
811 }
DumpData(int indent) const812 void PerfRecordUnthrottle::DumpData(int indent) const
813 {
814     PRINT_INDENT(indent, "time 0x%llx, id %llx, stream_id %llx\n", data_.time, data_.id,
815                  data_.stream_id);
816 }
817 
PerfRecordFork(uint8_t * p)818 PerfRecordFork::PerfRecordFork(uint8_t *p) : PerfEventRecord(p, "fork")
819 {
820     size_t copySize = GetSize() - sizeof(header);
821     if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
822         HLOGE("memcpy_s retren failed !!!");
823     }
824 }
825 
GetBinary(std::vector<uint8_t> & buf) const826 bool PerfRecordFork::GetBinary(std::vector<uint8_t> &buf) const
827 {
828     if (buf.size() < GetSize()) {
829         buf.resize(GetSize());
830     }
831 
832     GetHeaderBinary(buf);
833     uint8_t *p = buf.data() + GetHeaderSize();
834 
835     auto pDest = reinterpret_cast<PerfRecordForkData *>(p);
836     *pDest = data_;
837     return true;
838 }
839 
DumpData(int indent) const840 void PerfRecordFork::DumpData(int indent) const
841 {
842     PRINT_INDENT(indent, "pid %u, ppid %u, tid %u, ptid %u\n", data_.pid, data_.ppid, data_.tid,
843                  data_.ptid);
844 }
845 
PerfRecordRead(uint8_t * p)846 PerfRecordRead::PerfRecordRead(uint8_t *p) : PerfEventRecord(p, "read")
847 {
848     size_t copySize = GetSize() - sizeof(header);
849     if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
850         HLOGE("memcpy_s retren failed !!!");
851     }
852 }
853 
GetBinary(std::vector<uint8_t> & buf) const854 bool PerfRecordRead::GetBinary(std::vector<uint8_t> &buf) const
855 {
856     if (buf.size() < GetSize()) {
857         buf.resize(GetSize());
858     }
859 
860     GetHeaderBinary(buf);
861     uint8_t *p = buf.data() + GetHeaderSize();
862 
863     auto pDest = reinterpret_cast<PerfRecordReadData *>(p);
864     *pDest = data_;
865     return true;
866 }
867 
DumpData(int indent) const868 void PerfRecordRead::DumpData(int indent) const
869 {
870     PRINT_INDENT(indent, "pid %u, tid %u\n", data_.pid, data_.tid);
871     PRINT_INDENT(indent, "values: value %llx, timeEnabled %llx, timeRunning %llx, id %llx\n",
872                  data_.values.value, data_.values.timeEnabled, data_.values.timeRunning, data_.values.id);
873 }
874 
PerfRecordAux(uint8_t * p)875 PerfRecordAux::PerfRecordAux(uint8_t *p) : PerfEventRecord(p, "aux")
876 {
877     size_t copySize = GetSize() - sizeof(header);
878     if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
879         HLOGE("memcpy_s retren failed !!!");
880     }
881 }
882 
GetBinary(std::vector<uint8_t> & buf) const883 bool PerfRecordAux::GetBinary(std::vector<uint8_t> &buf) const
884 {
885     if (buf.size() < GetSize()) {
886         buf.resize(GetSize());
887     }
888 
889     GetHeaderBinary(buf);
890     uint8_t *p = buf.data() + GetHeaderSize();
891 
892     auto pDest = reinterpret_cast<PerfRecordAuxData *>(p);
893     *pDest = data_;
894     return true;
895 }
896 
DumpData(int indent) const897 void PerfRecordAux::DumpData(int indent) const
898 {
899     PRINT_INDENT(indent, "aux_offset %llx, aux_size %llx, flags %llx\n", data_.aux_offset,
900                  data_.aux_size, data_.flags);
901 }
902 
PerfRecordItraceStart(uint8_t * p)903 PerfRecordItraceStart::PerfRecordItraceStart(uint8_t *p) : PerfEventRecord(p, "itraceStart")
904 {
905     size_t copySize = GetSize() - sizeof(header);
906     if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
907         HLOGE("memcpy_s retren failed !!!");
908     }
909 }
910 
GetBinary(std::vector<uint8_t> & buf) const911 bool PerfRecordItraceStart::GetBinary(std::vector<uint8_t> &buf) const
912 {
913     if (buf.size() < GetSize()) {
914         buf.resize(GetSize());
915     }
916 
917     GetHeaderBinary(buf);
918     uint8_t *p = buf.data() + GetHeaderSize();
919 
920     auto pDest = reinterpret_cast<PerfRecordItraceStartData *>(p);
921     *pDest = data_;
922     return true;
923 }
924 
DumpData(int indent) const925 void PerfRecordItraceStart::DumpData(int indent) const
926 {
927     PRINT_INDENT(indent, "pid %u, tid %u\n", data_.pid, data_.tid);
928 }
929 
PerfRecordLostSamples(uint8_t * p)930 PerfRecordLostSamples::PerfRecordLostSamples(uint8_t *p) : PerfEventRecord(p, "lostSamples")
931 {
932     size_t copySize = GetSize() - sizeof(header);
933     if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
934         HLOGE("memcpy_s retren failed !!!");
935     }
936 }
937 
GetBinary(std::vector<uint8_t> & buf) const938 bool PerfRecordLostSamples::GetBinary(std::vector<uint8_t> &buf) const
939 {
940     if (buf.size() < GetSize()) {
941         buf.resize(GetSize());
942     }
943 
944     GetHeaderBinary(buf);
945     uint8_t *p = buf.data() + GetHeaderSize();
946 
947     auto pDest = reinterpret_cast<PerfRecordLostSamplesData *>(p);
948     *pDest = data_;
949     return true;
950 }
951 
DumpData(int indent) const952 void PerfRecordLostSamples::DumpData(int indent) const
953 {
954     PRINT_INDENT(indent, "lost %llu\n", data_.lost);
955 }
956 
PerfRecordSwitch(uint8_t * p)957 PerfRecordSwitch::PerfRecordSwitch(uint8_t *p) : PerfEventRecord(p, "switch")
958 {
959     size_t copySize = GetSize() - sizeof(header);
960     if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
961         HLOGE("memcpy_s retren failed !!!");
962     }
963 }
964 
GetBinary(std::vector<uint8_t> & buf) const965 bool PerfRecordSwitch::GetBinary(std::vector<uint8_t> &buf) const
966 {
967     if (buf.size() < GetSize()) {
968         buf.resize(GetSize());
969     }
970 
971     GetHeaderBinary(buf);
972     uint8_t *p = buf.data() + GetHeaderSize();
973 
974     auto pDest = reinterpret_cast<PerfRecordSwitchData *>(p);
975     *pDest = data_;
976     return true;
977 }
978 
PerfRecordSwitchCpuWide(uint8_t * p)979 PerfRecordSwitchCpuWide::PerfRecordSwitchCpuWide(uint8_t *p) : PerfEventRecord(p, "switchCpuWide")
980 {
981     size_t copySize = GetSize() - sizeof(header);
982     if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
983         HLOGE("memcpy_s retren failed !!!");
984     }
985 }
986 
GetBinary(std::vector<uint8_t> & buf) const987 bool PerfRecordSwitchCpuWide::GetBinary(std::vector<uint8_t> &buf) const
988 {
989     if (buf.size() < GetSize()) {
990         buf.resize(GetSize());
991     }
992 
993     GetHeaderBinary(buf);
994     uint8_t *p = buf.data() + GetHeaderSize();
995 
996     auto pDest = reinterpret_cast<PerfRecordSwitchCpuWideData *>(p);
997     *pDest = data_;
998     return true;
999 }
1000 
DumpData(int indent) const1001 void PerfRecordSwitchCpuWide::DumpData(int indent) const
1002 {
1003     PRINT_INDENT(indent, "next_prev_pid %u, next_prev_tid %u\n", data_.next_prev_pid,
1004                  data_.next_prev_tid);
1005 }
1006 
GetUstackServerPid()1007 pid_t PerfRecordSample::GetUstackServerPid()
1008 {
1009     if (!data_.server_nr) {
1010         return data_.pid;
1011     }
1012 
1013     size_t currServer = 0;
1014     // ipNr == 1...nr: server_pid of data_.ips[nr]
1015     for (size_t i = 0; i < data_.nr; i++) {
1016         // context change, use next server pid
1017         if (data_.ips[i] >= PERF_CONTEXT_MAX) {
1018             currServer++;
1019         }
1020     }
1021     // ipNr == nr + 1: server_pid of ustack
1022     if (currServer > 0) {
1023         currServer++;
1024     }
1025     if (currServer >= data_.server_nr) {
1026         HLOGE("ustack server pid nr %zu out of range", currServer);
1027         return data_.pid;
1028     }
1029 
1030     // return server pid
1031     return data_.server_pids[currServer];
1032 }
1033 
GetServerPidof(unsigned int ipNr)1034 pid_t PerfRecordSample::GetServerPidof(unsigned int ipNr)
1035 {
1036     if (!data_.server_nr) {
1037         return data_.pid;
1038     }
1039 
1040     // init serverPidMap_
1041     if (!serverPidMap_.size()) {
1042         size_t currServer = 0;
1043         // ipNr == 0: server_pid of data_.ip
1044         serverPidMap_.emplace_back(data_.server_pids[currServer]);
1045         // ipNr == 1...nr: server_pid of data_.ips[nr]
1046         for (size_t i = 1; i < data_.nr; i++) {
1047             // context change, use next server pid
1048             if (data_.ips[i] >= PERF_CONTEXT_MAX) {
1049                 currServer++;
1050             }
1051             if (currServer >= data_.server_nr) {
1052                 HLOGE("callchain server pid nr %zu out of range", currServer);
1053                 break;
1054             }
1055             serverPidMap_.emplace_back(data_.server_pids[currServer]);
1056         }
1057     }
1058 
1059     // return server pid
1060     if (ipNr >= serverPidMap_.size()) {
1061         return data_.pid;
1062     } else {
1063         return serverPidMap_[ipNr];
1064     }
1065 }
1066 } // namespace HiPerf
1067 } // namespace Developtools
1068 } // namespace OHOS
1069