/** @file
 * STAM - Statistics Manager.
 */

/*
 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
 *
 * This file is part of VirtualBox base platform packages, as
 * available from https://www.virtualbox.org.
 *
 * 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, in version 3 of the
 * License.
 *
 * 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 <https://www.gnu.org/licenses>.
 *
 * The contents of this file may alternatively be used under the terms
 * of the Common Development and Distribution License Version 1.0
 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
 * in the VirtualBox distribution, in which case the provisions of the
 * CDDL are applicable instead of those of the GPL.
 *
 * You may elect to license modified versions of this file under the
 * terms and conditions of either the GPL or the CDDL or both.
 *
 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
 */

#ifndef VBOX_INCLUDED_vmm_stam_h
#define VBOX_INCLUDED_vmm_stam_h
#ifndef RT_WITHOUT_PRAGMA_ONCE
# pragma once
#endif

#include <VBox/types.h>
#include <iprt/stdarg.h>
#ifdef _MSC_VER
# if RT_MSC_PREREQ(RT_MSC_VER_VS2005)
#  include <iprt/sanitized/intrin.h>
# endif
#endif
#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)
# include <iprt/asm-arm.h>
#endif

RT_C_DECLS_BEGIN

/** @defgroup grp_stam     The Statistics Manager API
 * @ingroup grp_vmm
 * @{
 */

#if defined(VBOX_WITHOUT_RELEASE_STATISTICS) && defined(VBOX_WITH_STATISTICS)
# error "Both VBOX_WITHOUT_RELEASE_STATISTICS and VBOX_WITH_STATISTICS are defined! Make up your mind!"
#endif


/** @def STAM_GET_TS
 * Gets the CPU timestamp counter.
 *
 * @param   u64     The 64-bit variable which the timestamp shall be saved in.
 */
#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)
#  define STAM_GET_TS(u64) do { (u64) = ASMReadTSC(); } while (0)
#elif defined(__GNUC__)
# if defined(RT_ARCH_X86)
   /* This produces optimal assembler code for x86 but does not work for AMD64 ('A' means 'either rax or rdx') */
#  define STAM_GET_TS(u64) __asm__ __volatile__ ("rdtsc\n\t" : "=A" (u64))
# elif defined(RT_ARCH_AMD64)
#  define STAM_GET_TS(u64) \
    do { uint64_t low; uint64_t high; \
         __asm__ __volatile__ ("rdtsc\n\t" : "=a"(low), "=d"(high)); \
         (u64) = ((high << 32) | low); \
    } while (0)
# endif
#else
# if RT_MSC_PREREQ(RT_MSC_VER_VS2005)
#  pragma intrinsic(__rdtsc)
#  define STAM_GET_TS(u64)    \
     do { (u64) = __rdtsc(); } while (0)
# else
#  define STAM_GET_TS(u64)    \
     do {                               \
         uint64_t u64Tmp;               \
         __asm {                        \
             __asm rdtsc                \
             __asm mov dword ptr [u64Tmp],     eax   \
             __asm mov dword ptr [u64Tmp + 4], edx   \
         }                              \
         (u64) = u64Tmp; \
     } while (0)
# endif
#endif


/** @def STAM_REL_STATS
 * Code for inclusion only when VBOX_WITH_STATISTICS is defined.
 * @param   code    A code block enclosed in {}.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_STATS(code) do code while(0)
#else
# define STAM_REL_STATS(code) do {} while(0)
#endif
/** @def STAM_STATS
 * Code for inclusion only when VBOX_WITH_STATISTICS is defined.
 * @param   code    A code block enclosed in {}.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_STATS(code) STAM_REL_STATS(code)
#else
# define STAM_STATS(code) do {} while(0)
#endif


/**
 * Sample type.
 */
typedef enum STAMTYPE
{
    /** Invalid entry. */
    STAMTYPE_INVALID = 0,
    /** Generic counter. */
    STAMTYPE_COUNTER,
    /** Profiling of an function. */
    STAMTYPE_PROFILE,
    /** Profiling of an operation. */
    STAMTYPE_PROFILE_ADV,
    /** Ratio of A to B, uint32_t types. Not reset. */
    STAMTYPE_RATIO_U32,
    /** Ratio of A to B, uint32_t types. Reset both to 0. */
    STAMTYPE_RATIO_U32_RESET,
    /** Callback. */
    STAMTYPE_CALLBACK,
    /** Generic unsigned 8-bit value. Not reset. */
    STAMTYPE_U8,
    /** Generic unsigned 8-bit value. Reset to 0. */
    STAMTYPE_U8_RESET,
    /** Generic hexadecimal unsigned 8-bit value. Not reset. */
    STAMTYPE_X8,
    /** Generic hexadecimal unsigned 8-bit value. Reset to 0. */
    STAMTYPE_X8_RESET,
    /** Generic unsigned 16-bit value. Not reset. */
    STAMTYPE_U16,
    /** Generic unsigned 16-bit value. Reset to 0. */
    STAMTYPE_U16_RESET,
    /** Generic hexadecimal unsigned 16-bit value. Not reset. */
    STAMTYPE_X16,
    /** Generic hexadecimal unsigned 16-bit value. Reset to 0. */
    STAMTYPE_X16_RESET,
    /** Generic unsigned 32-bit value. Not reset. */
    STAMTYPE_U32,
    /** Generic unsigned 32-bit value. Reset to 0. */
    STAMTYPE_U32_RESET,
    /** Generic hexadecimal unsigned 32-bit value. Not reset. */
    STAMTYPE_X32,
    /** Generic hexadecimal unsigned 32-bit value. Reset to 0. */
    STAMTYPE_X32_RESET,
    /** Generic unsigned 64-bit value. Not reset. */
    STAMTYPE_U64,
    /** Generic unsigned 64-bit value. Reset to 0. */
    STAMTYPE_U64_RESET,
    /** Generic hexadecimal unsigned 64-bit value. Not reset. */
    STAMTYPE_X64,
    /** Generic hexadecimal unsigned 64-bit value. Reset to 0. */
    STAMTYPE_X64_RESET,
    /** Generic boolean value. Not reset. */
    STAMTYPE_BOOL,
    /** Generic boolean value. Reset to false. */
    STAMTYPE_BOOL_RESET,
    /** Start of the internal types. */
    STAMTYPE_FIRST_INTERNAL_TYPE,
    /** Sum of two or more other samples. */
    STAMTYPE_INTERNAL_SUM = STAMTYPE_FIRST_INTERNAL_TYPE,
    /** Percent of a sum. */
    STAMTYPE_INTERNAL_PCT_OF_SUM,
    /** The end (exclusive). */
    STAMTYPE_END
} STAMTYPE;

/**
 * Sample visibility type.
 */
typedef enum STAMVISIBILITY
{
    /** Invalid entry. */
    STAMVISIBILITY_INVALID = 0,
    /** Always visible. */
    STAMVISIBILITY_ALWAYS,
    /** Only visible when used (/hit). */
    STAMVISIBILITY_USED,
    /** Not visible in the GUI. */
    STAMVISIBILITY_NOT_GUI,
    /** The end (exclusive). */
    STAMVISIBILITY_END
} STAMVISIBILITY;

/**
 * Sample unit.
 */
