// MIT License
//
// Copyright (c) 2023-2025 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#pragma once

#include <rocprofiler-sdk/agent.h>
#include <rocprofiler-sdk/defines.h>
#include <rocprofiler-sdk/fwd.h>

ROCPROFILER_EXTERN_C_INIT

/**
 * @defgroup PC_SAMPLING_SERVICE PC Sampling
 * @brief Enabling PC (Program Counter) Sampling for GPU Activity
 * @{
 */

/**
 * @brief (experimental) Function used to configure the PC sampling service on the GPU agent with @p
 * agent_id.
 *
 * Prerequisites are the following:
 * - The client must create a context and supply its @p context_id. By using this context,
 *   the client can start/stop PC sampling on the agent. For more information,
 *   please @see rocprofiler_start_context/rocprofiler_stop_context.
 * - The user must create a buffer and supply its @p buffer_id. Rocprofiler-SDK uses the buffer
 *   to deliver the PC samples to the client. For more information about the data delivery,
 *   please @see rocprofiler_create_buffer and @see rocprofiler_buffer_tracing_cb_t.
 *
 * Before calling this function, we recommend querying PC sampling configurations
 * supported by the GPU agent via the @see rocprofiler_query_pc_sampling_agent_configurations.
 * The client chooses the @p method, @p unit, and @p interval to match one of the
 * available configurations. Note that the @p interval must belong to the range of values
 * [available_config.min_interval, available_config.max_interval],
 * where available_config is the instance of the @see rocprofiler_pc_sampling_configuration_s
 * supported/available at the moment.
 *
 * Rocprofiler-SDK checks whether the requsted configuration is actually supported
 * at the moment of calling this function. If the answer is yes, it returns
 * the @see ROCPROFILER_STATUS_SUCCESS. Otherwise, it notifies the client about the
 * rejection reason via the returned status code. For more information
 * about the status codes, please @see rocprofiler_status_t.
 *
 * There are a few constraints a client's code needs to be aware of.
 *
 * Constraint1: A GPU agent can be configured to support at most one running PC sampling
 * configuration at any time, which implies some of the consequences described below.
 * After the tool configures the PC sampling with one of the available configurations,
 * rocprofiler-SDK guarantees that this configuration will be valid for the tool's
 * lifetime. The tool can start and stop the configured PC sampling service whenever convenient.
 *
 * Constraint2: Since the same GPU agent can be used by multiple processes concurrently,
 * Rocprofiler-SDK cannot guarantee the exclusive access to the PC sampling capability.
 * The consequence is the following scenario. The tool TA that belongs to the process PA,
 * calls the @see rocprofiler_query_pc_sampling_agent_configurations that returns the
 * two supported configurations CA and CB by the agent. Then the tool TB of the process PB,
 * configures the PC sampling on the same agent by using the configuration CB.
 * Subsequently, the TA tries configuring the CA on the agent, and it fails.
 * To point out that this case happened, we introduce a special status code
 * @see ROCPROFILER_STATUS_ERROR_NOT_AVAILABLE.
 * When this status code is observed by the tool TA, it queries all available configurations again
 * by calling @see rocprofiler_query_pc_sampling_agent_configurations,
 * that returns only CB this time. The tool TA can choose CB, so that both
 * TA and TB use the PC sampling capability in the separate processes.
 * Both TA and TB receives samples generated by the kernels launched by the
 * corresponding processes PA and PB, respectively.
 *
 * Constraint3: Rocprofiler-SDK allows multiple contexts to configure PC sampling service
 * within the process, but at most one context can configure PC sampling for any given GPU
 * agent. This enables multiple tools to use PC sampling concurrently, as long as each tool
 * targets different GPU agents. Each context can contain multiple PC sampling services
 * configured for different GPU agents.
 *
 * Constraint4: PC sampling feature is not available within the ROCgdb.
 *
 * Constraint5: PC sampling service cannot be used simultaneously with
 * counter collection service.
 *
 * @param [in] context_id - id of the context used for starting/stopping PC sampling service
 * @param [in] agent_id   - id of the agent on which caller tries using PC sampling capability
 * @param [in] method     - the type of PC sampling the caller tries to use on the agent.
 * @param [in] unit       - The unit appropriate to the PC sampling type/method.
 * @param [in] interval   - frequency at which PC samples are generated
 * @param [in] buffer_id  - id of the buffer used for delivering PC samples
 * @param [in] flags      - for future use
 * @return ::rocprofiler_status_t
 * @retval ::ROCPROFILER_STATUS_SUCCESS PC sampling service configured successfully
 * @retval ::ROCPROFILER_STATUS_ERROR_NOT_AVAILABLE One of the scenarios is present:
 * 1. PC sampling is already configured with configuration different than requested,
 * 2. PC sampling is requested from a process that runs within the ROCgdb.
 * 3. HSA runtime does not support PC sampling.
 * 4. GPU device does not support requested PC sampling method.
 * @retval ::ROCPROFILER_STATUS_ERROR_INCOMPATIBLE_KERNEL the amdgpu driver installed on the system
 * does not support the PC sampling feature
 * @retval ::ROCPROFILER_STATUS_ERROR a general error caused by the amdgpu driver
 * @retval ::ROCPROFILER_STATUS_ERROR_CONTEXT_CONFLICT counter collection service already
 * setup in the context
 * @retval ::ROCPROFILER_STATUS_ERROR_SERVICE_ALREADY_CONFIGURED PC sampling for this agent is
 * already configured by a different context
 * @retval ::ROCPROFILER_STATUS_ERROR_INVALID_ARGUMENT function invoked with an invalid argument
 */
