/*
 * =======================================================================================
 *
 *      Filename:  perfmon_types.h
 *
 *      Description:  Header File of perfmon module.
 *                    Configures and reads out performance counters
 *                    on x86 based architectures. Supports multi threading.
 *
 *      Version:   4.1
 *      Released:  19.5.2016
 *
 *      Author:   Jan Treibig (jt), jan.treibig@gmail.com
 *                Thomas Roehl (tr), thomas.roehl@googlemail.com
 *      Project:  likwid
 *
 *      Copyright (C) 2016 RRZE, University Erlangen-Nuremberg
 *
 *      This program is free software: you can redistribute it and/or modify it under
 *      the terms of the GNU General Public License as published by the Free Software
 *      Foundation, either version 3 of the License, or (at your option) any later
 *      version.
 *
 *      This program is distributed in the hope that it will be useful, but WITHOUT ANY
 *      WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 *      PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License along with
 *      this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * =======================================================================================
 */

#ifndef PERFMON_TYPES_H
#define PERFMON_TYPES_H

#include <bstrlib.h>
#include <timer.h>
#include <inttypes.h>
#include <perfgroup.h>

#define MAX_EVENT_OPTIONS NUM_EVENT_OPTIONS

/* #####   EXPORTED TYPE DEFINITIONS   #################################### */

/** \addtogroup PerfMon
 *  @{
 */
/////////////////////////////////////////////

/*! \brief Enum of possible event and counter options

List of internally used IDs for all event and counter options that are supported
by LIKWID.
\extends PerfmonEventOption
*/
typedef enum {
    EVENT_OPTION_NONE = 0, /*!< \brief No option, used as False value */
    EVENT_OPTION_OPCODE, /*!< \brief Match opcode */
    EVENT_OPTION_MATCH0, /*!< \brief Match0 register */
    EVENT_OPTION_MATCH1, /*!< \brief Match1 register */
    EVENT_OPTION_MATCH2, /*!< \brief Match2 register */
    EVENT_OPTION_MATCH3, /*!< \brief Match3 register */
    EVENT_OPTION_MASK0, /*!< \brief Mask0 register */
    EVENT_OPTION_MASK1, /*!< \brief Mask1 register */
    EVENT_OPTION_MASK2, /*!< \brief Mask2 register */
    EVENT_OPTION_MASK3, /*!< \brief Mask3 register */
    EVENT_OPTION_NID, /*!< \brief Set NUMA node ID */
    EVENT_OPTION_TID, /*!< \brief Set Thread ID */
    EVENT_OPTION_STATE, /*!< \brief Match for state */
    EVENT_OPTION_EDGE, /*!< \brief Increment counter at each edge */
    EVENT_OPTION_THRESHOLD, /*!< \brief Increment only if exceeding threshold */
    EVENT_OPTION_INVERT, /*!< \brief Invert behavior of EVENT_OPTION_THRESHOLD, hence increment only below threshold */
    EVENT_OPTION_COUNT_KERNEL, /*!< \brief Also count events when in kernel space */
    EVENT_OPTION_ANYTHREAD, /*!< \brief Increment counter at events of all HW threads in the core */
    EVENT_OPTION_OCCUPANCY, /*!< \brief Count occupancy not occurrences */
    EVENT_OPTION_OCCUPANCY_FILTER, /*!< \brief Filter for occupancy counting */
    EVENT_OPTION_OCCUPANCY_EDGE, /*!< \brief Increment occupancy counter at detection of an edge */
    EVENT_OPTION_OCCUPANCY_INVERT, /*!< \brief Invert filter for occupancy counting */
    EVENT_OPTION_IN_TRANS, /*!< \brief Count events during transactions */
    EVENT_OPTION_IN_TRANS_ABORT, /*!< \brief Count events that aborted during transactions */
    NUM_EVENT_OPTIONS /*!< \brief Amount of defined options */
} EventOptionType;

/*! \brief Enum of possible states of an event group

List of states for event groups
*/
typedef enum {
    STATE_NONE = 0, /*!< \brief Not configured, not started and not stopped */
    STATE_SETUP, /*!< \brief The event set hold by group is configured */
    STATE_START, /*!< \brief The event set hold by group is current running */
} GroupState;

/*! \brief List of option names

List of strings for all event and counter options used for matching and output
*/
extern char* eventOptionTypeName[NUM_EVENT_OPTIONS];