typedef enum STAMUNIT
{
    /** Invalid entry .*/
    STAMUNIT_INVALID = 0,
    /** No unit. */
    STAMUNIT_NONE,
    /** Number of calls. */
    STAMUNIT_CALLS,
    /** Number of calls per translation block. */
    STAMUNIT_CALLS_PER_TB,
    /** Count of whatever. */
    STAMUNIT_COUNT,
    /** Count of bytes. */
    STAMUNIT_BYTES,
    /** Count of bytes per call. */
    STAMUNIT_BYTES_PER_CALL,
    /** Count of bytes. */
    STAMUNIT_PAGES,
    /** Error count. */
    STAMUNIT_ERRORS,
    /** Number of occurences. */
    STAMUNIT_OCCURENCES,
    /** Ticks. */
    STAMUNIT_TICKS,
    /** Ticks per call. */
    STAMUNIT_TICKS_PER_CALL,
    /** Ticks per occurence. */
    STAMUNIT_TICKS_PER_OCCURENCE,
    /** Ratio of good vs. bad. */
    STAMUNIT_GOOD_BAD,
    /** Megabytes. */
    STAMUNIT_MEGABYTES,
    /** Kilobytes. */
    STAMUNIT_KILOBYTES,
    /** Nano seconds. */
    STAMUNIT_NS,
    /** Nanoseconds per call. */
    STAMUNIT_NS_PER_CALL,
    /** Nanoseconds per call. */
    STAMUNIT_NS_PER_OCCURENCE,
    /** Percentage. */
    STAMUNIT_PCT,
    /** Parts per thousand. */
    STAMUNIT_PP1K,
    /** Parts per ten thousand. */
    STAMUNIT_PP10K,
    /** Parts per million. */
    STAMUNIT_PPM,
    /** Parts per billion. */
    STAMUNIT_PPB,
    /** Hertz. */
    STAMUNIT_HZ,
    /** Instructions. */
    STAMUNIT_INSTR,
    /** Instructions per translation block. */
    STAMUNIT_INSTR_PER_TB,
    /** Bytes per translation block. */
    STAMUNIT_BYTES_PER_TB,
    /** The end (exclusive). */
    STAMUNIT_END
} STAMUNIT;

/** @name STAM_REFRESH_GRP_XXX - STAM refresh groups
 * @{ */
#define STAM_REFRESH_GRP_NONE       UINT8_MAX
#define STAM_REFRESH_GRP_GVMM       0
#define STAM_REFRESH_GRP_GMM        1
#define STAM_REFRESH_GRP_NEM        2
/** @} */


/** @def STAM_REL_U8_INC
 * Increments a uint8_t sample by one.
 *
 * @param   pCounter    Pointer to the uint8_t variable to operate on.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_U8_INC(pCounter) \
    do { ++*(pCounter); } while (0)
#else
# define STAM_REL_U8_INC(pCounter) do { } while (0)
#endif
/** @def STAM_U8_INC
 * Increments a uint8_t sample by one.
 *
 * @param   pCounter    Pointer to the uint8_t variable to operate on.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_U8_INC(pCounter) STAM_REL_U8_INC(pCounter)
#else
# define STAM_U8_INC(pCounter) do { } while (0)
#endif


/** @def STAM_REL_U8_DEC
 * Decrements a uint8_t sample by one.
 *
 * @param   pCounter    Pointer to the uint8_t variable to operate on.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_U8_DEC(pCounter) \
    do { --*(pCounter); } while (0)
#else
# define STAM_REL_U8_DEC(pCounter) do { } while (0)
#endif
/** @def STAM_U8_DEC
 * Decrements a uint8_t sample by one.
 *
 * @param   pCounter    Pointer to the uint8_t variable to operate on.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_U8_DEC(pCounter) STAM_REL_U8_DEC(pCounter)
#else
# define STAM_U8_DEC(pCounter) do { } while (0)
#endif


/** @def STAM_REL_U8_ADD
 * Increments a uint8_t sample by a value.
 *
 * @param   pCounter    Pointer to the uint8_t variable to operate on.
 * @param   Addend      The value to add.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_U8_ADD(pCounter, Addend) \
    do { *(pCounter) += (Addend); } while (0)
#else
# define STAM_REL_U8_ADD(pCounter, Addend) do { } while (0)
#endif
/** @def STAM_U8_ADD
 * Increments a uint8_t sample by a value.
 *
 * @param   pCounter    Pointer to the uint8_t variable to operate on.
 * @param   Addend      The value to add.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_U8_ADD(pCounter, Addend) STAM_REL_U8_ADD(pCounter, Addend
#else
# define STAM_U8_ADD(pCounter, Addend) do { } while (0)
#endif


/** @def STAM_REL_U16_INC
 * Increments a uint16_t sample by one.
 *
 * @param   pCounter    Pointer to the uint16_t variable to operate on.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_U16_INC(pCounter) \
    do { ++*(pCounter); } while (0)
#else
# define STAM_REL_U16_INC(pCounter) do { } while (0)
#endif
/** @def STAM_U16_INC
 * Increments a uint16_t sample by one.
 *
 * @param   pCounter    Pointer to the uint16_t variable to operate on.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_U16_INC(pCounter) STAM_REL_U16_INC(pCounter)
#else
# define STAM_U16_INC(pCounter) do { } while (0)
#endif


/** @def STAM_REL_U16_DEC
 * Decrements a uint16_t sample by one.
 *
 * @param   pCounter    Pointer to the uint16_t variable to operate on.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_U16_DEC(pCounter) \
    do { --*(pCounter); } while (0)
#else
# define STAM_REL_U16_DEC(pCounter) do { } while (0)
#endif
/** @def STAM_U16_DEC
 * Decrements a uint16_t sample by one.
 *
 * @param   pCounter    Pointer to the uint16_t variable to operate on.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_U16_DEC(pCounter) STAM_REL_U16_DEC(pCounter)
#else
# define STAM_U16_DEC(pCounter) do { } while (0)
#endif


/** @def STAM_REL_U16_ADD
 * Increments a uint16_t sample by a value.
 *
 * @param   pCounter    Pointer to the uint16_t variable to operate on.
 * @param   Addend      The value to add.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_U16_ADD(pCounter, Addend) \
    do { *(pCounter) += (Addend); } while (0)
#else
# define STAM_REL_U16_ADD(pCounter, Addend) do { } while (0)
#endif
/** @def STAM_U16_ADD
 * Increments a uint16_t sample by a value.
 *
 * @param   pCounter    Pointer to the uint16_t variable to operate on.
 * @param   Addend      The value to add.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_U16_ADD(pCounter, Addend) STAM_REL_U16_ADD(pCounter, Addend)
#else
# define STAM_U16_ADD(pCounter, Addend) do { } while (0)
#endif


/** @def STAM_REL_U32_INC
 * Increments a uint32_t sample by one.
 *
 * @param   pCounter    Pointer to the uint32_t variable to operate on.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_U32_INC(pCounter) \
    do { ++*(pCounter); } while (0)
#else
# define STAM_REL_U32_INC(pCounter) do { } while (0)
#endif
/** @def STAM_U32_INC
 * Increments a uint32_t sample by one.
 *
 * @param   pCounter    Pointer to the uint32_t variable to operate on.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_U32_INC(pCounter) STAM_REL_U32_INC(pCounter)
#else
# define STAM_U32_INC(pCounter) do { } while (0)
#endif


/** @def STAM_REL_U32_DEC
 * Decrements a uint32_t sample by one.
 *
 * @param   pCounter    Pointer to the uint32_t variable to operate on.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_U32_DEC(pCounter) \
    do { --*(pCounter); } while (0)
#else
# define STAM_REL_U32_DEC(pCounter) do { } while (0)
#endif
/** @def STAM_U32_DEC
 * Decrements a uint32_t sample by one.
 *
 * @param   pCounter    Pointer to the uint32_t variable to operate on.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_U32_DEC(pCounter) STAM_REL_U32_DEC(pCounter)
#else
# define STAM_U32_DEC(pCounter) do { } while (0)
#endif


/** @def STAM_REL_U32_ADD
 * Increments a uint32_t sample by value.
 *
 * @param   pCounter    Pointer to the uint32_t variable to operate on.
 * @param   Addend      The value to add.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_U32_ADD(pCounter, Addend) \
    do { *(pCounter) += (Addend); } while (0)
#else
# define STAM_REL_U32_ADD(pCounter, Addend) do { } while (0)
#endif
/** @def STAM_U32_ADD
 * Increments a uint32_t sample by value.
 *
 * @param   pCounter    Pointer to the uint32_t variable to operate on.
 * @param   Addend      The value to add.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_U32_ADD(pCounter, Addend) STAM_REL_U32_ADD(pCounter, Addend)
#else
# define STAM_U32_ADD(pCounter, Addend) do { } while (0)
#endif


/** @def STAM_REL_U64_INC
 * Increments a uint64_t sample by one.
 *
 * @param   pCounter    Pointer to the uint64_t variable to operate on.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_U64_INC(pCounter) \
    do { ++*(pCounter); } while (0)
#else
# define STAM_REL_U64_INC(pCounter) do { } while (0)
#endif
/** @def STAM_U64_INC
 * Increments a uint64_t sample by one.
 *
 * @param   pCounter    Pointer to the uint64_t variable to operate on.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_U64_INC(pCounter) STAM_REL_U64_INC(pCounter)
#else
# define STAM_U64_INC(pCounter) do { } while (0)
#endif


/** @def STAM_REL_U64_DEC
 * Decrements a uint64_t sample by one.
 *
 * @param   pCounter    Pointer to the uint64_t variable to operate on.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_U64_DEC(pCounter) \
    do { --*(pCounter); } while (0)
#else
# define STAM_REL_U64_DEC(pCounter) do { } while (0)
#endif
/** @def STAM_U64_DEC
 * Decrements a uint64_t sample by one.
 *
 * @param   pCounter    Pointer to the uint64_t variable to operate on.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_U64_DEC(pCounter) STAM_REL_U64_DEC(pCounter)
#else
# define STAM_U64_DEC(pCounter) do { } while (0)
#endif


/** @def STAM_REL_U64_ADD
 * Increments a uint64_t sample by a value.
 *
 * @param   pCounter    Pointer to the uint64_t variable to operate on.
 * @param   Addend      The value to add.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_U64_ADD(pCounter, Addend) \
    do { *(pCounter) += (Addend); } while (0)
#else
# define STAM_REL_U64_ADD(pCounter, Addend) do { } while (0)
#endif
/** @def STAM_U64_ADD
 * Increments a uint64_t sample by a value.
 *
 * @param   pCounter    Pointer to the uint64_t variable to operate on.
 * @param   Addend      The value to add.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_U64_ADD(pCounter, Addend) STAM_REL_U64_ADD(pCounter, Addend)
#else
# define STAM_U64_ADD(pCounter, Addend) do { } while (0)
#endif


/**
 * Counter sample - STAMTYPE_COUNTER.
 */