ROCPROFILER_SDK_EXPERIMENTAL
rocprofiler_status_t
rocprofiler_configure_pc_sampling_service(rocprofiler_context_id_t         context_id,
                                          rocprofiler_agent_id_t           agent_id,
                                          rocprofiler_pc_sampling_method_t method,
                                          rocprofiler_pc_sampling_unit_t   unit,
                                          uint64_t                         interval,
                                          rocprofiler_buffer_id_t          buffer_id,
                                          int                              flags) ROCPROFILER_API;

/**
 * @brief (experimental) Enumeration describing values of flags of
 * ::rocprofiler_pc_sampling_configuration_t.
 */
typedef enum ROCPROFILER_SDK_EXPERIMENTAL rocprofiler_pc_sampling_configuration_flags_t
{
    ROCPROFILER_PC_SAMPLING_CONFIGURATION_FLAGS_NONE = 0,
    ROCPROFILER_PC_SAMPLING_CONFIGURATION_FLAGS_INTERVAL_POW2,
    ROCPROFILER_PC_SAMPLING_CONFIGURATION_FLAGS_LAST

    /// @var ROCPROFILER_PC_SAMPLING_CONFIGURATION_FLAGS_INTERVAL_POW2
    /// @brief The interval value must be a power of 2.
} rocprofiler_pc_sampling_configuration_flags_t;

/**
 * @brief (experimental) PC sampling configuration supported by a GPU agent.
 */
typedef struct ROCPROFILER_SDK_EXPERIMENTAL rocprofiler_pc_sampling_configuration_t
{
    uint64_t                         size;  ///< Size of this struct
    rocprofiler_pc_sampling_method_t method;
    rocprofiler_pc_sampling_unit_t   unit;
    size_t                           min_interval;
    size_t                           max_interval;
    uint64_t flags;  ///< take values from ::rocprofiler_pc_sampling_configuration_flags_t

    /// @var method
    /// @brief Sampling method supported by the GPU agent.
    /// Currently, it can take one of the following two values:
    /// - ::ROCPROFILER_PC_SAMPLING_METHOD_HOST_TRAP: a background host kernel thread
    /// periodically interrupts waves execution on the GPU to generate PC samples
    /// - ::ROCPROFILER_PC_SAMPLING_METHOD_STOCHASTIC: performance monitoring hardware
    /// on the GPU periodically interrupts waves to generate PC samples.
    /// @var unit
    /// @brief A unit used to specify the interval of the @ref method for samples generation.
    /// @var min_interval
    /// @brief the highest possible frequencey for generating samples using @ref method.
    /// @var max_interval
    /// @brief the lowest possible frequency for generating samples using @ref method

} rocprofiler_pc_sampling_configuration_t;