/** \brief Bitmask with no event/counter option set */
#define EVENT_OPTION_NONE_MASK 0x0ULL
/** \brief Define for easily creating an bitmask of all configured event/counter options */
#define OPTIONS_TYPE_MASK(type) \
        (((type == EVENT_OPTION_NONE)||(type >= NUM_EVENT_OPTIONS)) ? \
        EVENT_OPTION_NONE_MASK : \
        (1ULL<<type))


/** @cond */ 
#define EVENT_OPTION_OPCODE_MASK (1ULL<<EVENT_OPTION_OPCODE)
#define EVENT_OPTION_MATCH0_MASK (1ULL<<EVENT_OPTION_MATCH0)
#define EVENT_OPTION_MATCH1_MASK (1ULL<<EVENT_OPTION_MATCH1)
#define EVENT_OPTION_MATCH2_MASK (1ULL<<EVENT_OPTION_MATCH2)
#define EVENT_OPTION_MATCH3_MASK (1ULL<<EVENT_OPTION_MATCH3)
#define EVENT_OPTION_MASK0_MASK (1ULL<<EVENT_OPTION_MASK0)
#define EVENT_OPTION_MASK1_MASK (1ULL<<EVENT_OPTION_MASK1)
#define EVENT_OPTION_MASK2_MASK (1ULL<<EVENT_OPTION_MASK2)
#define EVENT_OPTION_MASK3_MASK (1ULL<<EVENT_OPTION_MASK3)
#define EVENT_OPTION_NID_MASK (1ULL<<EVENT_OPTION_NID)
#define EVENT_OPTION_TID_MASK (1ULL<<EVENT_OPTION_TID)
#define EVENT_OPTION_STATE_MASK (1ULL<<EVENT_OPTION_STATE)
#define EVENT_OPTION_EDGE_MASK (1ULL<<EVENT_OPTION_EDGE)
#define EVENT_OPTION_THRESHOLD_MASK (1ULL<<EVENT_OPTION_THRESHOLD)
#define EVENT_OPTION_INVERT_MASK (1ULL<<EVENT_OPTION_INVERT)
#define EVENT_OPTION_COUNT_KERNEL_MASK (1ULL<<EVENT_OPTION_COUNT_KERNEL)
#define EVENT_OPTION_ANYTHREAD_MASK (1ULL<<EVENT_OPTION_ANYTHREAD)
#define EVENT_OPTION_OCCUPANCY_MASK (1ULL<<EVENT_OPTION_OCCUPANCY)
#define EVENT_OPTION_OCCUPANCY_FILTER_MASK (1ULL<<EVENT_OPTION_OCCUPANCY_FILTER)
#define EVENT_OPTION_OCCUPANCY_EDGE_MASK (1ULL<<EVENT_OPTION_OCCUPANCY_EDGE)
#define EVENT_OPTION_OCCUPANCY_INVERT_MASK (1ULL<<EVENT_OPTION_OCCUPANCY_INVERT)
#define EVENT_OPTION_IN_TRANS_MASK (1ULL<<EVENT_OPTION_IN_TRANS)
#define EVENT_OPTION_IN_TRANS_ABORT_MASK (1ULL<<EVENT_OPTION_IN_TRANS_ABORT)
/** @endcond */

/*! \brief Structure specifying thread to CPU relation

Threads are always numbered incrementally. This structure is used in order to 
resolve the real HW thread ID.
\extends PerfmonGroupSet
*/
typedef struct {
    int             thread_id; /*!< \brief Thread ID how it is used internally */
    int             processorId; /*!< \brief Real HW thread ID */
} PerfmonThread;

/*! \brief Structure specifying event/counter options and their value

Most options set a bitfield in registers and their values are stored in this structure.
If an option is a binary option, the value is set to 1.
\extends PerfmonEvent
*/
typedef struct {
    EventOptionType      type; /*!< \brief Type of the option */
    uint64_t             value; /*!< \brief Value of the option */
} PerfmonEventOption;