typedef struct STAMCOUNTER
{
    /** The current count. */
    volatile uint64_t   c;
} STAMCOUNTER;
/** Pointer to a counter. */
typedef STAMCOUNTER *PSTAMCOUNTER;
/** Pointer to a const counter. */
typedef const STAMCOUNTER *PCSTAMCOUNTER;


/** @def STAM_REL_COUNTER_INC
 * Increments a counter sample by one.
 *
 * @param   pCounter    Pointer to the STAMCOUNTER structure to operate on.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_COUNTER_INC(pCounter) \
    do { (pCounter)->c++; } while (0)
#else
# define STAM_REL_COUNTER_INC(pCounter) do { } while (0)
#endif
/** @def STAM_COUNTER_INC
 * Increments a counter sample by one.
 *
 * @param   pCounter    Pointer to the STAMCOUNTER structure to operate on.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_COUNTER_INC(pCounter) STAM_REL_COUNTER_INC(pCounter)
#else
# define STAM_COUNTER_INC(pCounter) do { } while (0)
#endif


/** @def STAM_REL_COUNTER_DEC
 * Decrements a counter sample by one.
 *
 * @param   pCounter    Pointer to the STAMCOUNTER structure to operate on.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_COUNTER_DEC(pCounter) \
    do { (pCounter)->c--; } while (0)
#else
# define STAM_REL_COUNTER_DEC(pCounter) do { } while (0)
#endif
/** @def STAM_COUNTER_DEC
 * Decrements a counter sample by one.
 *
 * @param   pCounter    Pointer to the STAMCOUNTER structure to operate on.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_COUNTER_DEC(pCounter) STAM_REL_COUNTER_DEC(pCounter)
#else
# define STAM_COUNTER_DEC(pCounter) do { } while (0)
#endif


/** @def STAM_REL_COUNTER_ADD
 * Increments a counter sample by a value.
 *
 * @param   pCounter    Pointer to the STAMCOUNTER structure to operate on.
 * @param   Addend      The value to add to the counter.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_COUNTER_ADD(pCounter, Addend) \
    do { (pCounter)->c += (Addend); } while (0)
#else
# define STAM_REL_COUNTER_ADD(pCounter, Addend) do { } while (0)
#endif
/** @def STAM_COUNTER_ADD
 * Increments a counter sample by a value.
 *
 * @param   pCounter    Pointer to the STAMCOUNTER structure to operate on.
 * @param   Addend      The value to add to the counter.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_COUNTER_ADD(pCounter, Addend) STAM_REL_COUNTER_ADD(pCounter, Addend)
#else
# define STAM_COUNTER_ADD(pCounter, Addend) do { } while (0)
#endif


/** @def STAM_REL_COUNTER_RESET
 * Resets the statistics sample.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_COUNTER_RESET(pCounter) do { (pCounter)->c = 0; } while (0)
#else
# define STAM_REL_COUNTER_RESET(pCounter) do { } while (0)
#endif
/** @def STAM_COUNTER_RESET
 * Resets the statistics sample.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_COUNTER_RESET(pCounter) STAM_REL_COUNTER_RESET(pCounter)
#else
# define STAM_COUNTER_RESET(pCounter) do { } while (0)
#endif



/**
 * Profiling sample - STAMTYPE_PROFILE.
 */