/**
 * @brief (experimental) Rocprofiler SDK's callback function to deliver the list of available PC
 * sampling configurations upon the call to the
 * ::rocprofiler_query_pc_sampling_agent_configurations.
 *
 * @param[out] configs - The array of PC sampling configurations supported by the agent
 * at the moment of invoking ::rocprofiler_query_pc_sampling_agent_configurations.
 * @param[out] num_config - The number of configurations contained in the underlying array
 * @p configs.
 * In case the GPU agent does not support PC sampling, the value is 0.
 * @param[in] user_data - client's private data passed via
 * ::rocprofiler_query_pc_sampling_agent_configurations
 * @return ::rocprofiler_status_t
 */
ROCPROFILER_SDK_EXPERIMENTAL
typedef rocprofiler_status_t (*rocprofiler_available_pc_sampling_configurations_cb_t)(
    const rocprofiler_pc_sampling_configuration_t* configs,
    size_t                                         num_config,
    void*                                          user_data);

/**
 * @brief (experimental) Query PC Sampling Configuration.
 *
 * Lists PC sampling configurations a GPU agent with @p agent_id supports at the moment
 * of invoking the function. Delivers configurations via @p cb.
 * In case the PC sampling is configured on the GPU agent, the @p cb delivers information
 * about the active PC sampling configuration.
 * In case the GPU agent does not support PC sampling capability,
 * the @p cb delivers none PC sampling configurations.
 *
 * @param [in] agent_id  - id of the agent for which available configurations will be listed
 * @param [in] cb        - User callback that delivers the available PC sampling configurations
 * @param [in] user_data - passed to the @p cb
 * @return ::rocprofiler_status_t
 * @retval ::ROCPROFILER_STATUS_ERROR_NOT_AVAILABLE One of the scenarios is present:
 * 1. PC sampling is requested from a process that runs within the ROCgdb.
 * 2. HSA runtime does not support PC sampling.
 * @retval ::ROCPROFILER_STATUS_ERROR_INCOMPATIBLE_KERNEL the amdgpu driver installed on the system
 * does not support the PC sampling feature.
 * @retval ::ROCPROFILER_STATUS_ERROR a general error caused by the amdgpu driver
 * @retval ::ROCPROFILER_STATUS_SUCCESS @p cb successfully finished
 */
ROCPROFILER_SDK_EXPERIMENTAL
rocprofiler_status_t
rocprofiler_query_pc_sampling_agent_configurations(
    rocprofiler_agent_id_t                                agent_id,
    rocprofiler_available_pc_sampling_configurations_cb_t cb,
    void* user_data) ROCPROFILER_API ROCPROFILER_NONNULL(2, 3);

/**
 * @brief (experimental) Information about the GPU part where wave was executing
 * at the moment of sampling.
 */
typedef struct ROCPROFILER_SDK_EXPERIMENTAL rocprofiler_pc_sampling_hw_id_v0_t
{
    uint64_t chiplet          : 6;  ///< chiplet index (3 bits allocated by the ROCr runtime)
    uint64_t wave_id          : 7;  ///< wave slot index
    uint64_t simd_id          : 2;  ///< SIMD index
    uint64_t pipe_id          : 4;  ///< pipe index
    uint64_t cu_or_wgp_id     : 4;
    uint64_t shader_array_id  : 1;   ///< Shared array index
    uint64_t shader_engine_id : 5;   ///< shared engine index
    uint64_t workgroup_id     : 7;   ///< thread_group index on GFX9, and workgroup index on GFX10+
    uint64_t vm_id            : 6;   ///< virtual memory ID
    uint64_t queue_id         : 4;   ///< queue id
    uint64_t microengine_id   : 2;   ///< ACE (microengine) index
    uint64_t reserved0        : 16;  ///< Reserved for the future use

    /// @var cu_or_wgp_id
    /// @brief Compute unit index on GFX9 or workgroup processor index on GFX10+.
} rocprofiler_pc_sampling_hw_id_v0_t;

