• 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 #ifndef HIPERF_PERF_EVENTS_H
16 #define HIPERF_PERF_EVENTS_H
17 
18 #include <atomic>
19 #include <cassert>
20 #include <chrono>
21 #include <cinttypes>
22 #include <condition_variable>
23 #include <deque>
24 #include <map>
25 #include <memory>
26 #include <string>
27 #include <thread>
28 #include <variant>
29 #include <vector>
30 #if !is_mingw
31 #include <poll.h>
32 #endif
33 
34 #include <sys/types.h>
35 #include <unique_fd.h>
36 #include <linux/perf_event.h>
37 
38 #include "debug_logger.h"
39 #include "perf_event_record.h"
40 #include "perf_record_format.h"
41 #include "ring_buffer.h"
42 #include "tracked_command.h"
43 #include "utilities.h"
44 #include "virtual_runtime.h"
45 
46 // this for some performance debug
47 #define HIDEBUG_SKIP_CALLBACK 0
48 #define CALC_OFFSET(offset, size) ((offset) & ((size) - 1))
49 #ifndef CLOCK_MONOTONIC_RAW
50 #define CLOCK_MONOTONIC_RAW 4
51 #endif
52 #define PERF_AUXTRACE_RECORD_ALIGNMENT 8
53 #define PTR_TO_VOID(ptr) ((void *)(uintptr_t)(ptr))
54 #define PTR_ADD(b, o) ({ \
55     uintptr_t _b = (uintptr_t)(b);  \
56     uintptr_t _p = (uintptr_t)&(((uint8_t *)(_b))[o]);  \
57     PTR_TO_VOID(_p);  \
58 })
59 
60 namespace OHOS {
61 namespace Developtools {
62 namespace HiPerf {
63 using ConfigTable = std::map<__u64, const std::string>;
64 using SharedConfigTable = std::unique_ptr<ConfigTable>;
65 
66 const std::string PERF_DISABLE_PARAM = "security.perf_harden";
67 
68 // define convert from linux/perf_event.h
69 // description from https://man7.org/linux/man-pages/man2/perf_event_open.2.html
70 
71 const ConfigTable PERF_HW_CONFIGS = {
72     {PERF_COUNT_HW_CPU_CYCLES, "hw-cpu-cycles"},
73     {PERF_COUNT_HW_INSTRUCTIONS, "hw-instructions"},
74     {PERF_COUNT_HW_CACHE_REFERENCES, "hw-cache-references"},
75     {PERF_COUNT_HW_CACHE_MISSES, "hw-cache-misses"},
76     {PERF_COUNT_HW_BRANCH_INSTRUCTIONS, "hw-branch-instructions"},
77     {PERF_COUNT_HW_BRANCH_MISSES, "hw-branch-misses"},
78     {PERF_COUNT_HW_BUS_CYCLES, "hw-bus-cycles"},
79     {PERF_COUNT_HW_STALLED_CYCLES_FRONTEND, "hw-stalled-cycles-frontend"},
80     {PERF_COUNT_HW_STALLED_CYCLES_BACKEND, "hw-stalled-cycles-backend"},
81     {PERF_COUNT_HW_REF_CPU_CYCLES, "hw-ref-cpu-cycles"},
82 };
83 const ConfigTable PERF_HW_CACHE_CONFIGS = {
84     {PERF_COUNT_HW_CACHE_L1D, "hw-cache-l1d"},   {PERF_COUNT_HW_CACHE_L1I, "hw-cache-l1i"},
85     {PERF_COUNT_HW_CACHE_LL, "hw-cache-ll"},     {PERF_COUNT_HW_CACHE_DTLB, "hw-cache-dtlb"},
86     {PERF_COUNT_HW_CACHE_ITLB, "hw-cache-itlb"}, {PERF_COUNT_HW_CACHE_BPU, "hw-cache-bpu"},
87     {PERF_COUNT_HW_CACHE_NODE, "hw-cache-node"},
88 };
89 const ConfigTable PERF_HW_CACHE_OP_CONFIGS = {
90     {PERF_COUNT_HW_CACHE_OP_READ, "hw-cache-op-read"},
91     {PERF_COUNT_HW_CACHE_OP_WRITE, "hw-cache-op-write"},
92     {PERF_COUNT_HW_CACHE_OP_PREFETCH, "hw-cache-op-prefetch"},
93 };
94 const ConfigTable PERF_HW_CACHE_OP_RESULT_CONFIGS = {
95     {PERF_COUNT_HW_CACHE_RESULT_ACCESS, "hw-cache-result-access"},
96     {PERF_COUNT_HW_CACHE_RESULT_MISS, "hw-cache-result-miss"},
97 };
98 const ConfigTable PERF_SW_CONFIGS = {
99     {PERF_COUNT_SW_CPU_CLOCK, "sw-cpu-clock"},
100     {PERF_COUNT_SW_TASK_CLOCK, "sw-task-clock"},
101     {PERF_COUNT_SW_PAGE_FAULTS, "sw-page-faults"},
102     {PERF_COUNT_SW_CONTEXT_SWITCHES, "sw-context-switches"},
103     {PERF_COUNT_SW_CPU_MIGRATIONS, "sw-cpu-migrations"},
104     {PERF_COUNT_SW_PAGE_FAULTS_MIN, "sw-page-faults-min"},
105     {PERF_COUNT_SW_PAGE_FAULTS_MAJ, "sw-page-faults-maj"},
106     {PERF_COUNT_SW_ALIGNMENT_FAULTS, "sw-alignment-faults"},
107     {PERF_COUNT_SW_EMULATION_FAULTS, "sw-emulation-faults"},
108     {PERF_COUNT_SW_DUMMY, "sw-dummy"},
109     {PERF_COUNT_SW_BPF_OUTPUT, "sw-bpf-output"},
110 };
111 const ConfigTable PERF_RAW_CONFIGS = {
112     {0x0, "raw-sw-incr"},
113     {0x1, "raw-l1-icache-refill"},
114     {0x2, "raw-l1-itlb-refill"},
115     {0x3, "raw-l1-dcache-refill"},
116     {0x4, "raw-l1-dcache"},
117     {0x5, "raw-l1-dtlb-refill"},
118     {0x6, "raw-load-retired"},
119     {0x7, "raw-store-retired"},
120     {0x8, "raw-instruction-retired"},
121     {0x9, "raw-exception-taken"},
122     {0xa, "raw-exception-return"},
123     {0xb, "raw-cid-write-retired"},
124     {0xc, "raw-pc-write-retired"},
125     {0xd, "raw-br-immed-retired"},
126     {0xe, "raw-br-return-retired"},
127     {0xf, "raw-unaligned-ldst-retired"},
128     {0x10, "raw-br-mis-pred"},
129     {0x11, "raw-cpu-cycles"},
130     {0x12, "raw-br-pred"},
131     {0x13, "raw-mem-access"},
132     {0x14, "raw-l1-icache"},
133     {0x15, "raw-l1-dcache-wb"},
134     {0x16, "raw-l2-dcache"},
135     {0x17, "raw-l2-dcache-refill"},
136     {0x18, "raw-l2-dcache-wb"},
137     {0x19, "raw-bus-access"},
138     {0x1a, "raw-memory-error"},
139     {0x1b, "raw-inst-spec"},
140     {0x1c, "raw-ttbr-write-retired"},
141     {0x1d, "raw-bus-cycles"},
142     {0x1f, "raw-l1-dcache-allocate"},
143     {0x20, "raw-l2-dcache-allocate"},
144     {0x21, "raw-br-retired"},
145     {0x22, "raw-br-mis-pred-retired"},
146     {0x23, "raw-stall-frontend"},
147     {0x24, "raw-stall-backend"},
148     {0x25, "raw-l1-dtlb"},
149     {0x26, "raw-l1-itlb"},
150     {0x27, "raw-l2-icache"},
151     {0x28, "raw-l2-icache-refill"},
152     {0x29, "raw-l3-dcache-allocate"},
153     {0x2a, "raw-l3-dcache-refill"},
154     {0x2b, "raw-l3-dcache"},
155     {0x2c, "raw-l3-dcache-wb"},
156     {0x2d, "raw-l2-dtlb-refill"},
157     {0x2e, "raw-l2-itlb-refill"},
158     {0x2f, "raw-l2-dtlb"},
159     {0x30, "raw-l2-itlb"},
160     // newadd
161     {0x31, "raw-remote-access"},
162     {0x32, "raw-ll-cache"},
163     {0x33, "raw-ll-cache-miss"},
164     {0x34, "raw-dtlb-walk"},
165     {0x35, "raw-itlb-walk"},
166     {0x36, "raw-ll-cache-rd"},
167     {0x37, "raw-ll-cache-miss-rd"},
168     {0x38, "raw-remote-access-rd"},
169     {0x39, "raw-l1d-cache-lmiss-rd"},
170     {0x3A, "raw-op-retired"},
171     {0x3B, "raw-op-spec"},
172     {0x3C, "raw-stall"},
173     {0x3D, "raw-stall-slot-backend"},
174     {0x3E, "raw-stall-slot-frontend"},
175     {0x3F, "raw-stall-slot"},
176     {0x40, "raw-l1d-cache-rd"},
177     {0x4000, "raw-sample-pop"},
178     {0x4001, "raw-sample-feed"},
179     {0x4002, "raw-sample-filtrate"},
180     {0x4003, "raw-sample-collision"},
181     {0x4004, "raw-cnt-cycles"},
182     {0x4005, "raw-stall-backend-mem"},
183     {0x4006, "raw-l1i-cache-lmiss"},
184     {0x4009, "raw-l2d-cache-lmiss-rd"},
185     {0x400A, "raw-l2i-cache-lmiss"},
186     {0x400B, "raw-l3d-cache-lmiss-rd"},
187     {0x8002, "raw-sve-inst-retired"},
188     {0x8006, "raw-sve-inst-spec"},
189     // Refer to "Table K3.1 ARM recommendations for IMPLEMENTATION DEFINED event numbers" in ARMv8 sp
190     {0x0040, "raw-l1d-cache-rd"},
191     {0x0041, "raw-l1d-cache-wr"},
192     {0x0042, "raw-l1d-cache-refill-rd"},
193     {0x0043, "raw-l1d-cache-refill-wr"},
194     {0x0044, "raw-l1d-cache-refill-inner"},
195     {0x0045, "raw-l1d-cache-refill-outer"},
196     {0x0046, "raw-l1d-cache-wb-victim"},
197     {0x0047, "raw-l1d-cache-wb-clean"},
198     {0x0048, "raw-l1d-cache-inval"},
199     // 0x0049-0x004B - Reserved
200     {0x004C, "raw-l1d-tlb-refill-rd"},
201     {0x004D, "raw-l1d-tlb-refill-wr"},
202     {0x004E, "raw-l1d-tlb-rd"},
203     {0x004F, "raw-l1d-tlb-wr"},
204     {0x0050, "raw-l2d-cache-rd"},
205     {0x0051, "raw-l2d-cache-wr"},
206     {0x0052, "raw-l2d-cache-refill-rd"},
207     {0x0053, "raw-l2d-cache-refill-wr"},
208     // 0x0054-0x0055 - Reserved
209     {0x0056, "raw-l2d-cache-wb-victim"},
210     {0x0057, "raw-l2d-cache-wb-clean"},
211     {0x0058, "raw-l2d-cache-inval"},
212     // 0x0059-0x005B - Reserved
213     {0x005C, "raw-l2d-tlb-refill-rd"},
214     {0x005D, "raw-l2d-tlb-refill-wr"},
215     {0x005E, "raw-l2d-tlb-rd"},
216     {0x005F, "raw-l2d-tlb-wr"},
217     {0x0060, "raw-bus-access-rd"},
218     {0x0061, "raw-bus-access-wr"},
219     {0x0062, "raw-bus-access-shared"},
220     {0x0063, "raw-bus-access-not-shared"},
221     {0x0064, "raw-bus-access-normal"},
222     {0x0065, "raw-bus-access-periph"},
223     {0x0066, "raw-mem-access-rd"},
224     {0x0067, "raw-mem-access-wr"},
225     {0x0068, "raw-unaligned-ld-spec"},
226     {0x0069, "raw-unaligned-st-spec"},
227     {0x006A, "raw-unaligned-ldst-spec"},
228     // 0x006B - Reserved
229     {0x006C, "raw-ldrex-spec"},
230     {0x006D, "raw-strex-pass-spec"},
231     {0x006E, "raw-strex-fail-spec"},
232     {0x006F, "raw-strex-spec"},
233     {0x0070, "raw-ld-spec"},
234     {0x0071, "raw-st-spec"},
235     {0x0072, "raw-ldst-spec"},
236     {0x0073, "raw-dp-spec"},
237     {0x0074, "raw-ase-spec"},
238     {0x0075, "raw-vfp-spec"},
239     {0x0076, "raw-pc-write-spec"},
240     {0x0077, "raw-crypto-spec"},
241     {0x0078, "raw-br-immed-spec"},
242     {0x0079, "raw-br-return-spec"},
243     {0x007A, "raw-br-indirect-spec"},
244     // 0x007B - Reserved
245     {0x007C, "raw-isb-spec"},
246     {0x007D, "raw-dsb-spec"},
247     {0x007E, "raw-dmb-spec"},
248     // 0x007F-0x0080 - Reserved
249     {0x0081, "raw-exc-undef"},
250     {0x0082, "raw-exc-svc"},
251     {0x0083, "raw-exc-pabort"},
252     {0x0084, "raw-exc-dabort"},
253     // 0x0085 - Reserved
254     {0x0086, "raw-exc-irq"},
255     {0x0087, "raw-exc-fiq"},
256     {0x0088, "raw-exc-smc"},
257     // 0x0089 - Reserved
258     {0x008A, "raw-exc-hvc"},
259     {0x008B, "raw-exc-trap-pabort"},
260     {0x008C, "raw-exc-trap-dabort"},
261     {0x008D, "raw-exc-trap-other"},
262     {0x008E, "raw-exc-trap-irq"},
263     {0x008F, "raw-exc-trap-fiq"},
264     {0x0090, "raw-rc-ld-spec"},
265     {0x0091, "raw-rc-st-spec"},
266     // 0x0092-0x009F - Reserved
267     {0x00A0, "raw-l3d-cache-rd"},
268     {0x00A1, "raw-l3d-cache-wr"},
269     {0x00A2, "raw-l3d-cache-refill-rd"},
270     {0x00A3, "raw-l3d-cache-refill-wr"},
271     // 0x00A4-0x00A5 - Reserved
272     {0x00A6, "raw-l3d-cache-wb-victim"},
273     {0x00A7, "raw-l3d-cache-wb-clean"},
274     {0x00A8, "raw-l3d-cache-inval"},
275 };
276 static ConfigTable PERF_TRACEPOINT_CONFIGS = {
277 
278 };
279 
280 const std::map<perf_type_id, std::string> PERF_TYPES = {
281     {PERF_TYPE_HARDWARE, "hardware"},
282     {PERF_TYPE_SOFTWARE, "software"},
283     {PERF_TYPE_TRACEPOINT, "tracepoint"},
284     {PERF_TYPE_HW_CACHE, "hardware cache"},
285     {PERF_TYPE_RAW, "raw"},
286 };
287 
288 static std::map<perf_type_id, ConfigTable> TYPE_CONFIGS = {
289     {PERF_TYPE_HARDWARE, (PERF_HW_CONFIGS)},           {PERF_TYPE_SOFTWARE, (PERF_SW_CONFIGS)},
290     {PERF_TYPE_HW_CACHE, (PERF_HW_CACHE_CONFIGS)},     {PERF_TYPE_RAW, (PERF_RAW_CONFIGS)},
291     {PERF_TYPE_TRACEPOINT, (PERF_TRACEPOINT_CONFIGS)},
292 };
293 
294 // default config
295 const std::vector<__u64> DEFAULT_HW_CONFIGS = {
296     PERF_COUNT_HW_CPU_CYCLES,
297 #if defined(__aarch64__)
298     PERF_COUNT_HW_STALLED_CYCLES_FRONTEND,
299     PERF_COUNT_HW_STALLED_CYCLES_BACKEND,
300 #endif
301     PERF_COUNT_HW_INSTRUCTIONS,
302     PERF_COUNT_HW_BRANCH_INSTRUCTIONS,
303     PERF_COUNT_HW_BRANCH_MISSES,
304 };
305 const std::vector<__u64> DEFAULT_SW_CONFIGS = {
306     PERF_COUNT_SW_TASK_CLOCK,
307     PERF_COUNT_SW_CONTEXT_SWITCHES,
308     PERF_COUNT_SW_PAGE_FAULTS,
309 };
310 const std::map<perf_type_id, std::vector<__u64>> DEFAULT_TYPE_CONFIGS = {
311     {PERF_TYPE_HARDWARE, DEFAULT_HW_CONFIGS},
312     {PERF_TYPE_SOFTWARE, DEFAULT_SW_CONFIGS},
313 };
314 
315 struct read_format_event {
316     __u64 value; /* The value of the event */
317     __u64 id;    /* if PERF_FORMAT_ID */
318 };
319 
320 struct read_format_group {
321     __u64 nr;           /* The number of events */
322     __u64 timeEnabled; /* if PERF_FORMAT_TOTAL_TIME_ENABLED */
323     __u64 timeRunning; /* if PERF_FORMAT_TOTAL_TIME_RUNNING */
324     read_format_event events[1];
325 };
326 
327 struct read_format_no_group {
328     __u64 value;        /* The value of the event */
329     __u64 timeEnabled; /* if PERF_FORMAT_TOTAL_TIME_ENABLED */
330     __u64 timeRunning; /* if PERF_FORMAT_TOTAL_TIME_RUNNING */
331     __u64 id;           /* if PERF_FORMAT_ID */
332 };
333 
334 class PerfEvents {
335 public:
336     static constexpr uint64_t DEFAULT_SAMPLE_FREQUNCY = 4000;
337     static constexpr uint64_t DEFAULT_SAMPLE_PERIOD = 1;
338     static constexpr uint64_t DEFAULT_TIMEOUT = 10 * 1000;
339     static constexpr size_t MIN_BUFFER_SIZE = 64 * 1024 * 1024;
340     static constexpr size_t BUFFER_LOW_LEVEL = 10 * 1024 * 1024;
341     static constexpr size_t BUFFER_CRITICAL_LEVEL = 5 * 1024 * 1024;
342     static constexpr size_t MAX_BUFFER_SIZE_LITTLE = 128 * 1024 * 1024;
343     static constexpr size_t MAX_BUFFER_SIZE_LARGE = 256 * 1024 * 1024;
344     static constexpr uint64_t DEFAULT_EVENT_MAX_SAMPLE_RATE = 8000;
345     static constexpr uint64_t MIN_HM_TRACEPOINT_EVENT_ID = 32768;
346     static constexpr size_t MAX_HEX_EVENT_NAME_LENGTH = 10;
347 
348     PerfEvents();
349     ~PerfEvents();
350 
351     bool AddEvents(const std::vector<std::string> &eventStrings, bool group = false);
352     bool PrepareTracking(void);
353     bool StartTracking(bool immediately = true);
354     bool StopTracking(void);
355     bool PauseTracking(void);
356     bool ResumeTracking(void);
357     bool OutputTracking();
358     /* call sequence
359        1. setXXX
360        2. AddEvents()
361        3. PrepareTracking
362        4. StartTracking (blocking...)
363     */
364     bool EnableTracking();
365     bool IsTrackRunning();
366     bool IsOutputTracking();
367     void SetOutputTrackingStatus(bool status);
368 
369     void SetSystemTarget(bool systemTarget);
370     void SetCpu(const std::vector<pid_t> cpus); // cpu id must be [0~N]
371     void SetPid(const std::vector<pid_t> pids); // tis is same as pid in kernel
372     void SetTimeOut(float timeOut);
373     void SetTimeReport(int);
374     void SetVerboseReport(bool);
375     bool AddOffCpuEvent();
376 
SetTrackedCommand(const std::vector<std::string> & trackedCommand)377     inline void SetTrackedCommand(const std::vector<std::string> &trackedCommand)
378     {
379         if (!trackedCommand.empty()) {
380             trackedCommand_ = TrackedCommand::CreateInstance(trackedCommand);
381         }
382     }
383 
384     void SetSampleFrequency(unsigned int frequency);
385     void SetSamplePeriod(unsigned int period);
386 
387     // for background track
388     void SetBackTrack(bool backtrack);
389     void SetBackTrackTime(uint64_t backtrackTime);
390 
391     enum SampleStackType {
392         NONE,
393         FP,
394         DWARF,
395     };
396     void SetSampleStackType(SampleStackType type);
397     void SetDwarfSampleStackSize(uint32_t stackSize);
398     void SetMmapPages(size_t mmapPages);
399     std::vector<AttrWithId> GetAttrWithId() const;
400 
SetInherit(bool inherit)401     void SetInherit(bool inherit)
402     {
403         inherit_ = inherit;
404     };
SetClockId(int clockId)405     void SetClockId(int clockId)
406     {
407         clockId_ = clockId;
408     };
409     void SetPerCpu(bool perCpu);
410     void SetPerThread(bool perThread);
411     bool SetBranchSampleType(uint64_t value);
412     bool AddDefaultEvent(perf_type_id type);
413 
414     std::map<__u64, std::string> GetSupportEvents(perf_type_id type);
415 
416     struct Summary {
417         int cpu;
418         pid_t tid;
419         __u64 eventCount = 0;
420         __u64 timeEnabled = 0;
421         __u64 timeRunning = 0;
SummarySummary422         Summary(const int cpu, const pid_t tid, const __u64 eventCount,
423                 const __u64 timeEnabled, const __u64 timeRunning)
424             : cpu(cpu), tid(tid), eventCount(eventCount), timeEnabled(timeEnabled), timeRunning(timeRunning)
425         {
426         }
427     };
428 
429     struct ReportSum {
430         int cpu;
431         pid_t pid;
432         pid_t tid;
433         double scaleSum = 1.0;
434         double commentSum = 0;
435         __u64 eventCountSum = 0;
436         __u64 enabledSum = 0;
437         __u64 runningSum = 0;
438         std::string configName = "";
439         std::string threadName = "";
440     };
441     struct CountEvent {
442         bool userOnly = false;
443         bool kernelOnly = false;
444         __u64 eventCount = 0;
445         __u64 timeEnabled = 0;
446         __u64 timeRunning = 0;
447         __u64 id = 0;
448         double usedCpus = 0;
449         std::vector<Summary> summaries;
450     };
451     using StatCallBack =
452         std::function<void(const std::map<std::string, std::unique_ptr<PerfEvents::CountEvent>> &)>;
453     using RecordCallBack = std::function<bool(PerfEventRecord&)>;
454 
455     void SetStatCallBack(StatCallBack reportCallBack);
456     void SetRecordCallBack(RecordCallBack recordCallBack);
GetLostSamples(size_t & lostSamples,size_t & lostNonSamples)457     void GetLostSamples(size_t &lostSamples, size_t &lostNonSamples)
458     {
459         lostSamples = lostSamples_;
460         lostNonSamples = lostNonSamples_;
461     }
462 
463     // review: remove this function.
GetStaticConfigName(perf_type_id type_id,__u64 config_id)464     static const std::string GetStaticConfigName(perf_type_id type_id, __u64 config_id)
465     {
466         auto typeConfigs = TYPE_CONFIGS.find(type_id);
467         if (typeConfigs != TYPE_CONFIGS.end()) {
468             auto configs = typeConfigs->second;
469             auto config = configs.find(config_id);
470             if (config != configs.end()) {
471                 return config->second;
472             } else {
473                 HLOGW("config not found for %u:%lld in %zu:%zu", type_id, config_id,
474                       TYPE_CONFIGS.size(), configs.size());
475                 // dump all config size
476                 for (auto types : TYPE_CONFIGS) {
477                     HLOGV("type id %d %zu", types.first, types.second.size());
478                 }
479             }
480         } else {
481             HLOGW("type not found for %d  in %zu", type_id, TYPE_CONFIGS.size());
482         }
483         std::string configName = StringPrintf("0x%llx", config_id);
484         return configName;
485     };
486 
GetStaticConfigId(const std::string & event_name)487     static const std::tuple<bool, perf_type_id, __u64> GetStaticConfigId(const std::string &event_name)
488     {
489         for (auto type : TYPE_CONFIGS) {
490             for (auto config : (type.second)) {
491                 if (config.second == event_name) {
492                     return std::make_tuple(true, type.first, config.first);
493                 }
494             }
495         }
496         return std::make_tuple(false, PERF_TYPE_MAX, 0);
497     };
498 
GetTraceConfigName(__u64 config_id)499     const std::string GetTraceConfigName(__u64 config_id)
500     {
501         auto config = traceConfigTable.find(config_id);
502         if (config != traceConfigTable.end()) {
503             return config->second;
504         } else {
505             HLOGW("config not found for %lld in traceConfigTable.", config_id);
506         }
507         return "<not found>";
508     };
509 
510     static const std::string GetTypeName(perf_type_id type_id);
511     bool ParseEventName(const std::string &nameStr, std::string &name, bool &excludeUser,
512                         bool &excludeKernel, bool &isTracePoint);
513 
514     // mmap one fd for each cpu
515     struct MmapFd {
516         int fd;
517         perf_event_mmap_page *mmapPage = nullptr;
518         uint8_t *buf = nullptr;
519         size_t bufSize = 0;
520         size_t auxBufSize = 0;
521         // for read and sort
522         size_t dataSize = 0;
523         perf_event_header header;
524         uint64_t timestamp = 0;
525         const perf_event_attr *attr = nullptr;
526         size_t posCallChain = 0;
527         int cpu = 0;
528         void *auxBuf = nullptr;
529         pid_t tid_ = 0;
530     };
531 
532     bool isHM_ = false;
533     bool isSpe_ = false;
534 
535     void SetHM(bool isHM);
536     void SetConfig(std::map<const std::string, uint64_t> &speOptMaps);
537 private:
538     size_t recordEventCount_ = 0; // only for debug time
539 #ifdef HIPERF_DEBUG_TIME
540     std::chrono::microseconds recordCallBackTime_ = std::chrono::microseconds::zero();
541     std::chrono::microseconds recordWaitDataTime_ = std::chrono::microseconds::zero();
542     std::chrono::microseconds recordSleepTime_ = std::chrono::microseconds::zero();
543     std::chrono::microseconds recordKernelReadTime_ = std::chrono::microseconds::zero();
544 #endif
545     size_t lostSamples_ = 0;
546     size_t lostNonSamples_ = 0;
547 
548     std::unique_ptr<RingBuffer> recordBuf_ {nullptr};
549     bool recordBufReady_ = false;
550     std::mutex mtxRrecordBuf_;
551     std::condition_variable cvRecordBuf_;
552     std::thread readRecordBufThread_;
553     std::atomic_bool readRecordThreadRunning_ = false;
554     bool startedTracking_ = false;
555     bool isLowPriorityThread_ = false;
556     void RecordLoop();
557     void StatLoop();
558     bool IsRecordInMmap(int timeout);
559     void ReadRecordsFromMmaps();
560     void ReadRecordsFromSpeMmaps(MmapFd& mmapFd, u64 auxOffset, u64 auxSize, u32 pid, u32 tid);
561     void SpeReadData(void *dataPage, u64 *dataTail, uint8_t *buf, u32 size);
562     bool GetRecordFromMmap(MmapFd &mmap);
563     void GetRecordFieldFromMmap(MmapFd &mmap, void *dest, size_t pos, size_t size);
564     void MoveRecordToBuf(MmapFd &mmap, bool &isAuxEvent, u64 &auxOffset, u64 &auxSize, u32 &pid, u32 &tid);
565     size_t GetCallChainPosInSampleRecord(const perf_event_attr &attr);
566     size_t GetStackSizePosInSampleRecord(MmapFd &mmap);
567     bool CutStackAndMove(MmapFd &mmap);
568     inline void WaitDataFromRingBuffer();
569     inline bool ProcessRecord(const perf_event_attr* attr, uint8_t* data);
570     void ReadRecordFromBuf();
571     size_t CalcBufferSize();
572     bool PrepareRecordThread();
573     void WaitRecordThread();
574     bool HaveTargetsExit(const std::chrono::steady_clock::time_point &startTime);
575     void ExitReadRecordBufThread();
576 
577     enum EventSpaceType {
578         UNKNOW = 0,
579         USER = 1,
580         KERNEL = 2,
581         USER_KERNEL = 3,
582     };
583     uint8_t eventSpaceType_ = EventSpaceType::UNKNOW;
584 
585     bool inherit_ = false;
586     std::vector<pid_t> pids_;
587     std::vector<pid_t> cpus_;
588     std::vector<OHOS::UniqueFd> groups_;
589     std::chrono::milliseconds timeOut_;    // milliseconds
590     std::chrono::milliseconds timeReport_; // means same as timeOut
591     bool perCpu_ = false;
592     bool perThread_ = false;
593     bool verboseReport_ = false;
594     bool prepared_ = false;
595     ConfigTable traceConfigTable;
596 
597     unsigned int samplePeriod_ = 0;
598     unsigned int sampleFreq_ = 0;
599     uint64_t config_ = 0;
600     uint64_t config1_ = 0;
601     uint64_t config2_ = 0;
602     unsigned int speType_ = 0;
603 
604     struct FdItem {
605         OHOS::UniqueFd fd;
606         int cpu;
607         pid_t pid;
608         pid_t tid;
609         __u64 eventCount;
610         mutable uint64_t perfId = 0;
GetPrefIdFdItem611         uint64_t GetPrefId() const
612         {
613             if (perfId == 0) {
614                 read_format_no_group readNoGroupValue;
615                 if (read(fd, &readNoGroupValue, sizeof(readNoGroupValue)) > 0) {
616                     perfId = readNoGroupValue.id;
617                 } else {
618                     HLOGW("read failed with fd %d", fd.Get());
619                 }
620             }
621             return perfId;
622         }
623     };
624     struct EventItem {
625         std::string typeName;
626         std::string configName;
627         perf_event_attr attr = {};
628         std::vector<FdItem> fdItems;
629     };
630     struct EventGroupItem {
631         std::vector<EventItem> eventItems;
632     };
633     std::vector<EventGroupItem> eventGroupItem_;
634 
635     std::map<int, MmapFd> cpuMmap_;
636     std::vector<MmapFd *> MmapRecordHeap_;
637 
638 #if !is_mingw
639     std::vector<struct pollfd> pollFds_;
640 #endif
641     const int pollTimeOut_ = 500; // ms
642     size_t pageSize_ = 4096;
643     size_t auxMmapPages_ = 128;
644     bool systemTarget_ = false;
645     bool excludeHiperf_ = false;
646     pid_t selfPid_ = -1;
647     unsigned int mmapPages_ = 0;
648     int clockId_ = -1;
649     uint64_t branchSampleType_ = 0;
650 
651     SampleStackType sampleStackType_ = SampleStackType::NONE;
652     uint32_t dwarfSampleStackSize_ = MAX_SAMPLE_STACK_SIZE;
653 
654     // read records from the ring buffer singleton
655     void ReadRecordFromBuffer();
656     void ReadRecordFromBufferThread();
657 
658     std::unique_ptr<TrackedCommand> trackedCommand_ = {};
659 
660     StatCallBack reportCallBack_;
661     RecordCallBack recordCallBack_;
662 
663     void LoadTracepointEventTypesFromSystem();
664     bool PerfEventsEnable(bool);
665     bool AddEvent(perf_type_id type, __u64 config, bool excludeUser = false,
666                   bool excludeKernel = false, bool followGroup = false);
667     bool AddEvent(const std::string &eventString, bool followGroup = false);
668     bool AddSpeEvent(u32 type, bool followGroup = false);
669     bool IsEventSupport(perf_type_id type, __u64 config);
670     bool IsEventAttrSupport(perf_event_attr &attr);
671 
672     std::chrono::time_point<std::chrono::steady_clock> trackingStartTime_;
673     std::chrono::time_point<std::chrono::steady_clock> trackingEndTime_;
674     std::chrono::time_point<std::chrono::steady_clock> readingStartTime_;
675 
676     std::map<std::string, std::unique_ptr<CountEvent>> countEvents_;
677 
678     void PutAllCpus();
679     bool PrepareFdEvents();
680     bool CreateFdEvents();
681     bool StatReport(const __u64 &durationInSec);
682     bool CreateMmap(const FdItem &item, const perf_event_attr &attr);
683     bool CreateSpeMmap(const FdItem &item, const perf_event_attr &attr);
684 
GetDefaultAttr()685     const perf_event_attr *GetDefaultAttr()
686     {
687         HLOG_ASSERT(eventGroupItem_.size() > 0);
688         HLOG_ASSERT(eventGroupItem_[0].eventItems.size() > 0);
689         return &(eventGroupItem_.at(0).eventItems.at(0).attr);
690     };
691 
692     OHOS::UniqueFd Open(perf_event_attr &attr, pid_t pid = 0, int cpu = -1, int groupFd = -1,
693                         unsigned long flags = 0);
694     std::unique_ptr<perf_event_attr> CreateDefaultAttr(perf_type_id type, __u64 config);
695 
696     // for update time thread
697     static bool updateTimeThreadRunning_;
698     static std::atomic<uint64_t> currentTimeSecond_;
699     static void UpdateCurrentTime();
700 
701     // for background track
702     bool backtrack_ = false;
703     bool outputTracking_ = false;
704     uint64_t backtrackTime_ = 0;
705     uint64_t outputEndTime_ = 0;
706     bool IsSkipRecordForBacktrack(const PerfRecordSample& sample);
707 };
708 } // namespace HiPerf
709 } // namespace Developtools
710 } // namespace OHOS
711 #endif // HIPERF_PERF_EVENTS_H
712