typedef struct STAMPROFILE
{
    /** Number of periods. */
    volatile uint64_t   cPeriods;
    /** Total count of ticks. */
    volatile uint64_t   cTicks;
    /** Maximum tick count during a sampling. */
    volatile uint64_t   cTicksMax;
    /** Minimum tick count during a sampling. */
    volatile uint64_t   cTicksMin;
} STAMPROFILE;
/** Pointer to a profile sample. */
typedef STAMPROFILE *PSTAMPROFILE;
/** Pointer to a const profile sample. */
typedef const STAMPROFILE *PCSTAMPROFILE;


/** @def STAM_REL_PROFILE_ADD_PERIOD
 * Adds a period.
 *
 * @param   pProfile        Pointer to the STAMPROFILE structure to operate on.
 * @param   cTicksInPeriod  The number of tick (or whatever) of the preiod
 *                          being added.  This is only referenced once.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_PROFILE_ADD_PERIOD(pProfile, cTicksInPeriod) \
    do { \
        uint64_t const StamPrefix_cTicks = (cTicksInPeriod); \
        (pProfile)->cTicks += StamPrefix_cTicks; \
        (pProfile)->cPeriods++; \
        if ((pProfile)->cTicksMax < StamPrefix_cTicks) \
            (pProfile)->cTicksMax = StamPrefix_cTicks; \
        if ((pProfile)->cTicksMin > StamPrefix_cTicks) \
            (pProfile)->cTicksMin = StamPrefix_cTicks; \
    } while (0)
#else
# define STAM_REL_PROFILE_ADD_PERIOD(pProfile, cTicksInPeriod) do { } while (0)
#endif
/** @def STAM_PROFILE_ADD_PERIOD
 * Adds a period.
 *
 * @param   pProfile        Pointer to the STAMPROFILE structure to operate on.
 * @param   cTicksInPeriod  The number of tick (or whatever) of the preiod
 *                          being added.  This is only referenced once.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_PROFILE_ADD_PERIOD(pProfile, cTicksInPeriod) STAM_REL_PROFILE_ADD_PERIOD(pProfile, cTicksInPeriod)
#else
# define STAM_PROFILE_ADD_PERIOD(pProfile, cTicksInPeriod) do { } while (0)
#endif


/** @def STAM_REL_PROFILE_START
 * Samples the start time of a profiling period.
 *
 * @param   pProfile    Pointer to the STAMPROFILE structure to operate on.
 * @param   Prefix      Identifier prefix used to internal variables.
 *
 * @remarks Declears a stack variable that will be used by related macros.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_PROFILE_START(pProfile, Prefix) \
    uint64_t Prefix##_tsStart; \
    STAM_GET_TS(Prefix##_tsStart)
#else
# define STAM_REL_PROFILE_START(pProfile, Prefix) do { } while (0)
#endif
/** @def STAM_PROFILE_START
 * Samples the start time of a profiling period.
 *
 * @param   pProfile    Pointer to the STAMPROFILE structure to operate on.
 * @param   Prefix      Identifier prefix used to internal variables.
 *
 * @remarks Declears a stack variable that will be used by related macros.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_PROFILE_START(pProfile, Prefix) STAM_REL_PROFILE_START(pProfile, Prefix)
#else
# define STAM_PROFILE_START(pProfile, Prefix) do { } while (0)
#endif

/** @def STAM_REL_PROFILE_STOP
 * Samples the stop time of a profiling period and updates the sample.
 *
 * @param   pProfile    Pointer to the STAMPROFILE structure to operate on.
 * @param   Prefix      Identifier prefix used to internal variables.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_PROFILE_STOP(pProfile, Prefix) \
    do { \
        uint64_t Prefix##_cTicks; \
        STAM_GET_TS(Prefix##_cTicks); \
        Prefix##_cTicks -= Prefix##_tsStart; \
        (pProfile)->cTicks += Prefix##_cTicks; \
        (pProfile)->cPeriods++; \
        if ((pProfile)->cTicksMax < Prefix##_cTicks) \
            (pProfile)->cTicksMax = Prefix##_cTicks; \
        if ((pProfile)->cTicksMin > Prefix##_cTicks) \
            (pProfile)->cTicksMin = Prefix##_cTicks; \
    } while (0)
#else
# define STAM_REL_PROFILE_STOP(pProfile, Prefix) do { } while (0)
#endif
/** @def STAM_PROFILE_STOP
 * Samples the stop time of a profiling period and updates the sample.
 *
 * @param   pProfile    Pointer to the STAMPROFILE structure to operate on.
 * @param   Prefix      Identifier prefix used to internal variables.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_PROFILE_STOP(pProfile, Prefix) STAM_REL_PROFILE_STOP(pProfile, Prefix)
#else
# define STAM_PROFILE_STOP(pProfile, Prefix) do { } while (0)
#endif


/** @def STAM_REL_PROFILE_STOP_EX
 * Samples the stop time of a profiling period and updates both the sample
 * and an attribution sample.
 *
 * @param   pProfile    Pointer to the STAMPROFILE structure to operate on.
 * @param   pProfile2   Pointer to the STAMPROFILE structure which this
 *                      interval should be attributed to as well. This may be NULL.
 * @param   Prefix      Identifier prefix used to internal variables.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_PROFILE_STOP_EX(pProfile, pProfile2, Prefix) \
    do { \
        uint64_t Prefix##_cTicks; \
        STAM_GET_TS(Prefix##_cTicks); \
        Prefix##_cTicks -= Prefix##_tsStart; \
        (pProfile)->cTicks += Prefix##_cTicks; \
        (pProfile)->cPeriods++; \
        if ((pProfile)->cTicksMax < Prefix##_cTicks) \
            (pProfile)->cTicksMax = Prefix##_cTicks; \
        if ((pProfile)->cTicksMin > Prefix##_cTicks) \
            (pProfile)->cTicksMin = Prefix##_cTicks; \
        \
        if ((pProfile2)) \
        { \
            (pProfile2)->cTicks += Prefix##_cTicks; \
            (pProfile2)->cPeriods++; \
            if ((pProfile2)->cTicksMax < Prefix##_cTicks) \
                (pProfile2)->cTicksMax = Prefix##_cTicks; \
            if ((pProfile2)->cTicksMin > Prefix##_cTicks) \
                (pProfile2)->cTicksMin = Prefix##_cTicks; \
        } \
    } while (0)
#else
# define STAM_REL_PROFILE_STOP_EX(pProfile, pProfile2, Prefix) do { } while (0)
#endif
/** @def STAM_PROFILE_STOP_EX
 * Samples the stop time of a profiling period and updates both the sample
 * and an attribution sample.
 *
 * @param   pProfile    Pointer to the STAMPROFILE structure to operate on.
 * @param   pProfile2   Pointer to the STAMPROFILE structure which this
 *                      interval should be attributed to as well. This may be NULL.
 * @param   Prefix      Identifier prefix used to internal variables.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_PROFILE_STOP_EX(pProfile, pProfile2, Prefix) STAM_REL_PROFILE_STOP_EX(pProfile, pProfile2, Prefix)
#else
# define STAM_PROFILE_STOP_EX(pProfile, pProfile2, Prefix) do { } while (0)
#endif


/** @def STAM_REL_PROFILE_STOP_START
 * Stops one profile counter (if running) and starts another one.
 *
 * @param   pProfile1   Pointer to the STAMPROFILE structure to stop.
 * @param   pProfile2   Pointer to the STAMPROFILE structure to start.
 * @param   Prefix      Identifier prefix used to internal variables.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_PROFILE_STOP_START(pProfile1, pProfile2, Prefix) \
    do { \
        uint64_t Prefix##_tsStop; \
        STAM_GET_TS(Prefix##_tsStop); \
        STAM_REL_PROFILE_ADD_PERIOD(pProfile1, Prefix##_tsStop - Prefix##_tsStart); \
        Prefix##_tsStart = Prefix##_tsStop; \
    } while (0)
#else
# define STAM_REL_PROFILE_STOP_START(pProfile1, pProfile2, Prefix) \
    do { } while (0)
#endif
/** @def STAM_PROFILE_STOP_START
 * Samples the stop time of a profiling period (if running) and updates the
 * sample.
 *
 * @param   pProfile1   Pointer to the STAMPROFILE structure to stop.
 * @param   pProfile2   Pointer to the STAMPROFILE structure to start.
 * @param   Prefix      Identifier prefix used to internal variables.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_PROFILE_STOP_START(pProfile1, pProfile2, Prefix) \
    STAM_REL_PROFILE_STOP_START(pProfile1, pProfile2, Prefix)
#else
# define STAM_PROFILE_STOP_START(pProfile1, pProfile2, Prefix) \
    do { } while (0)
#endif


/** @def STAM_REL_PROFILE_START_NS
 * Samples the start time of a profiling period, using RTTimeNanoTS().
 *
 * @param   pProfile    Pointer to the STAMPROFILE structure to operate on.
 * @param   Prefix      Identifier prefix used to internal variables.
 *
 * @remarks Declears a stack variable that will be used by related macros.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_PROFILE_START_NS(pProfile, Prefix) \
    uint64_t const Prefix##_tsStart = RTTimeNanoTS()
#else
# define STAM_REL_PROFILE_START_NS(pProfile, Prefix) do { } while (0)
#endif
/** @def STAM_PROFILE_START_NS
 * Samples the start time of a profiling period, using RTTimeNanoTS().
 *
 * @param   pProfile    Pointer to the STAMPROFILE structure to operate on.
 * @param   Prefix      Identifier prefix used to internal variables.
 *
 * @remarks Declears a stack variable that will be used by related macros.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_PROFILE_START_NS(pProfile, Prefix) STAM_REL_PROFILE_START_NS(pProfile, Prefix)
#else
# define STAM_PROFILE_START_NS(pProfile, Prefix) do { } while (0)
#endif

/** @def STAM_REL_PROFILE_STOP_NS
 * Samples the stop time of a profiling period and updates the sample, using
 * RTTimeNanoTS().
 *
 * @param   pProfile    Pointer to the STAMPROFILE structure to operate on.
 * @param   Prefix      Identifier prefix used to internal variables.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_PROFILE_STOP_NS(pProfile, Prefix) \
    STAM_REL_PROFILE_ADD_PERIOD(pProfile, RTTimeNanoTS() - Prefix##_tsStart)
#else
# define STAM_REL_PROFILE_STOP_NS(pProfile, Prefix) do { } while (0)
#endif
/** @def STAM_PROFILE_STOP_NS
 * Samples the stop time of a profiling period and updates the sample, using
 * RTTimeNanoTS().
 *
 * @param   pProfile    Pointer to the STAMPROFILE structure to operate on.
 * @param   Prefix      Identifier prefix used to internal variables.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_PROFILE_STOP_NS(pProfile, Prefix) STAM_REL_PROFILE_STOP_NS(pProfile, Prefix)
#else
# define STAM_PROFILE_STOP_NS(pProfile, Prefix) do { } while (0)
#endif


/**
 * Advanced profiling sample - STAMTYPE_PROFILE_ADV.
 *
 * Identical to a STAMPROFILE sample, but the start timestamp
 * is stored after the STAMPROFILE structure so the sampling
 * can start and stop in different functions.
 */