/**
 * @brief (experimental) Sampled program counter.
 */
typedef struct ROCPROFILER_SDK_EXPERIMENTAL rocprofiler_pc_t
{
    uint64_t code_object_id;
    uint64_t code_object_offset;

    /// @var code_object_id
    /// @brief id of the loaded code object instance that contains sampled PC.
    /// This fields holds the value ::ROCPROFILER_CODE_OBJECT_ID_NONE
    /// if the code object cannot be determined
    /// (e.g., sampled PC belongs to code generated by self modifying code).
    /// @var code_object_offset
    /// @brief If @ref code_object_id is different than ::ROCPROFILER_CODE_OBJECT_ID_NONE,
    /// then this field contains the offset of the sampled PC relative to the
    /// ::rocprofiler_callback_tracing_code_object_load_data_t.load_base
    /// of the code object instance with @ref code_object_id.
    /// To calculate the original virtual address of the sampled PC, one can add the value
    /// of this field to the ::rocprofiler_callback_tracing_code_object_load_data_t.load_base.
    /// The value of @ref code_object_offset matches
    /// the virtual address of the sampled instruction (PC), only if the
    /// @ref code_object_id is equal to the ::ROCPROFILER_CODE_OBJECT_ID_NONE.
} rocprofiler_pc_t;

/**
 * @brief (experimental) ROCProfiler Host-Trap PC Sampling Record.
 */
typedef struct ROCPROFILER_SDK_EXPERIMENTAL rocprofiler_pc_sampling_record_host_trap_v0_t
{
    uint64_t                           size;         ///< Size of this struct
    rocprofiler_pc_sampling_hw_id_v0_t hw_id;        ///< @see ::rocprofiler_pc_sampling_hw_id_v0_t
    rocprofiler_pc_t                   pc;           ///< information about sampled program counter
    uint64_t                           exec_mask;    ///< active SIMD lanes when sampled
    uint64_t                           timestamp;    ///< timestamp when sample is generated
    uint64_t                           dispatch_id;  ///< originating kernel dispatch ID
    rocprofiler_async_correlation_id_t correlation_id;
    rocprofiler_dim3_t                 workgroup_id;  ///< wave coordinates within the workgroup
    uint32_t wave_in_group : 8;                       ///< wave position within the workgroup (0-31)
    uint32_t reserved0     : 24;                      ///< wave position within the workgroup (0-31)

    /// @var correlation_id
    /// @brief API launch call id that matches dispatch ID
} rocprofiler_pc_sampling_record_host_trap_v0_t;

/**
 * @brief (experimental) The header of the ::rocprofiler_pc_sampling_record_stochastic_v0_t,
 * indicating what fields of the ::rocprofiler_pc_sampling_record_stochastic_v0_t instance are
 * meaningful for the sample.
 */
typedef struct ROCPROFILER_SDK_EXPERIMENTAL rocprofiler_pc_sampling_record_stochastic_header_t
{
    uint8_t has_memory_counter : 1;  ///< pc sample provides memory counters information
                                     ///< via ::rocprofiler_pc_sampling_memory_counters_t
    uint8_t reserved_type : 7;
} rocprofiler_pc_sampling_record_stochastic_header_t;

/**
 * @brief (experimental) Enumeration describing type of sampled issued instruction.
 */
