/******************************************************************************
 * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
 * libkperf licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
 * See the Mulan PSL v2 for more details.
 * Author: Mr.Zhang
 * Create: 2024-04-03
 * Description: definition of structures related to performance event sampling and recording in
 * the KUNPENG_PMU namespace
 ******************************************************************************/
#ifndef PMU_EVENT_H
#define PMU_EVENT_H
#include <memory>
#include <map>
#include <string>
#include <vector>
#include <climits>
#include <linux/types.h>
#include "pmu.h"

#ifndef PMU_SAMPLE_STRUCT_H
#define PMU_SAMPLE_STRUCT_H
#include <linux/types.h>
#include <linux/perf_event.h>

#define offset(type, v) (&(((type *)0)->v))

struct PmuEvt {
    __u64 type;     // pmu event type defined in linux/perf_event.h
    __u64 config;   // event configuration
    __u64 config1;  // event filter if applicable
    __u64 config2;  // further filter if necessary on top of config1
    int pmuType;    // if pmu is CORE/UNCORE/SPE and etc (to be implemented)
    int collectType;
    std::string name;   // string name of this pmu event
    std::vector<int> cpuMaskList; // representative CPU number list for each socket (package) in the motherboard.
    unsigned excludeUser : 1;     // don't count user
    unsigned excludeKernel : 1;   //  don't count kernel
    unsigned callStack : 1;   //  collect complete call stack
    unsigned blockedSample : 1; // collect on cpu and off cpu data at the same time
    union {
        unsigned period;            // sample period
        unsigned freq;              // sample frequency
    };
    unsigned useFreq : 1;
    unsigned includeNewFork : 1; // count new fork tid
    int cgroupFd;
    std::string cgroupName;
    unsigned enableUserAccess : 1; // avoid uncore (config1 & 0x2)  == 0x2
    unsigned numEvent;           // pmu event number for bpf cgroup init
    unsigned enableBpf : 1;      // enable bpf mode in counting mode
    unsigned enableHwMetric : 1; // enable hw_metric=1 in sampling mode
    unsigned enableOnExec : 1; // set enable_on_exec = 1 
    unsigned perThread : 1; // --per-thread mode, which just supports sampling mode
};

namespace KUNPENG_PMU {

const int PERF_SAMPLE_MAX_SIZE (1 << 16);

struct PerfRawSample {
    __u64 sampleid;
    __u64 ip;
    __u32 pid, tid;
    __u64 time;
    __u64 id;
    int cpu;
    __u64 period;
    __u64 nr;
    unsigned long ips[];
};

struct PerfSampleInfo {
    __u64 time;
};

struct TraceRawData {
    __u32 size;
    char data[];
};

struct BranchSampleData {
    __u64 bnr;
    struct perf_branch_entry lbr[];
};

struct PerfTraceSample {
    __u64 sampleId;
    __u32 tid, pid;
    __u64 time;
    __u32 cpu;
    __u32 size;
    char data[];
};

struct sampleId {
    __u32 pid, tid;     /* if PERF_SAMPLE_TID set */
    __u64 time;         /* if PERF_SAMPLE_TIME set */
    __u64 id;           /* if PERF_SAMPLE_ID set */
    __u32 cpu, res;     /* if PERF_SAMPLE_CPU set */
    __u64 identifier;   /* if PERF_SAMPLE_IDENTIFIER set */
};

struct ContextSwitchEvent {
    struct perf_event_header header;
    struct sampleId sampleId;
};

struct PmuSwitchData {
    __u32 pid, tid;         // process id and thread id
    __u64 ts;               // time stamp. unit: ns
    __u32 cpu;              // cpu id
    unsigned swOut : 1;     // 1: switch out, 0: switch in, 0 is the default value
};

struct PerfRawMmap {
    __u32 pid, tid;
    __u64 addr;
    __u64 len;
    __u64 pgoff;
    char filename[];
};

struct PerfRecordMmap {
    struct perf_event_header header;
    __u32 pid, tid;
    __u64 addr;
    __u64 len;
    __u64 pgoff;
    char filename[PATH_MAX];
};

struct PerfRecordMmap2 {
    struct perf_event_header header;
    __u32 pid, tid;
    __u64 addr;
    __u64 len;
    __u64 pgoff;
    __u32 maj;
    __u32 min;
    __u64 ino;
    __u64 ino_generation;
    __u32 prot, flags;
    char filename[PATH_MAX];
};

struct PerfRecordComm {
    struct perf_event_header header;
    __u32 pid, tid;
    char comm[16];
};

struct PerfRecordSample {
    struct perf_event_header header;
    __u64 array[];
};

struct PerfRecordFork {
    struct perf_event_header header;
    __u32 pid, ppid;
    __u32 tid, ptid;
    __u64 time;
};

struct PerfRecordExit {
    struct perf_event_header header;
    __u32 pid, ppid;
    __u32 tid, ptid;
    __u64 time;
};

struct PerfMmap {
    struct perf_event_mmap_page* base;
    int mask;
    int fd;
    __u64 prev;
    __u64 start;
    __u64 end;
    bool overwrite;
    __u64 flush;
    char copiedEvent[PERF_SAMPLE_MAX_SIZE];
};

struct PerfSampleIps {
    std::vector<unsigned long> ips;
};

union PerfEvent {
    struct perf_event_header header;
    struct PerfRecordMmap  mmap;
    struct PerfRecordComm comm;
    struct PerfRecordFork fork;
    struct PerfRecordSample sample;
    struct PerfRecordExit exit;
    struct PerfRecordMmap2 mmap2;
    struct ContextSwitchEvent context_switch;
};

struct EventData {
    unsigned pd;
    PmuTaskType collectType;
    std::vector<PmuData> data;
    std::vector<PerfSampleIps> sampleIps;
    std::vector<PmuDataExt *> extPool;
    std::vector<PmuSwitchData> switchData;
    std::vector<PerfRecordSample> metaData;
};

int MapErrno(int sysErr);
struct PerfSampleInfo GetPerfSampleInfo(__u64 sampleType, PerfEvent* event);
}   // namespace KUNPENG_PMU
#endif
#endif