typedef struct STAMPROFILEADV
{
    /** The STAMPROFILE core. */
    STAMPROFILE         Core;
    /** The start timestamp. */
    volatile uint64_t   tsStart;
} STAMPROFILEADV;
/** Pointer to a advanced profile sample. */
typedef STAMPROFILEADV *PSTAMPROFILEADV;
/** Pointer to a const advanced profile sample. */
typedef const STAMPROFILEADV *PCSTAMPROFILEADV;


/** @def STAM_REL_PROFILE_ADV_START
 * Samples the start time of a profiling period.
 *
 * @param   pProfileAdv Pointer to the STAMPROFILEADV structure to operate on.
 * @param   Prefix      Identifier prefix used to internal variables.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_PROFILE_ADV_START(pProfileAdv, Prefix) \
    STAM_GET_TS((pProfileAdv)->tsStart)
#else
# define STAM_REL_PROFILE_ADV_START(pProfileAdv, Prefix) do { } while (0)
#endif
/** @def STAM_PROFILE_ADV_START
 * Samples the start time of a profiling period.
 *
 * @param   pProfileAdv Pointer to the STAMPROFILEADV structure to operate on.
 * @param   Prefix      Identifier prefix used to internal variables.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_PROFILE_ADV_START(pProfileAdv, Prefix) STAM_REL_PROFILE_ADV_START(pProfileAdv, Prefix)
#else
# define STAM_PROFILE_ADV_START(pProfileAdv, Prefix) do { } while (0)
#endif


/** @def STAM_REL_PROFILE_ADV_STOP
 * Samples the stop time of a profiling period (if running) and updates the
 * sample.
 *
 * @param   pProfileAdv Pointer to the STAMPROFILEADV structure to operate on.
 * @param   Prefix      Identifier prefix used to internal variables.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_PROFILE_ADV_STOP(pProfileAdv, Prefix) \
    do { \
        if ((pProfileAdv)->tsStart) \
        { \
            uint64_t Prefix##_cTicks; \
            STAM_GET_TS(Prefix##_cTicks); \
            Prefix##_cTicks -= (pProfileAdv)->tsStart; \
            (pProfileAdv)->tsStart = 0; \
            (pProfileAdv)->Core.cTicks += Prefix##_cTicks; \
            (pProfileAdv)->Core.cPeriods++; \
            if ((pProfileAdv)->Core.cTicksMax < Prefix##_cTicks) \
                (pProfileAdv)->Core.cTicksMax = Prefix##_cTicks; \
            if ((pProfileAdv)->Core.cTicksMin > Prefix##_cTicks) \
                (pProfileAdv)->Core.cTicksMin = Prefix##_cTicks; \
        } \
    } while (0)
#else
# define STAM_REL_PROFILE_ADV_STOP(pProfileAdv, Prefix) do { } while (0)
#endif
/** @def STAM_PROFILE_ADV_STOP
 * Samples the stop time of a profiling period (if running) and updates the
 * sample.
 *
 * @param   pProfileAdv Pointer to the STAMPROFILEADV structure to operate on.
 * @param   Prefix      Identifier prefix used to internal variables.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_PROFILE_ADV_STOP(pProfileAdv, Prefix) STAM_REL_PROFILE_ADV_STOP(pProfileAdv, Prefix)
#else
# define STAM_PROFILE_ADV_STOP(pProfileAdv, Prefix) do { } while (0)
#endif


/** @def STAM_REL_PROFILE_ADV_STOP_START
 * Stops one profile counter (if running) and starts another one.
 *
 * @param   pProfileAdv1    Pointer to the STAMPROFILEADV structure to stop.
 * @param   pProfileAdv2    Pointer to the STAMPROFILEADV structure to start.
 * @param   Prefix          Identifier prefix used to internal variables.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_PROFILE_ADV_STOP_START(pProfileAdv1, pProfileAdv2, Prefix) \
    do { \
        uint64_t Prefix##_cTicks; \
        STAM_GET_TS(Prefix##_cTicks); \
        (pProfileAdv2)->tsStart = Prefix##_cTicks; \
        if ((pProfileAdv1)->tsStart) \
        { \
            Prefix##_cTicks -= (pProfileAdv1)->tsStart; \
            (pProfileAdv1)->tsStart = 0; \
            (pProfileAdv1)->Core.cTicks += Prefix##_cTicks; \
            (pProfileAdv1)->Core.cPeriods++; \
            if ((pProfileAdv1)->Core.cTicksMax < Prefix##_cTicks) \
                (pProfileAdv1)->Core.cTicksMax = Prefix##_cTicks; \
            if ((pProfileAdv1)->Core.cTicksMin > Prefix##_cTicks) \
                (pProfileAdv1)->Core.cTicksMin = Prefix##_cTicks; \
        } \
    } while (0)
#else
# define STAM_REL_PROFILE_ADV_STOP_START(pProfileAdv1, pProfileAdv2, Prefix) \
    do { } while (0)
#endif
/** @def STAM_PROFILE_ADV_STOP_START
 * Samples the stop time of a profiling period (if running) and updates the
 * sample.
 *
 * @param   pProfileAdv1    Pointer to the STAMPROFILEADV structure to stop.
 * @param   pProfileAdv2    Pointer to the STAMPROFILEADV structure to start.
 * @param   Prefix          Identifier prefix used to internal variables.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_PROFILE_ADV_STOP_START(pProfileAdv1, pProfileAdv2, Prefix) \
    STAM_REL_PROFILE_ADV_STOP_START(pProfileAdv1, pProfileAdv2, Prefix)
#else
# define STAM_PROFILE_ADV_STOP_START(pProfileAdv1, pProfileAdv2, Prefix) \
    do { } while (0)
#endif


/** @def STAM_REL_PROFILE_ADV_SUSPEND
 * Suspends the sampling for a while. This can be useful to exclude parts
 * covered by other samples without screwing up the count, and average+min times.
 *
 * @param   pProfileAdv Pointer to the STAMPROFILEADV structure to operate on.
 * @param   Prefix      Identifier prefix used to internal variables. The prefix
 *                      must match that of the resume one since it stores the
 *                      suspend time in a stack variable.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_PROFILE_ADV_SUSPEND(pProfileAdv, Prefix) \
    uint64_t Prefix##_tsSuspend; \
    STAM_GET_TS(Prefix##_tsSuspend)
#else
# define STAM_REL_PROFILE_ADV_SUSPEND(pProfileAdv, Prefix) do { } while (0)
#endif
/** @def STAM_PROFILE_ADV_SUSPEND
 * Suspends the sampling for a while. This can be useful to exclude parts
 * covered by other samples without screwing up the count, and average+min times.
 *
 * @param   pProfileAdv Pointer to the STAMPROFILEADV structure to operate on.
 * @param   Prefix      Identifier prefix used to internal variables. The prefix
 *                      must match that of the resume one since it stores the
 *                      suspend time in a stack variable.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_PROFILE_ADV_SUSPEND(pProfileAdv, Prefix) STAM_REL_PROFILE_ADV_SUSPEND(pProfileAdv, Prefix)
#else
# define STAM_PROFILE_ADV_SUSPEND(pProfileAdv, Prefix) do { } while (0)
#endif


/** @def STAM_REL_PROFILE_ADV_RESUME
 * Counter to STAM_REL_PROFILE_ADV_SUSPEND.
 *
 * @param   pProfileAdv Pointer to the STAMPROFILEADV structure to operate on.
 * @param   Prefix      Identifier prefix used to internal variables. This must
 *                      match the one used with the SUSPEND!
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_PROFILE_ADV_RESUME(pProfileAdv, Prefix) \
    do { \
        uint64_t Prefix##_tsNow; \
        STAM_GET_TS(Prefix##_tsNow); \
        (pProfileAdv)->tsStart += Prefix##_tsNow - Prefix##_tsSuspend; \
    } while (0)
#else
# define STAM_REL_PROFILE_ADV_RESUME(pProfileAdv, Prefix) do { } while (0)
#endif
/** @def STAM_PROFILE_ADV_RESUME
 * Counter to STAM_PROFILE_ADV_SUSPEND.
 *
 * @param   pProfileAdv Pointer to the STAMPROFILEADV structure to operate on.
 * @param   Prefix      Identifier prefix used to internal variables. This must
 *                      match the one used with the SUSPEND!
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_PROFILE_ADV_RESUME(pProfileAdv, Prefix) STAM_REL_PROFILE_ADV_RESUME(pProfileAdv, Prefix)
#else
# define STAM_PROFILE_ADV_RESUME(pProfileAdv, Prefix) do { } while (0)
#endif


/** @def STAM_REL_PROFILE_ADV_STOP_EX
 * Samples the stop time of a profiling period (if running) and updates both
 * the sample and an attribution sample.
 *
 * @param   pProfileAdv Pointer to the STAMPROFILEADV structure to operate on.
 * @param   pProfile2   Pointer to the STAMPROFILE structure which this
 *                      interval should be attributed to as well. This may be NULL.
 * @param   Prefix      Identifier prefix used to internal variables.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_PROFILE_ADV_STOP_EX(pProfileAdv, pProfile2, Prefix) \
    do { \
        if ((pProfileAdv)->tsStart) \
        { \
            uint64_t Prefix##_cTicks; \
            STAM_GET_TS(Prefix##_cTicks); \
            Prefix##_cTicks -= (pProfileAdv)->tsStart; \
            (pProfileAdv)->tsStart = 0; \
            (pProfileAdv)->Core.cTicks += Prefix##_cTicks; \
            (pProfileAdv)->Core.cPeriods++; \
            if ((pProfileAdv)->Core.cTicksMax < Prefix##_cTicks) \
                (pProfileAdv)->Core.cTicksMax = Prefix##_cTicks; \
            if ((pProfileAdv)->Core.cTicksMin > Prefix##_cTicks) \
                (pProfileAdv)->Core.cTicksMin = Prefix##_cTicks; \
            if ((pProfile2)) \
            { \
                (pProfile2)->cTicks += Prefix##_cTicks; \
                (pProfile2)->cPeriods++; \
                if ((pProfile2)->cTicksMax < Prefix##_cTicks) \
                    (pProfile2)->cTicksMax = Prefix##_cTicks; \
                if ((pProfile2)->cTicksMin > Prefix##_cTicks) \
                    (pProfile2)->cTicksMin = Prefix##_cTicks; \
            } \
        } \
    } while (0)
#else
# define STAM_REL_PROFILE_ADV_STOP_EX(pProfileAdv, pProfile2, Prefix) do { } while (0)
#endif
/** @def STAM_PROFILE_ADV_STOP_EX
 * Samples the stop time of a profiling period (if running) and updates both
 * the sample and an attribution sample.
 *
 * @param   pProfileAdv Pointer to the STAMPROFILEADV structure to operate on.
 * @param   pProfile2   Pointer to the STAMPROFILE structure which this
 *                      interval should be attributed to as well. This may be NULL.
 * @param   Prefix      Identifier prefix used to internal variables.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_PROFILE_ADV_STOP_EX(pProfileAdv, pProfile2, Prefix) STAM_REL_PROFILE_ADV_STOP_EX(pProfileAdv, pProfile2, Prefix)
#else
# define STAM_PROFILE_ADV_STOP_EX(pProfileAdv, pProfile2, Prefix) do { } while (0)
#endif

/** @def STAM_REL_PROFILE_ADV_IS_RUNNING
 * Checks if it is running.
 *
 * @param   pProfileAdv Pointer to the STAMPROFILEADV structure to operate on.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_PROFILE_ADV_IS_RUNNING(pProfileAdv)   (pProfileAdv)->tsStart
#else
# define STAM_REL_PROFILE_ADV_IS_RUNNING(pProfileAdv)   (false)
#endif
/** @def STAM_PROFILE_ADV_IS_RUNNING
 * Checks if it is running.
 *
 * @param   pProfileAdv Pointer to the STAMPROFILEADV structure to operate on.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_PROFILE_ADV_IS_RUNNING(pProfileAdv) STAM_REL_PROFILE_ADV_IS_RUNNING(pProfileAdv)
#else
# define STAM_PROFILE_ADV_IS_RUNNING(pProfileAdv) (false)
#endif

/** @def STAM_REL_PROFILE_ADV_SET_STOPPED
 * Marks the profile counter as stopped.
 *
 * This is for avoiding screwups in twisty code.
 *
 * @param   pProfileAdv Pointer to the STAMPROFILEADV structure to operate on.
 */