typedef enum ROCPROFILER_SDK_EXPERIMENTAL rocprofiler_pc_sampling_instruction_type_t
{
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_NONE = 0,
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_VALU,        ///< vector ALU instruction
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_MATRIX,      ///< matrix instruction
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_SCALAR,      ///< scalar (memory) instruction
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_TEX,         ///< texture memory instruction
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_LDS,         ///< LDS memory instruction
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_LDS_DIRECT,  ///< LDS direct memory instruction
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_FLAT,        ///< flat memory instruction
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_EXPORT,      ///< export instruction
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_MESSAGE,     ///< message instruction
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_BARRIER,     ///< barrier instruction
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_BRANCH_NOT_TAKEN,
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_BRANCH_TAKEN,
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_JUMP,       ///< jump instruction
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_OTHER,      ///< other types of instruction
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_NO_INST,    ///< no instruction issued
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_DUAL_VALU,  /// dual VALU instruction
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_LAST

    /// @var ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_BRANCH_NOT_TAKEN
    /// @brief Instruction representing a branch not being taken.
    /// @var ROCPROFILER_PC_SAMPLING_INSTRUCTION_TYPE_BRANCH_TAKEN
    /// @brief Instruction representing a taken branch.
} rocprofiler_pc_sampling_instruction_type_t;

/**
 * @brief (experimental) Enumeration describing reason for not issuing an instruction.
 */
typedef enum ROCPROFILER_SDK_EXPERIMENTAL rocprofiler_pc_sampling_instruction_not_issued_reason_t
{
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NONE = 0,
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE,
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ALU_DEPENDENCY,
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_WAITCNT,  ///< waitcnt dependency
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_INTERNAL_INSTRUCTION,
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_BARRIER_WAIT,  ///< waiting on a barrier
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_NOT_WIN,
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_WIN_EX_STALL,
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_OTHER_WAIT,
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_SLEEP_WAIT,  ///< wave was sleeping
    ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_LAST

    /// @var ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_NO_INSTRUCTION_AVAILABLE
    /// @brief No instruction available in the instruction cache.
    /// @var ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ALU_DEPENDENCY
    /// @brief ALU dependency not resolved.
    /// @var ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_INTERNAL_INSTRUCTION
    /// @brief Wave executes an internal instruction.
    /// @var ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_NOT_WIN
    /// @brief The instruction did not win the arbiter.
    /// @var ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_ARBITER_WIN_EX_STALL
    /// @brief Arbiter issued an instruction, but the execution pipe pushed it back from execution.
    /// @var ROCPROFILER_PC_SAMPLING_INSTRUCTION_NOT_ISSUED_REASON_OTHER_WAIT
    /// @brief Other types of wait (e.g., wait for XNACK acknowledgment).
} rocprofiler_pc_sampling_instruction_not_issued_reason_t;

/**
 * @brief (experimental) Data provided by stochastic sampling hardware.
 *
 */