/*! \brief Structure specifying an performance monitoring event

This structure holds the configuration data for an event. It groups the name,
the allowed counters and internally used values like event ID and masks. Moreover
the event options are hold here.
\extends PerfmonEventSetEntry
*/
typedef struct {
    const char*     name; /*!< \brief Name of the event */
    const char*     limit; /*!< \brief Valid counters for the event */
    uint16_t        eventId; /*!< \brief ID of the event */
    uint8_t         umask; /*!< \brief Most events need to specify a mask to limit counting */
    uint8_t         cfgBits; /*!< \brief Misc configuration bits */
    uint64_t        cmask; /*!< \brief Misc mask bits */
    uint8_t         numberOfOptions; /*!< \brief Number of options for the event */
    uint64_t        optionMask; /*!< \brief Bitmask for fast check of set options */
    PerfmonEventOption options[NUM_EVENT_OPTIONS]; /*!< \brief List of options */
} PerfmonEvent;

/*! \brief Structure describing performance monitoring counter data

Each event holds one of these structures for each thread to store the counter
data, if it is configured and the amount of happened overflows.
\extends PerfmonEventSetEntry
*/
typedef struct {
    int         init; /*!< \brief Flag if corresponding control register is set up properly */
    int         id; /*!< \brief Offset in higher level control register, e.g. position of enable bit */
    int         overflows; /*!< \brief Amount of overflows */
    uint64_t    startData; /*!< \brief Start data from the counter */
    uint64_t    counterData; /*!< \brief Intermediate data from the counters */
    double      lastResult; /*!< \brief Last measurement result*/
    double      fullResult; /*!< \brief Aggregated measurement result */
} PerfmonCounter;


/*! \brief Structure specifying an performance monitoring event

An eventSet consists of an event and a counter and the read counter values.
\extends PerfmonEventSet
*/
typedef struct {
    PerfmonEvent        event; /*!< \brief Event configuration */
    RegisterIndex       index; /*!< \brief Index of the counter register in the counter map */
    RegisterType        type; /*!< \brief Type of the counter register and event */
    PerfmonCounter*     threadCounter; /*!< \brief List of counter data for each thread, list length is \a numberOfThreads in PerfmonGroupSet */
} PerfmonEventSetEntry;

/*! \brief Structure specifying an performance monitoring event group

A PerfmonEventSet holds a set of event and counter combinations and some global information about all eventSet entries
\extends PerfmonGroupSet
*/
typedef struct {
    int                   numberOfEvents; /*!< \brief Number of eventSets in \a events */
    PerfmonEventSetEntry* events; /*!< \brief List of eventSets */
    TimerData             timer; /*!< \brief Time information how long the counters were running */
    double                rdtscTime; /*!< \brief Evaluation of the Time information in seconds */
    double                runTime; /*!< \brief Sum of all time information in seconds that the group was running */
#ifdef __x86_64
    __uint128_t           regTypeMask; /*!< \brief Bitmask for easy checks which types are included in the eventSet */
#else
    uint64_t              regTypeMask; /*!< \brief Bitmask for easy checks which types are included in the eventSet */
#endif
    GroupState            state; /*!< \brief Current state of the event group (configured, started, none) */
    GroupInfo             group; /*!< \brief Structure holding the performance group information */
} PerfmonEventSet;

/*! \brief Structure specifying all performance monitoring event groups

The global PerfmonGroupSet structure holds all eventSets and threads that are
configured to measure. Only one eventSet can be measured at a time but the groups
can be switched to perform some kind of multiplexing.
*/
typedef struct {
    int              numberOfGroups; /*!< \brief List length of \a groups*/
    int              numberOfActiveGroups; /*!< \brief Amount of added eventSets. Only those eventSets can be accessed in \a groups. */
    int              activeGroup; /*!< \brief Currently active eventSet */
    PerfmonEventSet* groups; /*!< \brief List of eventSets */
    int              numberOfThreads; /*!< \brief Amount of threads in \a threads */
    PerfmonThread*   threads; /*!< \brief List of threads */
} PerfmonGroupSet;

/** \brief List of counter with name, config register, counter registers and
if needed PCI device */
extern RegisterMap* counter_map;
/** \brief List of boxes with name, config register, counter registers and if
needed PCI device. Mainly used in Uncore handling but also core-local counters
are defined as a box. */
extern BoxMap* box_map;
/** \brief List of events available for the current architecture */
extern PerfmonEvent* eventHash;
/** \brief List of PCI devices available for the current architecture */
extern PciDevice* pci_devices;
/** @}*/

/* perfmon datatypes */
extern PerfmonGroupSet *groupSet;
extern int perfmon_numCounters;
extern int perfmon_numCoreCounters;
extern int perfmon_numUncoreCounters;
extern int perfmon_numArchEvents;


#endif /*PERFMON_TYPES_H*/