#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
# define STAM_REL_PROFILE_ADV_SET_STOPPED(pProfileAdv)   do { (pProfileAdv)->tsStart = 0; } while (0)
#else
# define STAM_REL_PROFILE_ADV_SET_STOPPED(pProfileAdv)   do { } while (0)
#endif
/** @def STAM_PROFILE_ADV_SET_STOPPED
 * Marks the profile counter as stopped.
 *
 * This is for avoiding screwups in twisty code.
 *
 * @param   pProfileAdv Pointer to the STAMPROFILEADV structure to operate on.
 */
#ifdef VBOX_WITH_STATISTICS
# define STAM_PROFILE_ADV_SET_STOPPED(pProfileAdv)      STAM_REL_PROFILE_ADV_SET_STOPPED(pProfileAdv)
#else
# define STAM_PROFILE_ADV_SET_STOPPED(pProfileAdv)      do { } while (0)
#endif


/**
 * Ratio of A to B, uint32_t types.
 * @remark Use STAM_STATS or STAM_REL_STATS for modifying A & B values.
 */
typedef struct STAMRATIOU32
{
    /** Sample A. */
    uint32_t volatile   u32A;
    /** Sample B. */
    uint32_t volatile   u32B;
} STAMRATIOU32;
/** Pointer to a uint32_t ratio. */
typedef STAMRATIOU32 *PSTAMRATIOU32;
/** Pointer to const a uint32_t ratio. */
typedef const STAMRATIOU32 *PCSTAMRATIOU32;