typedef struct ROCPROFILER_SDK_EXPERIMENTAL rocprofiler_pc_sampling_snapshot_v0_t
{
    uint32_t reason_not_issued          : 4;
    uint32_t reserved0                  : 1;  ///< reserved for future use
    uint32_t arb_state_issue_valu       : 1;  ///< arbiter issued a VALU instruction
    uint32_t arb_state_issue_matrix     : 1;  ///< arbiter issued a matrix instruction
    uint32_t arb_state_issue_lds        : 1;  ///< arbiter issued a LDS instruction
    uint32_t arb_state_issue_lds_direct : 1;  ///< arbiter issued a LDS direct instruction
    uint32_t arb_state_issue_scalar     : 1;  ///< arbiter issued a scalar (SALU/SMEM) instruction
    uint32_t arb_state_issue_vmem_tex   : 1;  ///< arbiter issued a texture instruction
    uint32_t arb_state_issue_flat       : 1;  ///< arbiter issued a FLAT instruction
    uint32_t arb_state_issue_exp        : 1;  ///< arbiter issued a export instruction
    uint32_t arb_state_issue_misc       : 1;  ///< arbiter issued a miscellaneous instruction
    uint32_t arb_state_issue_brmsg      : 1;  ///< arbiter issued a branch/message instruction
    uint32_t arb_state_issue_reserved   : 1;  ///< reserved for the future use
    uint32_t arb_state_stall_valu       : 1;
    uint32_t arb_state_stall_matrix     : 1;  ///< matrix instruction was stalled
    uint32_t arb_state_stall_lds        : 1;  ///< LDS instruction was stalled
    uint32_t arb_state_stall_lds_direct : 1;  ///< LDS direct instruction was stalled
    uint32_t arb_state_stall_scalar     : 1;  ///< Scalar (SALU/SMEM) instruction was stalled
    uint32_t arb_state_stall_vmem_tex   : 1;  ///< texture instruction was stalled
    uint32_t arb_state_stall_flat       : 1;  ///< flat instruction was stalled
    uint32_t arb_state_stall_exp        : 1;  ///< export instruction was stalled
    uint32_t arb_state_stall_misc       : 1;  ///< miscellaneous instruction was stalled
    uint32_t arb_state_stall_brmsg      : 1;  ///< branch/message instruction was stalled
    uint32_t arb_state_state_reserved   : 1;  ///< reserved for the future use
    // We have two reserved bits
    uint32_t dual_issue_valu     : 1;
    uint32_t sampling_lock_error : 1;
    uint32_t reserved2           : 3;  ///< reserved for the future use

    /// @var reason_not_issued
    /// @brief The reason for not issuing an instruction. The field takes one of the value defined
    /// in ::rocprofiler_pc_sampling_instruction_not_issued_reason_t
    /// @var arb_state_stall_valu
    /// @brief VALU instruction was stalled when a sample was generated
    /// @var dual_issue_valu
    /// @brief Two VALU instructions were issued for coexecution (MI3xx specific)
    /// @var sampling_lock_error
    /// @brief At least one wave was locked out from taking a sample,
    /// due to the latency instroduced by current sample read.
    /// Too many samples with this bit on indicates that the sampling frequency is too high
} rocprofiler_pc_sampling_snapshot_v0_t;

/**
 * @brief (experimental) Counters of issued but not yet completed instructions.
 */
typedef struct ROCPROFILER_SDK_EXPERIMENTAL rocprofiler_pc_sampling_memory_counters_t
{
    uint64_t load_cnt   : 6;
    uint64_t store_cnt  : 6;
    uint64_t bvh_cnt    : 3;
    uint64_t sample_cnt : 6;
    uint64_t ds_cnt     : 6;
    uint64_t km_cnt     : 5;
    // The following counters are relevant for gfx1250 only.
    uint64_t async_cnt  : 6;
    uint64_t tensor_cnt : 6;
    uint64_t xnack_cnt  : 6;
    uint64_t reserved   : 14;  ///< reserved for the future use

    /// @var load_cnt
    /// @brief Counts the number of VMEM load instructions issued but not yet completed.
    /// @var store_cnt
    /// @brief Counts the number of VMEM store instructions issued but not yet completed.
    /// @var bvh_cnt
    /// @brief Counts the number of VMEM BVH instructions issued but not yet completed.
    /// @var sample_cnt
    /// @brief Counts the number of VMEM sample instructions issued but not yet completed.
    /// @var ds_cnt
    /// @brief Counts the number of LDS instructions issued but not yet completed.
    /// @var km_cnt
    /// @brief Counts the number of scalar memory reads and memory instructions issued but not yet
    /// completed.
    /// @var async_cnt
    /// @brief Counts the number of async instructions issued but not yet completed.
    /// @var tensor_cnt
    /// @brief Counts the number of tensor instructions issued but not yet completed.
    /// @var xnack_cnt
    /// @brief Counts the number of oustanding memory instruction not yet reported
    /// XNACK ackwlodgement.
} rocprofiler_pc_sampling_memory_counters_t;

/**
 * @brief (experimental) ROCProfiler Stochastic PC Sampling Record.
 */
