xref: /developtools/hiperf/include/perf_events.h (revision 48f512ce)
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
60namespace OHOS {
61namespace Developtools {
62namespace HiPerf {
63using ConfigTable = std::map<__u64, const std::string>;
64using SharedConfigTable = std::unique_ptr<ConfigTable>;
65
66const 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
71const 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};
83const 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};
89const 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};
94const 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};
98const 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};
111const 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};
276static ConfigTable PERF_TRACEPOINT_CONFIGS = {
277
278};
279
280const 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
288static 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
295const 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};
305const 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};
310const 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
315struct read_format_event {
316    __u64 value; /* The value of the event */
317    __u64 id;    /* if PERF_FORMAT_ID */
318};
319
320struct 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
327struct 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
334class PerfEvents {
335public:
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    /* call sequence
358       1. setXXX
359       2. AddEvents()
360       3. PrepareTracking
361       4. StartTracking (blocking...)
362    */
363    bool EnableTracking();
364    bool IsTrackRunning();
365
366    void SetSystemTarget(bool systemTarget);
367    void SetCpu(const std::vector<pid_t> cpus); // cpu id must be [0~N]
368    void SetPid(const std::vector<pid_t> pids); // tis is same as pid in kernel
369    void SetTimeOut(float timeOut);
370    void SetTimeReport(int);
371    void SetVerboseReport(bool);
372    bool AddOffCpuEvent();
373
374    inline void SetTrackedCommand(const std::vector<std::string> &trackedCommand)
375    {
376        if (!trackedCommand.empty()) {
377            trackedCommand_ = TrackedCommand::CreateInstance(trackedCommand);
378        }
379    }
380
381    void SetSampleFrequency(unsigned int frequency);
382    void SetSamplePeriod(unsigned int period);
383
384    enum SampleStackType {
385        NONE,
386        FP,
387        DWARF,
388    };
389    void SetSampleStackType(SampleStackType type);
390    void SetDwarfSampleStackSize(uint32_t stackSize);
391    void SetMmapPages(size_t mmapPages);
392    std::vector<AttrWithId> GetAttrWithId() const;
393
394    void SetInherit(bool inherit)
395    {
396        inherit_ = inherit;
397    };
398    void SetClockId(int clockId)
399    {
400        clockId_ = clockId;
401    };
402    void SetPerCpu(bool perCpu);
403    void SetPerThread(bool perThread);
404    bool SetBranchSampleType(uint64_t value);
405    bool AddDefaultEvent(perf_type_id type);
406
407    std::map<__u64, std::string> GetSupportEvents(perf_type_id type);
408
409    struct Summary {
410        int cpu;
411        pid_t tid;
412        __u64 eventCount = 0;
413        __u64 timeEnabled = 0;
414        __u64 timeRunning = 0;
415        Summary(const int cpu, const pid_t tid, const __u64 eventCount,
416                const __u64 timeEnabled, const __u64 timeRunning)
417            : cpu(cpu), tid(tid), eventCount(eventCount), timeEnabled(timeEnabled), timeRunning(timeRunning)
418        {
419        }
420    };
421
422    struct ReportSum {
423        int cpu;
424        pid_t pid;
425        pid_t tid;
426        double scaleSum = 1.0;
427        double commentSum = 0;
428        __u64 eventCountSum = 0;
429        __u64 enabledSum = 0;
430        __u64 runningSum = 0;
431        std::string configName = "";
432        std::string threadName = "";
433    };
434    struct CountEvent {
435        bool userOnly = false;
436        bool kernelOnly = false;
437        __u64 eventCount = 0;
438        __u64 timeEnabled = 0;
439        __u64 timeRunning = 0;
440        __u64 id = 0;
441        double usedCpus = 0;
442        std::vector<Summary> summaries;
443    };
444    using StatCallBack =
445        std::function<void(const std::map<std::string, std::unique_ptr<PerfEvents::CountEvent>> &)>;
446    using RecordCallBack = std::function<bool(std::unique_ptr<PerfEventRecord>)>;
447
448    void SetStatCallBack(StatCallBack reportCallBack);
449    void SetRecordCallBack(RecordCallBack recordCallBack);
450    void GetLostSamples(size_t &lostSamples, size_t &lostNonSamples)
451    {
452        lostSamples = lostSamples_;
453        lostNonSamples = lostNonSamples_;
454    }
455
456    // review: remove this function.
457    static const std::string GetStaticConfigName(perf_type_id type_id, __u64 config_id)
458    {
459        auto typeConfigs = TYPE_CONFIGS.find(type_id);
460        if (typeConfigs != TYPE_CONFIGS.end()) {
461            auto configs = typeConfigs->second;
462            auto config = configs.find(config_id);
463            if (config != configs.end()) {
464                return config->second;
465            } else {
466                HLOGW("config not found for %u:%lld in %zu:%zu", type_id, config_id,
467                      TYPE_CONFIGS.size(), configs.size());
468                // dump all config size
469                for (auto types : TYPE_CONFIGS) {
470                    HLOGV("type id %d %zu", types.first, types.second.size());
471                }
472            }
473        } else {
474            HLOGW("type not found for %d  in %zu", type_id, TYPE_CONFIGS.size());
475        }
476        std::string configName = StringPrintf("0x%llx", config_id);
477        return configName;
478    };
479
480    static const std::tuple<bool, perf_type_id, __u64> GetStaticConfigId(const std::string &event_name)
481    {
482        for (auto type : TYPE_CONFIGS) {
483            for (auto config : (type.second)) {
484                if (config.second == event_name) {
485                    return std::make_tuple(true, type.first, config.first);
486                }
487            }
488        }
489        return std::make_tuple(false, PERF_TYPE_MAX, 0);
490    };
491
492    const std::string GetTraceConfigName(__u64 config_id)
493    {
494        auto config = traceConfigTable.find(config_id);
495        if (config != traceConfigTable.end()) {
496            return config->second;
497        } else {
498            HLOGW("config not found for %lld in traceConfigTable.", config_id);
499        }
500        return "<not found>";
501    };
502
503    static const std::string GetTypeName(perf_type_id type_id);
504    bool ParseEventName(const std::string &nameStr, std::string &name, bool &excludeUser,
505                        bool &excludeKernel, bool &isTracePoint);
506
507    // mmap one fd for each cpu
508    struct MmapFd {
509        int fd;
510        perf_event_mmap_page *mmapPage = nullptr;
511        uint8_t *buf = nullptr;
512        size_t bufSize = 0;
513        size_t auxBufSize = 0;
514        // for read and sort
515        size_t dataSize = 0;
516        perf_event_header header;
517        uint64_t timestamp = 0;
518        const perf_event_attr *attr = nullptr;
519        size_t posCallChain = 0;
520        int cpu = 0;
521        void *auxBuf = nullptr;
522        pid_t tid_ = 0;
523    };
524
525    bool isHM_ = false;
526    bool isSpe_ = false;
527
528    void SetHM(bool isHM);
529    void SetConfig(std::map<const std::string, unsigned long long> &speOptMaps);
530private:
531    size_t recordEventCount_ = 0; // only for debug time
532#ifdef HIPERF_DEBUG_TIME
533    std::chrono::microseconds recordCallBackTime_ = std::chrono::microseconds::zero();
534    std::chrono::microseconds recordWaitDataTime_ = std::chrono::microseconds::zero();
535    std::chrono::microseconds recordSleepTime_ = std::chrono::microseconds::zero();
536    std::chrono::microseconds recordKernelReadTime_ = std::chrono::microseconds::zero();
537#endif
538    size_t lostSamples_ = 0;
539    size_t lostNonSamples_ = 0;
540
541    std::unique_ptr<RingBuffer> recordBuf_ {nullptr};
542    bool recordBufReady_ = false;
543    std::mutex mtxRrecordBuf_;
544    std::condition_variable cvRecordBuf_;
545    std::thread readRecordBufThread_;
546    std::atomic_bool readRecordThreadRunning_ = false;
547    bool startedTracking_ = false;
548    bool isLowPriorityThread_ = false;
549    void RecordLoop();
550    void StatLoop();
551    bool IsRecordInMmap(int timeout);
552    void ReadRecordsFromMmaps();
553    void ReadRecordsFromSpeMmaps(MmapFd& mmapFd, u64 auxOffset, u64 auxSize, u32 pid, u32 tid);
554    void SpeReadData(void *dataPage, u64 *dataTail, uint8_t *buf, u32 size);
555    bool GetRecordFromMmap(MmapFd &mmap);
556    void GetRecordFieldFromMmap(MmapFd &mmap, void *dest, size_t pos, size_t size);
557    void MoveRecordToBuf(MmapFd &mmap, bool &isAuxEvent, u64 &auxOffset, u64 &auxSize, u32 &pid, u32 &tid);
558    size_t GetCallChainPosInSampleRecord(const perf_event_attr &attr);
559    size_t GetStackSizePosInSampleRecord(MmapFd &mmap);
560    bool CutStackAndMove(MmapFd &mmap);
561    void ReadRecordFromBuf();
562    size_t CalcBufferSize();
563    bool PrepareRecordThread();
564    void WaitRecordThread();
565    bool HaveTargetsExit(const std::chrono::steady_clock::time_point &startTime);
566    void ExitReadRecordBufThread();
567
568    enum EventSpaceType {
569        UNKNOW = 0,
570        USER = 1,
571        KERNEL = 2,
572        USER_KERNEL = 3,
573    };
574    uint8_t eventSpaceType_ = EventSpaceType::UNKNOW;
575
576    bool inherit_ = false;
577    std::vector<pid_t> pids_;
578    std::vector<pid_t> cpus_;
579    std::vector<OHOS::UniqueFd> groups_;
580    std::chrono::milliseconds timeOut_;    // milliseconds
581    std::chrono::milliseconds timeReport_; // means same as timeOut
582    bool perCpu_ = false;
583    bool perThread_ = false;
584    bool verboseReport_ = false;
585    bool prepared_ = false;
586    ConfigTable traceConfigTable;
587
588    unsigned int samplePeriod_ = 0;
589    unsigned int sampleFreq_ = 0;
590    unsigned long long config_ = 0;
591    unsigned long long config1_ = 0;
592    unsigned long long config2_ = 0;
593    unsigned int speType_ = 0;
594
595    struct FdItem {
596        OHOS::UniqueFd fd;
597        int cpu;
598        pid_t pid;
599        pid_t tid;
600        __u64 eventCount;
601        mutable uint64_t perfId = 0;
602        uint64_t GetPrefId() const
603        {
604            if (perfId == 0) {
605                read_format_no_group readNoGroupValue;
606                if (read(fd, &readNoGroupValue, sizeof(readNoGroupValue)) > 0) {
607                    perfId = readNoGroupValue.id;
608                } else {
609                    HLOGW("read failed with fd %d", fd.Get());
610                }
611            }
612            return perfId;
613        }
614    };
615    struct EventItem {
616        std::string typeName;
617        std::string configName;
618        perf_event_attr attr = {};
619        std::vector<FdItem> fdItems;
620    };
621    struct EventGroupItem {
622        std::vector<EventItem> eventItems;
623    };
624    std::vector<EventGroupItem> eventGroupItem_;
625
626    std::map<int, MmapFd> cpuMmap_;
627    std::vector<MmapFd *> MmapRecordHeap_;
628
629#if !is_mingw
630    std::vector<struct pollfd> pollFds_;
631#endif
632    const int pollTimeOut_ = 500; // ms
633    size_t pageSize_ = 4096;
634    size_t auxMmapPages_ = 128;
635    bool systemTarget_ = false;
636    bool excludeHiperf_ = false;
637    pid_t selfPid_ = -1;
638    unsigned int mmapPages_ = 0;
639    int clockId_ = -1;
640    uint64_t branchSampleType_ = 0;
641
642    SampleStackType sampleStackType_ = SampleStackType::NONE;
643    uint32_t dwarfSampleStackSize_ = MAX_SAMPLE_STACK_SIZE;
644
645    // read records from the ring buffer singleton
646    void ReadRecordFromBuffer();
647    void ReadRecordFromBufferThread();
648
649    std::unique_ptr<TrackedCommand> trackedCommand_ = {};
650
651    StatCallBack reportCallBack_;
652    RecordCallBack recordCallBack_;
653
654    void LoadTracepointEventTypesFromSystem();
655    bool PerfEventsEnable(bool);
656    bool AddEvent(perf_type_id type, __u64 config, bool excludeUser = false,
657                  bool excludeKernel = false, bool followGroup = false);
658    bool AddEvent(const std::string &eventString, bool followGroup = false);
659    bool AddSpeEvent(u32 type, bool followGroup = false);
660    bool IsEventSupport(perf_type_id type, __u64 config);
661    bool IsEventAttrSupport(perf_event_attr &attr);
662
663    std::chrono::time_point<std::chrono::steady_clock> trackingStartTime_;
664    std::chrono::time_point<std::chrono::steady_clock> trackingEndTime_;
665    std::chrono::time_point<std::chrono::steady_clock> readingStartTime_;
666
667    std::map<std::string, std::unique_ptr<CountEvent>> countEvents_;
668
669    void PutAllCpus();
670    bool PrepareFdEvents();
671    bool CreateFdEvents();
672    bool StatReport(const __u64 &durationInSec);
673    bool CreateMmap(const FdItem &item, const perf_event_attr &attr);
674    bool CreateSpeMmap(const FdItem &item, const perf_event_attr &attr);
675
676    const perf_event_attr *GetDefaultAttr()
677    {
678        HLOG_ASSERT(eventGroupItem_.size() > 0);
679        HLOG_ASSERT(eventGroupItem_[0].eventItems.size() > 0);
680        return &(eventGroupItem_.at(0).eventItems.at(0).attr);
681    };
682
683    OHOS::UniqueFd Open(perf_event_attr &attr, pid_t pid = 0, int cpu = -1, int groupFd = -1,
684                        unsigned long flags = 0);
685    std::unique_ptr<perf_event_attr> CreateDefaultAttr(perf_type_id type, __u64 config);
686};
687} // namespace HiPerf
688} // namespace Developtools
689} // namespace OHOS
690#endif // HIPERF_PERF_EVENTS_H
691