/** @defgroup grp_stam_r3   The STAM Host Context Ring 3 API
 * @{
 */

VMMR3DECL(int)  STAMR3InitUVM(PUVM pUVM);
VMMR3DECL(void) STAMR3TermUVM(PUVM pUVM);
VMMR3DECL(int)  STAMR3RegisterU(PUVM pUVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
                                const char *pszName, STAMUNIT enmUnit, const char *pszDesc);
VMMR3DECL(int)  STAMR3Register(PVM pVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
                               const char *pszName, STAMUNIT enmUnit, const char *pszDesc);

/** @def STAM_REL_REG
 * Registers a statistics sample.
 *
 * @param   pVM         The cross context VM structure.
 * @param   pvSample    Pointer to the sample.
 * @param   enmType     Sample type. This indicates what pvSample is pointing at.
 * @param   pszName     Sample name. The name is on this form "/<component>/<sample>".
 *                      Further nesting is possible.
 * @param   enmUnit     Sample unit.
 * @param   pszDesc     Sample description.
 */
#define STAM_REL_REG(pVM, pvSample, enmType, pszName, enmUnit, pszDesc) \
    STAM_REL_STATS({ int rcStam = STAMR3Register(pVM, pvSample, enmType, STAMVISIBILITY_ALWAYS, pszName, enmUnit, pszDesc); \
                     AssertRC(rcStam); })
/** @def STAM_REG
 * Registers a statistics sample if statistics are enabled.
 *
 * @param   pVM         The cross context VM structure.
 * @param   pvSample    Pointer to the sample.
 * @param   enmType     Sample type. This indicates what pvSample is pointing at.
 * @param   pszName     Sample name. The name is on this form "/<component>/<sample>".
 *                      Further nesting is possible.
 * @param   enmUnit     Sample unit.
 * @param   pszDesc     Sample description.
 */
#define STAM_REG(pVM, pvSample, enmType, pszName, enmUnit, pszDesc) \
    STAM_STATS({STAM_REL_REG(pVM, pvSample, enmType, pszName, enmUnit, pszDesc);})

/** @def STAM_REL_REG_USED
 * Registers a statistics sample which only shows when used.
 *
 * @param   pVM         The cross context VM structure.
 * @param   pvSample    Pointer to the sample.
 * @param   enmType     Sample type. This indicates what pvSample is pointing at.
 * @param   pszName     Sample name. The name is on this form "/<component>/<sample>".
 *                      Further nesting is possible.
 * @param   enmUnit     Sample unit.
 * @param   pszDesc     Sample description.
 */
#define STAM_REL_REG_USED(pVM, pvSample, enmType, pszName, enmUnit, pszDesc) \
    STAM_REL_STATS({ int rcStam = STAMR3Register(pVM, pvSample, enmType, STAMVISIBILITY_USED, pszName, enmUnit, pszDesc); \
                     AssertRC(rcStam);})
/** @def STAM_REG_USED
 * Registers a statistics sample which only shows when used, if statistics are enabled.
 *
 * @param   pVM         The cross context VM structure.
 * @param   pvSample    Pointer to the sample.
 * @param   enmType     Sample type. This indicates what pvSample is pointing at.
 * @param   pszName     Sample name. The name is on this form "/<component>/<sample>".
 *                      Further nesting is possible.
 * @param   enmUnit     Sample unit.
 * @param   pszDesc     Sample description.
 */
#define STAM_REG_USED(pVM, pvSample, enmType, pszName, enmUnit, pszDesc) \
    STAM_STATS({ STAM_REL_REG_USED(pVM, pvSample, enmType, pszName, enmUnit, pszDesc); })