typedef struct ROCPROFILER_SDK_EXPERIMENTAL rocprofiler_pc_sampling_record_stochastic_v0_t
{
    uint64_t                                           size;  ///< Size of this struct
    rocprofiler_pc_sampling_record_stochastic_header_t flags;
    uint8_t                                            wave_in_group;
    uint8_t                                            wave_issued : 1;
    uint8_t                                            inst_type   : 5;
    uint8_t                                            reserved    : 2;
    rocprofiler_pc_sampling_hw_id_v0_t                 hw_id;
    rocprofiler_pc_t                                   pc;
    uint64_t                                           exec_mask;
    rocprofiler_dim3_t                                 workgroup_id;
    uint32_t                                           wave_count;
    uint64_t                                           timestamp;
    uint64_t                                           dispatch_id;
    rocprofiler_async_correlation_id_t                 correlation_id;
    rocprofiler_pc_sampling_snapshot_v0_t              snapshot;
    rocprofiler_pc_sampling_memory_counters_t          memory_counters;

    /// @var flags
    /// @brief Defines what fields are meaningful for the sample.
    /// @var wave_in_group
    /// @brief wave position within the workgroup (0-15)
    /// @var wave_issued
    /// @brief wave issued the instruction represented with the PC
    /// @var inst_type
    /// @brief instruction type, takes a value defined in @ref
    /// ::rocprofiler_pc_sampling_instruction_type_t
    /// @var reserved
    /// @brief reserved 2 bits must be zero
    /// @var hw_id
    /// @brief @see ::rocprofiler_pc_sampling_hw_id_v0_t
    /// @var pc
    /// @brief information about sampled program counter
    /// @var exec_mask
    /// @brief active SIMD lanes at the moment of sampling
    /// @var workgroup_id
    /// @brief wave coordinates within the workgroup
    /// @var wave_count
    /// @brief active waves on the CU at the moment of sampling
    /// @var timestamp
    /// @brief timestamp when sample is generated
    /// @var dispatch_id
    /// @brief originating kernel dispatch ID
    /// @var correlation_id
    /// @brief API launch call id that matches dispatch ID
    /// @var snapshot
    /// @brief Data provided by stochastic sampling hardware. @see
    /// ::rocprofiler_pc_sampling_snapshot_v0_t
    /// @var memory_counters
    /// @brief Counters of issued but not yet completed instructions. @see
    /// ::rocprofiler_pc_sampling_memory_counters_t
} rocprofiler_pc_sampling_record_stochastic_v0_t;

/**
 * @brief (experimental) Record representing an invalid PC Sampling Record.
 */
typedef struct ROCPROFILER_SDK_EXPERIMENTAL rocprofiler_pc_sampling_record_invalid_t
{
    uint64_t size;  ///< Size of the struct
} rocprofiler_pc_sampling_record_invalid_t;

/**
 * @brief (experimental) Return the string encoding of ::rocprofiler_pc_sampling_instruction_type_t
 * value
 * @param [in] instruction_type instruction type enum value
 * @return Will return a nullptr if invalid/unsupported ::rocprofiler_pc_sampling_instruction_type_t
 * value is provided.
 */
ROCPROFILER_SDK_EXPERIMENTAL
const char*
rocprofiler_get_pc_sampling_instruction_type_name(
    rocprofiler_pc_sampling_instruction_type_t instruction_type) ROCPROFILER_API;

/**
 * @brief (experimental) Return the string encoding of
 * ::rocprofiler_pc_sampling_instruction_not_issued_reason_t value
 * @param [in] not_issued_reason no issue reason enum value
 * @return Will return a nullptr if invalid/unsupported
 * ::rocprofiler_pc_sampling_instruction_not_issued_reason_t value is provided.
 */
ROCPROFILER_SDK_EXPERIMENTAL const char*
rocprofiler_get_pc_sampling_instruction_not_issued_reason_name(
    rocprofiler_pc_sampling_instruction_not_issued_reason_t not_issued_reason) ROCPROFILER_API;

/** @} */

ROCPROFILER_EXTERN_C_FINI