VMMR3DECL(int)  STAMR3RegisterFU(PUVM pUVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit,
                                 const char *pszDesc, const char *pszName, ...) RT_IPRT_FORMAT_ATTR(7, 8);
VMMR3DECL(int)  STAMR3RegisterF(PVM pVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit,
                                const char *pszDesc, const char *pszName, ...) RT_IPRT_FORMAT_ATTR(7, 8);
VMMR3DECL(int)  STAMR3RegisterVU(PUVM pUVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit,
                                 const char *pszDesc, const char *pszName, va_list args) RT_IPRT_FORMAT_ATTR(7, 0);
VMMR3DECL(int)  STAMR3RegisterV(PVM pVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit,
                                const char *pszDesc, const char *pszName, va_list args) RT_IPRT_FORMAT_ATTR(7, 0);

/**
 * Resets the sample.
 * @param   pVM         The cross context VM structure.
 * @param   pvSample    The sample registered using STAMR3RegisterCallback.
 */
typedef DECLCALLBACKTYPE(void, FNSTAMR3CALLBACKRESET,(PVM pVM, void *pvSample));
/** Pointer to a STAM sample reset callback. */
typedef FNSTAMR3CALLBACKRESET *PFNSTAMR3CALLBACKRESET;

/**
 * Prints the sample into the buffer.
 *
 * @param   pVM         The cross context VM structure.
 * @param   pvSample    The sample registered using STAMR3RegisterCallback.
 * @param   pszBuf      The buffer to print into.
 * @param   cchBuf      The size of the buffer.
 */
typedef DECLCALLBACKTYPE(void, FNSTAMR3CALLBACKPRINT,(PVM pVM, void *pvSample, char *pszBuf, size_t cchBuf));
/** Pointer to a STAM sample print callback. */
typedef FNSTAMR3CALLBACKPRINT *PFNSTAMR3CALLBACKPRINT;

VMMR3DECL(int)  STAMR3RegisterCallback(PVM pVM, void *pvSample, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit,
                                       PFNSTAMR3CALLBACKRESET pfnReset, PFNSTAMR3CALLBACKPRINT pfnPrint,
                                       const char *pszDesc, const char *pszName, ...) RT_IPRT_FORMAT_ATTR(8, 9);
VMMR3DECL(int)  STAMR3RegisterCallbackV(PVM pVM, void *pvSample, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit,
                                        PFNSTAMR3CALLBACKRESET pfnReset, PFNSTAMR3CALLBACKPRINT pfnPrint,
                                        const char *pszDesc, const char *pszName, va_list args) RT_IPRT_FORMAT_ATTR(8, 0);

VMMR3DECL(int)  STAMR3RegisterRefresh(PUVM pUVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
                                      STAMUNIT enmUnit, uint8_t iRefreshGrp, const char *pszDesc,
                                      const char *pszName, ...) RT_IPRT_FORMAT_ATTR(8, 9);
VMMR3DECL(int)  STAMR3RegisterRefreshV(PUVM pUVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
                                       STAMUNIT enmUnit, uint8_t iRefreshGrp, const char *pszDesc,
                                       const char *pszName, va_list va) RT_IPRT_FORMAT_ATTR(8, 0);

VMMR3DECL(int)  STAMR3RegisterSum(PUVM pUVM, STAMVISIBILITY enmVisibility, const char *pszSummandPattern,
                                  const char *pszDesc, const char *pszName, ...) RT_IPRT_FORMAT_ATTR(5, 6);
VMMR3DECL(int)  STAMR3RegisterSumV(PUVM pUVM, STAMVISIBILITY enmVisibility, const char *pszSummandPattern,
                                   const char *pszDesc, const char *pszName, va_list va) RT_IPRT_FORMAT_ATTR(5, 0);
VMMR3DECL(int)  STAMR3RegisterPctOfSum(PUVM pUVM, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, const char *pszValue,
                                       bool fAddValueToSum, const char *pszSummandPattern, const char *pszDesc,
                                       const char *pszName, ...);
VMMR3DECL(int)  STAMR3RegisterPctOfSumV(PUVM pUVM, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, const char *pszValue,
                                        bool fAddValueToSum, const char *pszSummandPattern, const char *pszDesc,
                                        const char *pszName, va_list va);

VMMR3DECL(int)  STAMR3Deregister(PUVM pUVM, const char *pszPat);
VMMR3DECL(int)  STAMR3DeregisterF(PUVM pUVM, const char *pszPatFmt, ...) RT_IPRT_FORMAT_ATTR(2, 3);
VMMR3DECL(int)  STAMR3DeregisterV(PUVM pUVM, const char *pszPatFmt, va_list va) RT_IPRT_FORMAT_ATTR(2, 0);
VMMR3DECL(int)  STAMR3DeregisterByPrefix(PUVM pUVM, const char *pszPrefix);
VMMR3DECL(int)  STAMR3DeregisterByAddr(PUVM pUVM, void *pvSample);

VMMR3DECL(int)  STAMR3Reset(PUVM pUVM, const char *pszPat);
VMMR3DECL(int)  STAMR3Snapshot(PUVM pUVM, const char *pszPat, char **ppszSnapshot, size_t *pcchSnapshot, bool fWithDesc);
VMMR3DECL(int)  STAMR3SnapshotFree(PUVM pUVM, char *pszSnapshot);
VMMR3DECL(int)  STAMR3Dump(PUVM pUVM, const char *pszPat);
VMMR3DECL(int)  STAMR3DumpToReleaseLog(PUVM pUVM, const char *pszPat);
VMMR3DECL(int)  STAMR3Print(PUVM pUVM, const char *pszPat);

/**
 * Callback function for STAMR3Enum().
 *
 * @returns non-zero to halt the enumeration.
 *
 * @param   pszName         The name of the sample.
 * @param   enmType         The type.
 * @param   pvSample        Pointer to the data. enmType indicates the format of this data.
 * @param   enmUnit         The unit.
 * @param   pszUnit         The unit as string.  This is a permanent string,
 *                          same as returned by STAMR3GetUnit().
 * @param   enmVisibility   The visibility.
 * @param   pszDesc         The description.
 * @param   pvUser          The pvUser argument given to STAMR3Enum().
 */
typedef DECLCALLBACKTYPE(int, FNSTAMR3ENUM,(const char *pszName, STAMTYPE enmType, void *pvSample, STAMUNIT enmUnit,
                                            const char *pszUnit, STAMVISIBILITY enmVisibility, const char *pszDesc, void *pvUser));
/** Pointer to a FNSTAMR3ENUM(). */
typedef FNSTAMR3ENUM *PFNSTAMR3ENUM;

VMMR3DECL(int)  STAMR3Enum(PUVM pUVM, const char *pszPat, PFNSTAMR3ENUM pfnEnum, void *pvUser);
VMMR3DECL(const char *) STAMR3GetUnit(STAMUNIT enmUnit);
VMMR3DECL(const char *) STAMR3GetUnit1(STAMUNIT enmUnit);
VMMR3DECL(const char *) STAMR3GetUnit2(STAMUNIT enmUnit);

/** @} */

/** @} */

RT_C_DECLS_END

#endif /* !VBOX_INCLUDED_vmm_stam_h */

