Gbaraldi/threadtrace2 (#724)

* Added first ATT API

* Finalizing thread trace API

* Fixing more rebase conflicts

* Added codeobj disassembly sample

* Fixing merge issues with rebase [2]

* Adding ATT packets

* Implemented thread trace intercept

* Moved codeobj parser to same repo as rocprofiler

* Moved thread trace to new API

* Fixing merge conflicts

* Fixing more merge conflicts

* Adding thread trace packet reuse

* Merged aql_profile_v2 headers

* Linked ATT sample to aqlprofile

* Updated decoder to include non-loaded codeobjs

* Implemented ISA decoder into ATT sample

* Added marker_id to vaddr

* Updating aql_profile_v2 API to memcpy

* Updating thread trace API to include 64bit markers. Using the result of ISA matching.

* Added instruction type and cycles summary

* Updated sample with selection of kernel by kernel_object

* Added option to copy from memory kernels

* Moved tool_data in thread_trace to dynamic alloc

* Restoring hsa.cpp

* Fixed ATT sample crash. General improvements.

* Moved codeobj library to outside src/

* Updated license header

* Moved codeobj_capture to camelcase

* Solving some more merge conflicts

* Update samples/advanced_thread_trace/CMakeLists.txt

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update samples/advanced_thread_trace/CMakeLists.txt

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update samples/code_object_isa_decode/CMakeLists.txt

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update source/lib/rocprofiler-sdk/thread_trace/CMakeLists.txt

* Removing unused parameter check

* Adding const to isEmpty

* Removing unused warning

* Adding libdw-dev to requirements

* Running clang-format

* Commenting out new aql calls

* Clang format

* Unused variable fix

* Adding codeobj-decoder coverage

* Commenting out threadtrace

* Update samples/CMakeLists.txt

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* P

* WOverloaded

* Addressing clang-tidy

* Virtual destructor on ttracer class

* Corr id

* Fixing code source format

* Update CMakeLists.txt

* Build fixes

* Update source/lib/rocprofiler-sdk-codeobj/code_object_track.cpp

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Fix shadowing

* Update CMakeLists.txt

* Update samples/CMakeLists.txt

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Ammar ELWazir <ammar.elwazir@amd.com>
Co-authored-by: Ammar ELWazir <aelwazir@amd.com>
Co-authored-by: Benjamin Welton <bewelton@amd.com>
Tento commit je obsažen v:
authored and GitHub committed 2024-04-08 12:43:02 -07:00
1 rodič d2bad14bf6
revize 69b8a43dc6
48 files changed
+4649 -109

No files matched your search

+1
Zobrazit soubor
@@ -42,6 +42,7 @@ add_subdirectory(counters)
add_subdirectory(aql)
add_subdirectory(pc_sampling)
add_subdirectory(marker)
add_subdirectory(thread_trace)
target_link_libraries(
rocprofiler-object-library
+644 -7
Zobrazit soubor
@@ -1,17 +1,352 @@
// This file should be removed when it appears in AQL Profile
#pragma ONCE
// MIT License
//
// Copyright (c) 2024 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 <hsa/hsa.h>
#include <hsa/hsa_ven_amd_aqlprofile.h>
#define PUBLIC_API __attribute__((visibility("default")))
#ifdef __cplusplus
extern "C" {
#endif
typedef struct
{
uint64_t handle;
} aqlprofile_handle_t;
typedef enum
{
AQLPROFILE_MEMORY_HINT_NONE = 0,
AQLPROFILE_MEMORY_HINT_HOST = 1,
AQLPROFILE_MEMORY_HINT_DEVICE_UNCACHED = 2,
AQLPROFILE_MEMORY_HINT_DEVICE_COHERENT = 3,
AQLPROFILE_MEMORY_HINT_DEVICE_NONCOHERENT = 4,
AQLPROFILE_MEMORY_HINT_LAST
} aqlprofile_memory_hint_t;
/**
* @brief Flags to describe which agents can access given buffer.
*/
typedef union
{
uint32_t raw;
struct
{
uint32_t device_access : 1;
uint32_t host_access : 1;
uint32_t memory_hint : 6; // One of aqlprofile_memory_hint_t
uint32_t _reserved : 24;
};
} aqlprofile_buffer_desc_flags_t;
/**
* @brief Callback to request a memory buffer, which will be tied to a profile.
* The user is responsible for clearing up memory after the profile is no longer needed.
* @param[out] ptr The pointer containing memory.
* @param[in] size Minimum requested buffer size.
* @param[in] flags Access flags, requesting which agents need to read/write to the buffer.
* @param[in] userdata Data to be passed back to user.
* @retval HSA_STATUS_SUCCESS if successful
* @retval HSA_STATUS_ERROR if memory could not be allocated
*/
typedef hsa_status_t (*aqlprofile_memory_alloc_callback_t)(void** ptr,
uint64_t size,
aqlprofile_buffer_desc_flags_t flags,
void* userdata);
/**
* @brief Callback to dealloc memory requested via aqlprofile_memory_alloc_callback_t
* @param[in] ptr The pointer containing memory.
* @param[in] userdata Data to be passed back to user.
* @retval HSA_STATUS_SUCCESS if successful
* @retval HSA_STATUS_ERROR if memory could not be allocated
*/
typedef void (*aqlprofile_memory_dealloc_callback_t)(void* ptr, void* userdata);
typedef enum
{
AQLPROFILE_ACCUMULATION_NONE = 0, /** Do not accumulate event */
AQLPROFILE_ACCUMULATION_LO_RES, /**< The event should be integrated over quad-cycles */
AQLPROFILE_ACCUMULATION_HI_RES, /**< The event should be integrated every cycle */
AQLPROFILE_ACCUMULATION_LAST,
} aqlprofile_accumulation_type_t;
/**
* @brief Special flags indicating additional properties to a counter. E.g. Accumulation metrics
*/
typedef union
{
uint32_t raw;
struct
{
uint32_t accum : 3; /**< One of aqlprofile_accumulation_type_t */
uint32_t _reserved : 29;
} sq_flags;
} aqlprofile_pmc_event_flags_t;
/**
* @brief Struct containing all necessary information of an event (counter).
*/
typedef struct
{
uint32_t block_index; /**< Block channel. */
uint32_t event_id; /**< Event ID as fined by XML */
aqlprofile_pmc_event_flags_t flags; /**< Special event flags e.g. accumulation */
hsa_ven_amd_aqlprofile_block_name_t block_name; /**< Block name as defined by block indexes */
} aqlprofile_pmc_event_t;
/**
* @brief Struct containing information about the agent. User code sets these values
* to the describe the agent to profile. Information can be obtained either from HSA
* (if loaded) or the KFD topology.
*/
typedef struct
{
const char* agent_gfxip; /**< Agent GFXIP (HSA_AGENT_INFO_NAME or KFD.product_name) */
uint32_t xcc_num; /**< XCC's on the agent (HSA_AMD_AGENT_INFO_NUM_XCC or KFD.num_xcc) */
uint32_t se_num; /**< SE's on the agent (HSA_AMD_AGENT_INFO_NUM_SHADER_ENGINES or
KFD.num_shader_banks) */
uint32_t
cu_num; /**< CU's on the agent (HSA_AMD_AGENT_INFO_COMPUTE_UNIT_COUNT or KFD.cu_count) */
uint32_t shader_arrays_per_se; /**< Shader arrays per SE of agent
(HSA_AMD_AGENT_INFO_NUM_SHADER_ARRAYS_PER_SE or
KFD.simd_arrays_per_engine)*/
} aqlprofile_agent_info_t;
/**
* @brief Struct containing a handle to a registered agent
*
*/
typedef struct
{
uint64_t handle;
} aqlprofile_agent_handle_t;
/**
* @brief Registers an agent to be used with AQL profile.
* @param[out] agent_id Handle to newly registered agent
* @param[in] agent_info Info to register a new agent with AQL Profiler
* @retval HSA_STATUS_SUCCESS registration ok
* @retval HSA_STATUS_ERROR registration failed
*/
hsa_status_t
aqlprofile_register_agent(aqlprofile_agent_handle_t* agent_id,
const aqlprofile_agent_info_t* agent_info);
/**
* @brief AQLprofile struct containing information for perfmon events
*/
typedef struct
{
aqlprofile_agent_handle_t agent;
const aqlprofile_pmc_event_t* events;
uint32_t event_count;
} aqlprofile_pmc_profile_t;
// Profile attributes
typedef enum
{
AQLPROFILE_INFO_COMMAND_BUFFER_SIZE = 0, // get_info returns uint32_t value
AQLPROFILE_INFO_PMC_DATA_SIZE = 1, // get_info returns uint32_t value
AQLPROFILE_INFO_PMC_DATA = 2, // get_info returns PMC uint64_t value
// in info_data object
AQLPROFILE_INFO_BLOCK_COUNTERS = 4, // get_info returns number of block counter
AQLPROFILE_INFO_BLOCK_ID = 5, // get_info returns block id, instances
// by name string using _id_query_t
AQLPROFILE_INFO_ENABLE_CMD = 6, // get_info returns size/pointer for
// counters enable command buffer
AQLPROFILE_INFO_DISABLE_CMD = 7, // get_info returns size/pointer for
// counters disable command buffer
} aqlprofile_pmc_info_type_t;
hsa_status_t
aqlprofile_get_pmc_info(const aqlprofile_pmc_profile_t* profile,
aqlprofile_pmc_info_type_t attribute,
void* value);
/**
* @brief AQLprofile struct containing information for Advanced Thread Trace
*/
typedef struct
{
hsa_agent_t agent;
const hsa_ven_amd_aqlprofile_parameter_t* parameters;
uint32_t parameter_count;
} aqlprofile_att_profile_t;
/**
* @brief Data callback for perfmon events. Each event will call this once per coordinate
* @param[in] event The event information passed in from aqlprofile_pmc_profile_t
* @param[in] counter_id Internal ID of the counter
* @param[in] counter_value The event value, as incremented from start() to stop()
* @param[in] userdata Data returned to user
* @retval HSA_STATUS_SUCCESS to continue iteration
* @retval HSA_STATUS_ERROR to stop callback iteration
*/
typedef hsa_status_t (*aqlprofile_pmc_data_callback_t)(aqlprofile_pmc_event_t event,
uint64_t counter_id,
uint64_t counter_value,
void* userdata);
/**
* @brief Data callback for thread trace. This will be called at least once per shader engine
* @param[in] shader Shader Engine ID
* @param[in] buffer Pointer containing the data
* @param[in] size Amount of bytes used by thread trace
* @param[in] callback_data Data returned to user
* @retval HSA_STATUS_SUCCESS to continue iteration
* @retval HSA_STATUS_ERROR to stop callback iteration
*/
typedef hsa_status_t (*aqlprofile_att_data_callback_t)(uint32_t shader,
void* buffer,
uint64_t size,
void* callback_data);
/**
* @brief Memory copy fn for aqlprofile to copy data.
* @param[in] dst Destination pointer to copy data to.
* @param[in] src Source pointer where data is to be copied from.
* @param[in] size Amount of bytes to be copied.
* @param[in] userdata Data returned to user
* @retval HSA_STATUS_SUCCESS on success
* @retval HSA_STATUS_ERROR on failure
*/
typedef hsa_status_t (*aqlprofile_memory_copy_t)(void* dst,
const void* src,
size_t size,
void* userdata);
/**
* @brief Validates the event for the agent.
* @param[in] agent The agent to validate the event for.
* @param[in] event The event to validate.
* @param[out] result True if the event is valid for the agent, false otherwise.
* @retval HSA_STATUS_SUCCESS if the event was validated.
* @retval HSA_STATUS_ERROR if the event was not validated.
*/
hsa_status_t
aqlprofile_validate_pmc_event(aqlprofile_agent_handle_t agent,
const aqlprofile_pmc_event_t* event,
bool* result);
/**
* @brief Iterate_data() will parse the event data and call @callback with the resulting event data
* @param[in] handle The handle returned from aqlprofile_pmc_create_packets()
* @param[in] callback CB where the resulting event values are going to be returned
* @param[in] userdata Data sent back to user
* @retval HSA_STATUS_SUCCESS all operations exited succesfully
* @retval HSA_STATUS_ERROR if some callback returns an error
* @retval HSA_STATUS_ERROR_INVALID_ARGUMENT if invalid handle is given
*/
hsa_status_t
aqlprofile_pmc_iterate_data(aqlprofile_handle_t handle,
aqlprofile_pmc_data_callback_t callback,
void* userdata);
/**
* @brief Struct to be returned by aqlprofile_pmc_create_packets
*/
typedef struct
{
hsa_ext_amd_aql_pm4_packet_t start_packet; /**< Reset counters and start incrementing */
hsa_ext_amd_aql_pm4_packet_t stop_packet; /**< Pause counters from incrementing */
hsa_ext_amd_aql_pm4_packet_t read_packet; /**< Retrieve results from device */
} aqlprofile_pmc_aql_packets_t;
/**
* @brief Function to create AQL packets to be inserted into the queue.
* @param[out] handle To be passed to iterate_data()
* @param[out] packets Pointer to where the start, stop and read packets will be written to
* @param[in] profile Agent and events information
* @param[in] alloc_cb Memory allocation, which may request cpu or gpu memory for internal use
* @param[in] dealloc_cb Function to free memory allocated by alloc_cb
* @param[in] userdata Data passed back to user via memory alloc callback
*/
hsa_status_t
aqlprofile_pmc_create_packets(aqlprofile_handle_t* handle,
aqlprofile_pmc_aql_packets_t* packets,
aqlprofile_pmc_profile_t profile,
aqlprofile_memory_alloc_callback_t alloc_cb,
aqlprofile_memory_dealloc_callback_t dealloc_cb,
aqlprofile_memory_copy_t memcpy_cb,
void* userdata);
/**
* @brief Function to delete AQL packets after creation by aqlprofile_pmc_create_packets
* @param[in] handle Returned by aqlprofile_pmc_create_packets()
*/
void
aqlprofile_pmc_delete_packets(aqlprofile_handle_t handle);
/**
* @brief Iterates over thread trace data and the data to user
* @param[in] handle The handle returned from aqlprofile_att_create_packets()
* @param[in] callback CB where the resulting data is going to be returned
* @param[in] userdata Data sent back to user
* @retval HSA_STATUS_SUCCESS all operations exited succesfully
* @retval HSA_STATUS_ERROR if some callback returns an error
* @retval HSA_STATUS_ERROR_INVALID_ARGUMENT if invalid handle is given
*/
hsa_status_t
aqlprofile_att_iterate_data(aqlprofile_handle_t handle,
aqlprofile_att_data_callback_t callback,
void* userdata);
/**
* @brief Struct containing AQLpackets to start and stop thread trace
*/
typedef struct
{
hsa_ext_amd_aql_pm4_packet_t start_packet; /**< Packet to start thread trace */
hsa_ext_amd_aql_pm4_packet_t stop_packet; /**< Packet to stop thread trace and flush data */
} aqlprofile_att_control_aql_packets_t;
/**
* @brief Fn to create start and stop thread trace packets
* @param[out] handle To be passed to iterate_data()
* @param[out] packets Packets returned by this function to start and stop thread trace
* @param[in] profile Agent information and extra parameters for thread trace
* @param[in] callback Memory allocation fn which may request cpu or gpu memory
* @retval HSA_STATUS_SUCCESS if all packets created succesfully
* @retval HSA_STATUS_ERROR otherwise
*/
hsa_status_t
aqlprofile_att_create_packets(aqlprofile_handle_t* handle,
aqlprofile_att_control_aql_packets_t* packets,
aqlprofile_att_profile_t profile,
aqlprofile_memory_alloc_callback_t alloc_cb,
aqlprofile_memory_dealloc_callback_t dealloc_cb,
aqlprofile_memory_copy_t memcpy_cb,
void* userdata);
void
aqlprofile_att_delete_packets(aqlprofile_handle_t handle);
/**
* @brief Callback for iteration of all possible event coordinate IDs and coordinate names.
* @param [in] id Integer identifying the dimension.
* @param [in] name Name of the dimension
* @param [in] data User data supplied to @ref aqlprofile_iterate_event_ids
* @return hsa_status_t
* @retval HSA_STATUS_SUCCESS Continues iteration
* @retval OTHERS Any other HSA return values stops iteration, passing back this value through
* @ref aqlprofile_iterate_event_ids
@@ -22,12 +357,314 @@ typedef hsa_status_t (*aqlprofile_eventname_callback_t)(int id, const char* name
* @brief Iterate over all possible event coordinate IDs and their names.
* @param [in] callback Callback to use for iteration of dimensions
* @param [in] user_data Data to supply to callback @ref aqlprofile_eventname_callback_t
* @return hsa_status_t
* @retval HSA_STATUS_SUCCESS if successful
* @retval HSA_STATUS_ERROR if error on interation
* @retval OTHERS If @ref aqlprofile_eventname_callback_t returns non-HSA_STATUS_SUCCESS,
* that value is returned.
*/
PUBLIC_API hsa_status_t
hsa_status_t
aqlprofile_iterate_event_ids(aqlprofile_eventname_callback_t callback, void* user_data);
/**
* @brief Iterate over all event coordinates for a given agent_t and event_t.
* @param position A counting sequence indicating callback number.
* @param id Coordinate ID as in _iterate_event_ids.
* @param extent Coordinate extent indicating maximum allowed instances.
* @param coordinate The coordinate, in the range [0,extent-1].
* @param name Coordinate name as in _iterate_event_ids.
* @param userdata Userdata returned from _iterate_event_coord function.
*/
typedef hsa_status_t (*aqlprofile_coordinate_callback_t)(int position,
int id,
int extent,
int coordinate,
const char* name,
void* userdata);
/**
* @brief Iterate over all event coordinates for a given agent_t and event_t.
* @param[in] agent HSA agent.
* @param[in] event The event ID and block ID to iterate for.
* @param[in] sample_id aqlprofile_info_data_t.sample_id returned from _aqlprofile_iterate_data.
* @param[in] callback Callback function to return the coordinates.
* @param[in] userdata Arbitrary data pointer to be sent back to the user via callback.
*/
hsa_status_t
aqlprofile_iterate_event_coord(aqlprofile_agent_handle_t agent,
aqlprofile_pmc_event_t event,
uint64_t sample_id,
aqlprofile_coordinate_callback_t callback,
void* userdata);
typedef union
{
uint64_t raw;
struct
{
uint64_t isValid : 1;
uint64_t isNavi : 1;
uint64_t npiWaveData : 1;
uint64_t version : 13;
};
} att_output_flags_t;
typedef struct
{
int64_t time;
uint16_t events0;
uint16_t events1;
uint16_t events2;
uint16_t events3;
uint8_t CU;
uint8_t bank;
} att_perfevent_t;
typedef struct
{
uint64_t kernel_id : 12;
uint64_t simd : 2;
uint64_t slot : 4;
uint64_t enable : 1;
uint64_t cu : 4;
uint64_t time : 41; // Time_value/8
} att_occupancy_info_t;
typedef struct
{
int32_t type;
int32_t duration;
} wave_state_t;
typedef struct
{
int64_t time;
int64_t duration;
} wave_instruction_t;
enum WAVESLOT_STATE
{
WS_EMPTY = 0,
WS_IDLE = 1,
WS_EXEC = 2,
WS_WAIT = 3,
WS_STALL = 4,
WS_UNKNOWN = 5,
};
enum WaveInstCategory
{
NONE = 0,
SMEM = 1,
SALU = 2,
VMEM = 3,
FLAT = 4,
LDS = 5,
VALU = 6,
JUMP = 7,
NEXT = 8,
IMMED = 9,
TRAP = 10,
PCINFO = 15,
WAVE_NOT_FINISHED,
};
enum WaveTrapStatus
{
TRAP_RESTORED = 0,
TRAP_REQUEST = 1,
TRAP_SAVED = 1,
TRAP_STANDBY = 2
};
typedef struct
{
size_t addr;
size_t marker_id;
} pcinfo_t;
typedef struct __attribute__((packed))
{
uint64_t category : 8;
uint64_t hitcount : 56;
uint64_t latency;
pcinfo_t pc;
} att_trace_event_t;
typedef struct
{
uint8_t simd;
uint8_t wave_id;
uint8_t trap_status;
uint8_t reserved;
// VMEM Pipeline: instrs and stalls
int num_vmem_instrs;
int num_vmem_stalls;
// FLAT instrs and stalls
int num_flat_instrs;
int num_flat_stalls;
// LDS instr and stalls
int num_lds_instrs;
int num_lds_stalls;
// SCA instrs stalls
int num_salu_instrs;
int num_smem_instrs;
int num_salu_stalls;
int num_smem_stalls;
// Branch
int num_branch_instrs;
int num_branch_taken_instrs;
int num_branch_stalls;
// total VMEM/FLAT/LDS/SMEM instructions issued
int num_mem_instrs; // total issued memory instructions
int num_valu_stalls;
size_t num_valu_instrs;
size_t num_issued_instrs; // total issued instructions (compute + memory)
int64_t begin_time; // Begin and end cycle
int64_t end_time;
int64_t traceID;
size_t timeline_size;
size_t instructions_size;
wave_state_t* timeline_array;
wave_instruction_t* instructions_array;
} wave_data_t;
/**
* @brief Callback for rocprofiler to return ISA to aqlprofile ATT parser.
* The caller must copy a desired instruction on isa_instruction and source_reference,
* while obeying the max length passed by the caller.
* If the caller's length is insufficient, then this function writes the minimum sizes to isa_size
* and source_size and returns HSA_STATUS_ERROR_OUT_OF_RESOURCES.
* If call returns HSA_STATUS_SUCCESS, isa_size and source_size are written with bytes used.
* @param[out] isa_instruction Where to copy the ISA line to.
* @param[out] source_reference Reference to source line and/or additional comments in the binary.
* @param[out] isa_memory_size (Auto) The number of bytes to next instruction. 0 for custom ISA.
* @param[inout] isa_size Size of returned ISA string.
* @param[inout] source_size Size of returned reference/comment string.
* @param[in] marker_id The generated ATT marker for given codeobject ID.
* @param[in] offset The offset from base vaddr for given codeobj ID.
* If marker_id == 0, this parameter is raw virtual address with no codeobj ID information.
* @param[in] userdata Arbitrary data pointer to be sent back to the user via callback.
* @retval HSA_STATUS_SUCCESS on success.
* @retval HSA_STATUS_ERROR on generic error.
* @retval HSA_STATUS_ERROR_INVALID_ARGUMENT for invalid offset or invalid marker_id.
* @retval HSA_STATUS_ERROR_OUT_OF_RESOURCES for insufficient isa_size or source_size.
*/
typedef hsa_status_t (*aqlprofile_att_isa_callback_t)(char* isa_instruction,
char* source_reference,
uint64_t* isa_memory_size,
uint64_t* isa_size,
uint64_t* source_size,
uint64_t marker_id,
uint64_t offset,
void* userdata);
/**
* @brief Callback for rocprofiler to return traces back to rocprofiler.
* @param[in] trace_type_id The type of this trace as in _iterate_event_ids().
* @param[in] correlation_id The ID of shader engine or trace callback number.
* @param[in] trace_events A pointer to sequence of events, of size trace_size.
* @param[in] trace_size The number of events in the trace.
* @param[in] userdata Arbitrary data pointer to be sent back to the user via callback.
*/
typedef hsa_status_t (*aqlprofile_att_trace_callback_t)(int trace_type_id,
int correlation_id,
void* trace_events,
uint64_t trace_size,
void* userdata);
/**
* @brief Callback for the ATT parser to retrieve Shader Engine data.
* Returns the amount of data filled. If no more data is available, then callback return 0
* If the space available in the buffer is less than required for parsing the full data,
* the full data is transfered over multiple calls.
* When all data has been transfered from current shader_engine_id, the caller has the option to
* 1) Return -1 on shader_engine ID and parsing terminates
* 2) Move to the next shader engine.
* @param[out] shader_engine_id The ID of given shader engine.
* @param[out] buffer The buffer to fill up with SE data.
* @param[out] buffer_size The space available in the buffer.
* @param[in] userdata Arbitrary data pointer to be sent back to the user via callback.
* @returns Number of bytes remaining in shader engine.
* @retval 0 if no more SE data is available. Parsing will stop.
* @retval buffer_size if the buffer does not hold enough data for the current shader engine.
* @retval 0 > ret > buffer_size for partially filled buffer, and caller moves over to next SE.
*/
typedef uint64_t (*aqlprofile_att_se_data_callback_t)(int* shader_engine_id,
uint8_t** buffer,
uint64_t* buffer_size,
void* userdata);
/**
* @brief Callback returning from aqlprofile_att_parser_iterate_event_list
* @param[in] trace_event_id ID of the event.
* @param[in] trace_event_metadata Null-terminated string, entries separated by ';'
* @param[in] userdata userdata.
*/
typedef void (*aqlprofile_att_parser_iterate_event_cb_t)(int trace_event_id,
const char* trace_event_metadata,
void* userdata);
/**
* @brief Iterate over all available event types.
* @param[in] callback Callback where events are returned to.
* @param[in] userdata userdata.
*/
void
aqlprofile_att_parser_iterate_event_list(aqlprofile_att_parser_iterate_event_cb_t callback,
void* userdata);
/**
* @brief Iterate over all event coordinates for a given agent_t and event_t.
* @param[in] se_data_callback Callback to return shader engine data from.
* @param[in] trace_callback Callback where the trace data is returned to.
* Each trace will be marked by the ID returned on aqlprofile_att_parser_iterate_event_list.
* @param[in] isa_callback Callback to return ISA lines.
* @param[in] userdata Userdata passed back to caller via callback.
*/
hsa_status_t
aqlprofile_att_parse_data(aqlprofile_att_se_data_callback_t se_data_callback,
aqlprofile_att_trace_callback_t trace_callback,
aqlprofile_att_isa_callback_t isa_callback,
void* userdata);
/**
* @brief Contains flags for how code objects are interpreted
*/
typedef union
{
struct
{
uint32_t isUnload : 1; // 0 if code object is being loaded, 1 for unload
uint32_t bFromStart : 1; // Has this code object been loaded before thread trace started?
uint32_t legacy_id : 30; // Legacy code object ID, if it fits in 30 bits.
};
uint32_t raw;
} aqlprofile_att_header_marker_t;
/**
* @brief Creates an AQL packet for marking code objects
* @param[out] packets Returned packet
* @param[in] handle The handle created from aqlprofile_att_create_packets()
* @param[in] header Header containing code object information created from profiler
* @param[in] id To be passed back to isa_string_callback in marker_id
* @param[in] addr Code object loaded address.
* @param[in] size Code object loaded size.
*/
hsa_status_t
aqlprofile_att_codeobj_load_marker(hsa_ext_amd_aql_pm4_packet_t* packets,
aqlprofile_handle_t handle,
aqlprofile_att_header_marker_t header,
uint64_t id,
uint64_t addr,
uint64_t size);
#ifdef __cplusplus
}
#endif
+82 -29
Zobrazit soubor
@@ -26,12 +26,22 @@
#include <hsa/hsa_ext_amd.h>
#include "glog/logging.h"
#define CHECK_HSA(fn, message) \
{ \
auto status = (fn); \
if(status != HSA_STATUS_SUCCESS) \
{ \
std::cerr << "HSA Err: " << status << "\n"; \
exit(1); \
} \
}
namespace rocprofiler
{
namespace aql
{
AQLPacketConstruct::AQLPacketConstruct(const hsa::AgentCache& agent,
const std::vector<counters::Metric>& metrics)
CounterPacketConstruct::CounterPacketConstruct(const hsa::AgentCache& agent,
const std::vector<counters::Metric>& metrics)
: _agent(agent)
{
// Validate that the counter exists and construct the block instances
@@ -67,12 +77,11 @@ AQLPacketConstruct::AQLPacketConstruct(const hsa::AgentCache& agen
_events = get_all_events();
}
std::unique_ptr<hsa::AQLPacket>
AQLPacketConstruct::construct_packet(const AmdExtTable& ext) const
std::unique_ptr<hsa::CounterAQLPacket>
CounterPacketConstruct::construct_packet(const AmdExtTable& ext)
{
const size_t MEM_PAGE_MASK = 0x1000 - 1;
auto pkt_ptr = std::make_unique<hsa::AQLPacket>(ext.hsa_amd_memory_pool_free_fn);
auto& pkt = *pkt_ptr;
auto pkt_ptr = std::make_unique<hsa::CounterAQLPacket>(ext.hsa_amd_memory_pool_free_fn);
auto& pkt = *pkt_ptr;
if(_events.empty())
{
return pkt_ptr;
@@ -104,15 +113,7 @@ AQLPacketConstruct::construct_packet(const AmdExtTable& ext) const
_agent.get_hsa_agent().handle));
}
auto throw_if_failed = [](auto status, auto& message) {
if(status != HSA_STATUS_SUCCESS)
{
throw std::runtime_error(message);
}
};
throw_if_failed(hsa_ven_amd_aqlprofile_start(&profile, nullptr),
"could not generate packet sizes");
CHECK_HSA(hsa_ven_amd_aqlprofile_start(&profile, nullptr), "could not generate packet sizes");
if(profile.command_buffer.size == 0 || profile.output_buffer.size == 0)
{
@@ -125,7 +126,7 @@ AQLPacketConstruct::construct_packet(const AmdExtTable& ext) const
// Allocate buffers and check the results
auto alloc_and_check = [&](auto& pool, auto** mem_loc, auto size) -> bool {
bool malloced = false;
size_t page_aligned = (size + MEM_PAGE_MASK) & ~MEM_PAGE_MASK;
size_t page_aligned = getPageAligned(size);
if(ext.hsa_amd_memory_pool_allocate_fn(
pool, page_aligned, 0, static_cast<void**>(mem_loc)) != HSA_STATUS_SUCCESS)
{
@@ -153,22 +154,74 @@ AQLPacketConstruct::construct_packet(const AmdExtTable& ext) const
_agent.kernarg_pool(), &profile.output_buffer.ptr, profile.output_buffer.size);
memset(profile.output_buffer.ptr, 0x0, profile.output_buffer.size);
// throw if we do not construct the packets correctly.
throw_if_failed(hsa_ven_amd_aqlprofile_start(&profile, &pkt.start),
"could not generate start packet");
throw_if_failed(hsa_ven_amd_aqlprofile_stop(&profile, &pkt.stop),
"could not generate stop packet");
throw_if_failed(hsa_ven_amd_aqlprofile_read(&profile, &pkt.read),
"could not generate read packet");
CHECK_HSA(hsa_ven_amd_aqlprofile_start(&profile, &pkt.start), "failed to create start packet");
CHECK_HSA(hsa_ven_amd_aqlprofile_stop(&profile, &pkt.stop), "failed to create stop packet");
CHECK_HSA(hsa_ven_amd_aqlprofile_read(&profile, &pkt.read), "failed to create read packet");
pkt.start.header = HSA_PACKET_TYPE_VENDOR_SPECIFIC << HSA_PACKET_HEADER_TYPE;
pkt.stop.header = HSA_PACKET_TYPE_VENDOR_SPECIFIC << HSA_PACKET_HEADER_TYPE;
pkt.read.header = HSA_PACKET_TYPE_VENDOR_SPECIFIC << HSA_PACKET_HEADER_TYPE;
return pkt_ptr;
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnarrowing"
ThreadTraceAQLPacketFactory::ThreadTraceAQLPacketFactory(
const hsa::AgentCache& agent,
std::shared_ptr<thread_trace_parameters>& params,
const CoreApiTable& coreapi,
const AmdExtTable& ext)
{
this->tracepool = std::make_shared<hsa::TraceMemoryPool>();
this->tracepool->allocate_fn = ext.hsa_amd_memory_pool_allocate_fn;
this->tracepool->allow_access_fn = ext.hsa_amd_agents_allow_access_fn;
this->tracepool->free_fn = ext.hsa_amd_memory_pool_free_fn;
this->tracepool->api_copy_fn = coreapi.hsa_memory_copy_fn;
this->tracepool->gpu_agent = agent.get_hsa_agent();
this->tracepool->cpu_pool_ = agent.cpu_pool();
this->tracepool->gpu_pool_ = agent.gpu_pool();
this->aql_params.clear();
auto& p = this->aql_params;
p.push_back({HSA_VEN_AMD_AQLPROFILE_PARAMETER_NAME_COMPUTE_UNIT_TARGET, params->target_cu});
p.push_back({HSA_VEN_AMD_AQLPROFILE_PARAMETER_NAME_SE_MASK, params->shader_engine_mask});
p.push_back({HSA_VEN_AMD_AQLPROFILE_PARAMETER_NAME_SIMD_SELECTION, params->simd_select});
p.push_back({HSA_VEN_AMD_AQLPROFILE_PARAMETER_NAME_ATT_BUFFER_SIZE, params->buffer_size});
this->profile = aqlprofile_att_profile_t{agent.get_hsa_agent(), p.data(), p.size()};
}
#pragma GCC diagnostic pop
std::unique_ptr<hsa::TraceAQLPacket>
ThreadTraceAQLPacketFactory::construct_packet()
{
auto packet = std::make_unique<hsa::TraceAQLPacket>(this->tracepool);
/*hsa_status_t _status = aqlprofile_att_create_packets(&packet->handle,
&packet->packets,
this->profile,
&hsa::TraceAQLPacket::Alloc,
&hsa::TraceAQLPacket::Free,
&hsa::TraceAQLPacket::Copy,
packet.get());
CHECK_HSA(_status, "failed to create ATT packet");*/
packet->before_krn_pkt.clear();
packet->after_krn_pkt.clear();
packet->packets.start_packet.header = HSA_PACKET_TYPE_VENDOR_SPECIFIC << HSA_PACKET_HEADER_TYPE;
packet->packets.stop_packet.header = HSA_PACKET_TYPE_VENDOR_SPECIFIC << HSA_PACKET_HEADER_TYPE;
packet->empty = false;
packet->start = packet->packets.start_packet;
packet->stop = packet->packets.stop_packet;
packet->before_krn_pkt.push_back(packet->start);
packet->after_krn_pkt.push_back(packet->stop);
return packet;
}
std::vector<hsa_ven_amd_aqlprofile_event_t>
AQLPacketConstruct::get_all_events() const
CounterPacketConstruct::get_all_events() const
{
std::vector<hsa_ven_amd_aqlprofile_event_t> ret;
for(const auto& metric : _metrics)
@@ -179,7 +232,7 @@ AQLPacketConstruct::get_all_events() const
}
const counters::Metric*
AQLPacketConstruct::event_to_metric(const hsa_ven_amd_aqlprofile_event_t& event) const
CounterPacketConstruct::event_to_metric(const hsa_ven_amd_aqlprofile_event_t& event) const
{
if(const auto* ptr = rocprofiler::common::get_val(
_event_to_metric,
@@ -191,7 +244,7 @@ AQLPacketConstruct::event_to_metric(const hsa_ven_amd_aqlprofile_event_t& event)
}
const std::vector<hsa_ven_amd_aqlprofile_event_t>&
AQLPacketConstruct::get_counter_events(const counters::Metric& metric) const
CounterPacketConstruct::get_counter_events(const counters::Metric& metric) const
{
for(const auto& prof_metric : _metrics)
{
@@ -204,7 +257,7 @@ AQLPacketConstruct::get_counter_events(const counters::Metric& metric) const
}
void
AQLPacketConstruct::can_collect()
CounterPacketConstruct::can_collect()
{
// Verify that the counters fit within harrdware limits
std::map<std::pair<hsa_ven_amd_aqlprofile_block_name_t, uint32_t>, int64_t> counter_count;
+28 -6
Zobrazit soubor
@@ -30,10 +30,12 @@
#include <hsa/hsa_api_trace.h>
#include <hsa/hsa_ven_amd_aqlprofile.h>
#include "lib/rocprofiler-sdk/aql/aql_profile_v2.h"
#include "lib/rocprofiler-sdk/aql/helpers.hpp"
#include "lib/rocprofiler-sdk/counters/metrics.hpp"
#include "lib/rocprofiler-sdk/hsa/agent_cache.hpp"
#include "lib/rocprofiler-sdk/hsa/queue.hpp"
#include "lib/rocprofiler-sdk/thread_trace/att_core.hpp"
namespace rocprofiler
{
@@ -47,21 +49,27 @@ namespace aql
* consturcted start/stop/read packets along with allocated buffers needed
* to collect the counter data.
*/
class AQLPacketConstruct
class CounterPacketConstruct
{
public:
AQLPacketConstruct(const hsa::AgentCache& agent, const std::vector<counters::Metric>& metrics);
std::unique_ptr<hsa::AQLPacket> construct_packet(const AmdExtTable&) const;
CounterPacketConstruct(const hsa::AgentCache& agent,
const std::vector<counters::Metric>& metrics);
std::unique_ptr<hsa::CounterAQLPacket> construct_packet(const AmdExtTable&);
const counters::Metric* event_to_metric(const hsa_ven_amd_aqlprofile_event_t& event) const;
std::vector<hsa_ven_amd_aqlprofile_event_t> get_all_events() const;
hsa_agent_t hsa_agent() const { return _agent.get_hsa_agent(); }
const std::vector<hsa_ven_amd_aqlprofile_event_t>& get_counter_events(
const counters::Metric&) const;
hsa_agent_t hsa_agent() const { return _agent.get_hsa_agent(); }
private:
const hsa::AgentCache& _agent;
static constexpr size_t MEM_PAGE_ALIGN = 0x1000;
static constexpr size_t MEM_PAGE_MASK = MEM_PAGE_ALIGN - 1;
static size_t getPageAligned(size_t p) { return (p + MEM_PAGE_MASK) & ~MEM_PAGE_MASK; }
protected:
struct AQLProfileMetric
{
counters::Metric metric;
@@ -70,12 +78,26 @@ private:
void can_collect();
const hsa::AgentCache& _agent;
std::vector<AQLProfileMetric> _metrics;
std::vector<hsa_ven_amd_aqlprofile_event_t> _events;
std::map<std::tuple<hsa_ven_amd_aqlprofile_block_name_t, uint32_t, uint32_t>, counters::Metric>
_event_to_metric;
};
class ThreadTraceAQLPacketFactory
{
public:
ThreadTraceAQLPacketFactory(const hsa::AgentCache& agent,
std::shared_ptr<thread_trace_parameters>& params,
const CoreApiTable& coreapi,
const AmdExtTable& ext);
std::unique_ptr<hsa::TraceAQLPacket> construct_packet();
private:
std::shared_ptr<hsa::TraceMemoryPool> tracepool;
std::vector<hsa_ven_amd_aqlprofile_parameter_t> aql_params;
aqlprofile_att_profile_t profile;
};
} // namespace aql
} // namespace rocprofiler
+26 -23
Zobrazit soubor
@@ -122,7 +122,7 @@ TEST(aql_profile, construct_packets)
LOG(WARNING) << fmt::format("Found Agent: {}", agent.get_hsa_agent().handle);
auto metrics = rocprofiler::findDeviceMetrics(agent, {"SQ_WAVES"});
ASSERT_EQ(metrics.size(), 1);
AQLPacketConstruct(agent, metrics);
CounterPacketConstruct(agent, metrics);
}
hsa_shut_down();
}
@@ -142,7 +142,7 @@ TEST(aql_profile, too_many_counters)
{
try
{
AQLPacketConstruct(agent, metrics);
CounterPacketConstruct(agent, metrics);
} catch(const std::exception& e)
{
EXPECT_NE(e.what(), nullptr) << e.what();
@@ -163,9 +163,9 @@ TEST(aql_profile, packet_generation_single)
ASSERT_GT(agents.size(), 0);
for(const auto& [_, agent] : agents)
{
auto metrics = rocprofiler::findDeviceMetrics(agent, {"SQ_WAVES"});
AQLPacketConstruct pkt(agent, metrics);
auto test_pkt = pkt.construct_packet(rocprofiler::get_ext_table());
auto metrics = rocprofiler::findDeviceMetrics(agent, {"SQ_WAVES"});
CounterPacketConstruct pkt(agent, metrics);
auto test_pkt = pkt.construct_packet(rocprofiler::get_ext_table());
EXPECT_TRUE(test_pkt);
}
@@ -183,14 +183,30 @@ TEST(aql_profile, packet_generation_multi)
{
auto metrics =
rocprofiler::findDeviceMetrics(agent, {"SQ_WAVES", "TA_FLAT_READ_WAVEFRONTS"});
AQLPacketConstruct pkt(agent, metrics);
auto test_pkt = pkt.construct_packet(rocprofiler::get_ext_table());
CounterPacketConstruct pkt(agent, metrics);
auto test_pkt = pkt.construct_packet(rocprofiler::get_ext_table());
EXPECT_TRUE(test_pkt);
}
hsa_shut_down();
}
class TestAqlPacket : public rocprofiler::hsa::CounterAQLPacket
{
public:
TestAqlPacket(bool mallocd)
: rocprofiler::hsa::CounterAQLPacket([](void* x) -> hsa_status_t {
::free(x);
return HSA_STATUS_SUCCESS;
})
{
this->profile.output_buffer.ptr = malloc(sizeof(double));
this->profile.command_buffer.ptr = malloc(sizeof(double));
this->command_buf_mallocd = mallocd;
this->output_buffer_malloced = mallocd;
}
};
TEST(aql_profile, test_aql_packet)
{
auto check_null = [](auto& val) {
@@ -201,25 +217,12 @@ TEST(aql_profile, test_aql_packet)
val.completion_signal.handle == null_val.completion_signal.handle;
};
rocprofiler::hsa::AQLPacket test_pkt([](void* x) -> hsa_status_t {
::free(x);
return HSA_STATUS_SUCCESS;
});
TestAqlPacket test_pkt(true);
EXPECT_TRUE(check_null(test_pkt.start)) << "Start packet not null";
EXPECT_TRUE(check_null(test_pkt.stop)) << "Stop packet not null";
EXPECT_TRUE(check_null(test_pkt.read)) << "Read packet not null";
// If this leaks, then AQLPacket is not freeing data correctly.
test_pkt.profile.output_buffer.ptr = malloc(sizeof(double));
test_pkt.profile.command_buffer.ptr = malloc(sizeof(double));
test_pkt.command_buf_mallocd = true;
test_pkt.output_buffer_malloced = true;
// test custom destructor as well
rocprofiler::hsa::AQLPacket test_pkt2([](void* x) -> hsa_status_t {
::free(x);
return HSA_STATUS_SUCCESS;
});
test_pkt2.profile.output_buffer.ptr = malloc(sizeof(double));
test_pkt2.profile.command_buffer.ptr = malloc(sizeof(double));
// Why is this valid?
TestAqlPacket test_pkt2(false);
}
+4
Zobrazit soubor
@@ -32,6 +32,7 @@
#include "lib/rocprofiler-sdk/buffer.hpp"
#include "lib/rocprofiler-sdk/context/context.hpp"
#include "lib/rocprofiler-sdk/counters/core.hpp"
#include "lib/rocprofiler-sdk/thread_trace/att_core.hpp"
#include <glog/logging.h>
@@ -446,6 +447,7 @@ start_context(rocprofiler_context_id_t context_id)
}
if(cfg->counter_collection) rocprofiler::counters::start_context(cfg);
if(cfg->thread_trace) cfg->thread_trace->start_context();
return ROCPROFILER_STATUS_SUCCESS;
}
@@ -472,6 +474,8 @@ stop_context(rocprofiler_context_id_t idx)
if(_expected->counter_collection)
rocprofiler::counters::stop_context(const_cast<context*>(_expected));
else if(_expected->thread_trace)
_expected->thread_trace->stop_context();
return ROCPROFILER_STATUS_SUCCESS;
}
}
+2
Zobrazit soubor
@@ -33,6 +33,7 @@
#include "lib/rocprofiler-sdk/context/domain.hpp"
#include "lib/rocprofiler-sdk/counters/core.hpp"
#include "lib/rocprofiler-sdk/external_correlation.hpp"
#include "lib/rocprofiler-sdk/thread_trace/att_core.hpp"
#include <array>
#include <atomic>
@@ -153,6 +154,7 @@ struct context
std::unique_ptr<callback_tracing_service> callback_tracer = {};
std::unique_ptr<buffer_tracing_service> buffered_tracer = {};
std::unique_ptr<counter_collection_service> counter_collection = {};
std::shared_ptr<rocprofiler::ThreadTracer> thread_trace = {};
};
// set the client index needs to be called before allocate_context()
+2 -2
Zobrazit soubor
@@ -218,7 +218,7 @@ counter_callback_info::setup_profile_config(const hsa::AgentCache& age
}
}
profile->pkt_generator = std::make_unique<rocprofiler::aql::AQLPacketConstruct>(
profile->pkt_generator = std::make_unique<rocprofiler::aql::CounterPacketConstruct>(
agent,
std::vector<counters::Metric>{profile->reqired_hw_counters.begin(),
profile->reqired_hw_counters.end()});
@@ -288,7 +288,7 @@ queue_cb(const context::context* ctx,
// Packet generated when no instrumentation is performed. May contain serialization
// packets/barrier packets (and can be empty).
auto no_instrumentation = [&]() {
auto ret_pkt = std::make_unique<rocprofiler::hsa::AQLPacket>(nullptr);
auto ret_pkt = std::make_unique<rocprofiler::hsa::CounterAQLPacket>(nullptr);
// If we have a counter collection context but it is not enabled, we still might need
// to add barrier packets to transition from serialized -> unserialized execution. This
// transition is coordinated by the serializer.
+1 -1
Zobrazit soubor
@@ -59,7 +59,7 @@ struct profile_config
std::vector<counters::EvaluateAST> asts{};
rocprofiler_profile_config_id_t id{.handle = 0};
// Packet generator to create AQL packets for insertion
std::unique_ptr<rocprofiler::aql::AQLPacketConstruct> pkt_generator{nullptr};
std::unique_ptr<rocprofiler::aql::CounterPacketConstruct> pkt_generator{nullptr};
// A packet cache of AQL packets. This allows reuse of AQL packets (preventing costly
// allocation of new packets/destruction).
rocprofiler::common::Synchronized<std::vector<std::unique_ptr<rocprofiler::hsa::AQLPacket>>>
+2 -2
Zobrazit soubor
@@ -61,8 +61,8 @@ getBlockDimensions(std::string_view agent, const Metric& metric)
{
if(maybe_agent.name() == agent)
{
aql::AQLPacketConstruct pkt_gen(maybe_agent, {metric});
const auto& events = pkt_gen.get_counter_events(metric);
aql::CounterPacketConstruct pkt_gen(maybe_agent, {metric});
const auto& events = pkt_gen.get_counter_events(metric);
for(const auto& event : events)
{
+3 -3
Zobrazit soubor
@@ -450,16 +450,16 @@ EvaluateAST::read_special_counters(
}
std::unordered_map<uint64_t, std::vector<rocprofiler_record_counter_t>>
EvaluateAST::read_pkt(const aql::AQLPacketConstruct* pkt_gen, hsa::AQLPacket& pkt)
EvaluateAST::read_pkt(const aql::CounterPacketConstruct* pkt_gen, hsa::AQLPacket& pkt)
{
struct it_data
{
std::unordered_map<uint64_t, std::vector<rocprofiler_record_counter_t>>* data;
const aql::AQLPacketConstruct* pkt_gen;
const aql::CounterPacketConstruct* pkt_gen;
};
std::unordered_map<uint64_t, std::vector<rocprofiler_record_counter_t>> ret;
if(pkt.empty) return ret;
if(pkt.isEmpty()) return ret;
it_data aql_data{.data = &ret, .pkt_gen = pkt_gen};
;
hsa_status_t status = hsa_ven_amd_aqlprofile_iterate_data(
+2 -2
Zobrazit soubor
@@ -136,8 +136,8 @@ public:
*
*/
static std::unordered_map<uint64_t, std::vector<rocprofiler_record_counter_t>> read_pkt(
const aql::AQLPacketConstruct* pkt_gen,
hsa::AQLPacket& pkt);
const aql::CounterPacketConstruct* pkt_gen,
hsa::AQLPacket& pkt);
/**
* @brief Insert special counter values, such as constants of the agent (i.e. max waves)
+2 -2
Zobrazit soubor
@@ -251,8 +251,8 @@ TEST(dimension, block_dim_test)
}
else
{
aql::AQLPacketConstruct pkt_gen(agent, {metric});
const auto& events = pkt_gen.get_counter_events(metric);
aql::CounterPacketConstruct pkt_gen(agent, {metric});
const auto& events = pkt_gen.get_counter_events(metric);
for(const auto& event : events)
{
std::map<int, uint64_t> dims;
+61 -4
Zobrazit soubor
@@ -21,14 +21,22 @@
// THE SOFTWARE.
#include "lib/rocprofiler-sdk/hsa/aql_packet.hpp"
#include <cstdlib>
#include <iostream>
#include <string>
#define CHECK_HSA(fn, message) \
if((fn) != HSA_STATUS_SUCCESS) \
{ \
std::cerr << __FILE__ << ':' << __LINE__ << ' ' << message; \
exit(1); \
}
namespace rocprofiler
{
namespace hsa
{
AQLPacket::~AQLPacket()
CounterAQLPacket::~CounterAQLPacket()
{
if(!profile.command_buffer.ptr)
{
@@ -36,7 +44,7 @@ AQLPacket::~AQLPacket()
}
else if(!command_buf_mallocd)
{
free_func(profile.command_buffer.ptr);
CHECK_HSA(free_func(profile.command_buffer.ptr), "freeing memory");
}
else
{
@@ -49,12 +57,61 @@ AQLPacket::~AQLPacket()
}
else if(!output_buffer_malloced)
{
free_func(profile.output_buffer.ptr);
CHECK_HSA(free_func(profile.output_buffer.ptr), "freeing memory");
}
else
{
::free(profile.output_buffer.ptr);
}
}
TraceAQLPacket::~TraceAQLPacket() = default;
/*
TraceAQLPacket::~TraceAQLPacket()
{
aqlprofile_att_delete_packets(this->handle);
}
*/
hsa_status_t
TraceAQLPacket::Alloc(void** ptr, size_t size, aqlprofile_buffer_desc_flags_t flags, void* data)
{
if(!data) return HSA_STATUS_ERROR;
if(!reinterpret_cast<TraceAQLPacket*>(data)->tracepool) return HSA_STATUS_ERROR;
auto& pool = *reinterpret_cast<TraceAQLPacket*>(data)->tracepool;
if(!pool.allocate_fn || !pool.free_fn || !pool.allow_access_fn) return HSA_STATUS_ERROR;
if(flags.host_access)
{
hsa_status_t status = pool.allocate_fn(pool.cpu_pool_, size, 0, ptr);
if(!flags.device_access || status != HSA_STATUS_SUCCESS) return status;
return pool.allow_access_fn(1, &pool.gpu_agent, nullptr, *ptr);
}
return pool.allocate_fn(pool.gpu_pool_, size, 0, ptr);
}
void
TraceAQLPacket::Free(void* ptr, void* data)
{
auto* pool = reinterpret_cast<TraceAQLPacket*>(data)->tracepool.get();
if(!pool || !pool->free_fn) return;
pool->free_fn(ptr);
}
hsa_status_t
TraceAQLPacket::Copy(void* dst, const void* src, size_t size, void* data)
{
auto* pool = reinterpret_cast<TraceAQLPacket*>(data)->tracepool.get();
if(!pool || !pool->api_copy_fn) return HSA_STATUS_ERROR;
return pool->api_copy_fn(dst, src, size);
}
TraceAQLPacket::TraceAQLPacket(std::shared_ptr<TraceMemoryPool>& _tracepool)
: tracepool(_tracepool){};
} // namespace hsa
} // namespace rocprofiler
+70 -16
Zobrazit soubor
@@ -23,6 +23,7 @@
#pragma once
#include "lib/common/container/small_vector.hpp"
#include "lib/rocprofiler-sdk/aql/aql_profile_v2.h"
#include <hsa/hsa_ext_amd.h>
#include <hsa/hsa_ven_amd_aqlprofile.h>
@@ -30,6 +31,12 @@
namespace rocprofiler
{
namespace aql
{
class CounterPacketConstruct;
class ThreadTraceAQLPacketFactory;
} // namespace aql
namespace hsa
{
constexpr hsa_ext_amd_aql_pm4_packet_t null_amd_aql_pm4_packet = {
@@ -41,12 +48,11 @@ constexpr hsa_ext_amd_aql_pm4_packet_t null_amd_aql_pm4_packet = {
* Struct containing AQL packet information. Including start/stop/read
* packets along with allocated buffers
*/
struct AQLPacket
class AQLPacket
{
using memory_pool_free_func_t = decltype(::hsa_amd_memory_pool_free)*;
AQLPacket(memory_pool_free_func_t func);
~AQLPacket();
public:
AQLPacket() = default;
virtual ~AQLPacket() = default;
// Keep move constuctors (i.e. std::move())
AQLPacket(AQLPacket&& other) = default;
@@ -56,20 +62,68 @@ struct AQLPacket
AQLPacket(const AQLPacket&) = delete;
AQLPacket& operator=(const AQLPacket&) = delete;
bool command_buf_mallocd = false;
bool output_buffer_malloced = false;
bool empty = {true};
hsa_ven_amd_aqlprofile_profile_t profile = {};
hsa_ext_amd_aql_pm4_packet_t start = null_amd_aql_pm4_packet;
hsa_ext_amd_aql_pm4_packet_t stop = null_amd_aql_pm4_packet;
hsa_ext_amd_aql_pm4_packet_t read = null_amd_aql_pm4_packet;
memory_pool_free_func_t free_func = nullptr;
hsa_ven_amd_aqlprofile_profile_t profile = {};
hsa_ext_amd_aql_pm4_packet_t start = null_amd_aql_pm4_packet;
hsa_ext_amd_aql_pm4_packet_t stop = null_amd_aql_pm4_packet;
hsa_ext_amd_aql_pm4_packet_t read = null_amd_aql_pm4_packet;
common::container::small_vector<hsa_ext_amd_aql_pm4_packet_t, 3> before_krn_pkt = {};
common::container::small_vector<hsa_ext_amd_aql_pm4_packet_t, 2> after_krn_pkt = {};
bool isEmpty() const { return empty; }
bool empty = true;
};
class CounterAQLPacket : public AQLPacket
{
friend class rocprofiler::aql::CounterPacketConstruct;
using memory_pool_free_func_t = decltype(::hsa_amd_memory_pool_free)*;
public:
CounterAQLPacket(memory_pool_free_func_t func)
: free_func{func} {};
~CounterAQLPacket() override;
protected:
bool command_buf_mallocd = false;
bool output_buffer_malloced = false;
memory_pool_free_func_t free_func = nullptr;
};
struct TraceMemoryPool
{
hsa_agent_t gpu_agent;
hsa_amd_memory_pool_t cpu_pool_;
hsa_amd_memory_pool_t gpu_pool_;
decltype(hsa_amd_memory_pool_allocate)* allocate_fn;
decltype(hsa_amd_agents_allow_access)* allow_access_fn;
decltype(hsa_amd_memory_pool_free)* free_fn;
decltype(hsa_memory_copy)* api_copy_fn;
};
class TraceAQLPacket : public AQLPacket
{
friend class rocprofiler::aql::ThreadTraceAQLPacketFactory;
public:
TraceAQLPacket(std::shared_ptr<TraceMemoryPool>& _tracepool);
TraceMemoryPool& GetPool() const { return *tracepool; }
aqlprofile_handle_t GetHandle() const { return handle; }
uint64_t GetAgent() const { return tracepool->gpu_agent.handle; }
~TraceAQLPacket() override;
protected:
std::shared_ptr<TraceMemoryPool> tracepool;
aqlprofile_att_control_aql_packets_t packets;
aqlprofile_handle_t handle;
static hsa_status_t Alloc(void** ptr,
size_t size,
aqlprofile_buffer_desc_flags_t flags,
void* data);
static void Free(void* ptr, void* data);
static hsa_status_t Copy(void* dst, const void* src, size_t size, void* data);
};
inline AQLPacket::AQLPacket(memory_pool_free_func_t func)
: free_func{func}
{}
} // namespace hsa
} // namespace rocprofiler
+4 -4
Zobrazit soubor
@@ -672,10 +672,10 @@ code_object_load_callback(hsa_executable_t executable,
if(_status != HSA_STATUS_SUCCESS) return _status; \
}
auto& loader_table = get_loader_table();
auto code_obj_v = code_object{};
auto& data = code_obj_v.rocp_data;
int _storage_type = ROCPROFILER_CODE_OBJECT_STORAGE_TYPE_NONE;
auto& loader_table = get_loader_table();
auto code_obj_v = code_object{};
auto& data = code_obj_v.rocp_data;
uint32_t _storage_type = ROCPROFILER_CODE_OBJECT_STORAGE_TYPE_NONE;
LOG_IF(FATAL, data.size == 0) << "code object did not properly initialized the size field upon "
"construction (this is likely a compiler bug)";
-2
Zobrazit soubor
@@ -342,8 +342,6 @@ WriteInterceptor(const void* packets,
{
hsa_barrier_and_packet_t barrier{};
barrier.header = HSA_PACKET_TYPE_BARRIER_AND << HSA_PACKET_HEADER_TYPE;
// barrier.header |= HSA_FENCE_SCOPE_SYSTEM << HSA_PACKET_HEADER_SCACQUIRE_FENCE_SCOPE;
// barrier.header |= HSA_FENCE_SCOPE_SYSTEM << HSA_PACKET_HEADER_SCRELEASE_FENCE_SCOPE;
barrier.header |= 1 << HSA_PACKET_HEADER_BARRIER;
barrier.completion_signal = original_packet.completion_signal;
transformed_packets.emplace_back(barrier);
+24 -1
Zobrazit soubor
@@ -90,6 +90,9 @@ constexpr rocprofiler_agent_t default_agent =
void
QueueController::add_queue(hsa_queue_t* id, std::unique_ptr<Queue> queue)
{
for(auto& pre_initialize_fn : pre_initialize)
pre_initialize_fn(queue->get_agent(), get_core_table(), get_ext_table());
CHECK(queue);
_callback_cache.wlock([&](auto& callbacks) {
_queues.wlock([&](auto& map) {
@@ -111,6 +114,11 @@ void
QueueController::destroy_queue(hsa_queue_t* id)
{
if(!id) return;
_queues.wlock([&](auto& map) {
for(auto& deinitialize_fn : pre_deinitialize)
if(map.find(id) != map.end())
deinitialize_fn(map.at(id)->get_agent(), get_core_table(), get_ext_table());
});
const auto* queue = get_queue(*id);
@@ -195,7 +203,8 @@ QueueController::init(CoreApiTable& core_table, AmdExtTable& ext_table)
{
constexpr auto expected_context_size = 160UL;
static_assert(
sizeof(context::context) == expected_context_size,
sizeof(context::context) ==
expected_context_size + sizeof(std::shared_ptr<rocprofiler::ThreadTracer>),
"If you added a new field to context struct, make sure there is a check here if it "
"requires queue interception. Once you have done so, increment expected_context_size");
@@ -212,6 +221,20 @@ QueueController::init(CoreApiTable& core_table, AmdExtTable& ext_table)
break;
}
}
else if(itr->thread_trace)
{
enable_intercepter = true;
std::weak_ptr<rocprofiler::ThreadTracer> trace = itr->thread_trace;
pre_initialize.emplace_back(
[trace](const AgentCache& cache, const CoreApiTable& core, const AmdExtTable& ext) {
if(auto locked = trace.lock()) locked->resource_init(cache, core, ext);
});
pre_deinitialize.emplace_back(
[trace](const AgentCache& cache, const CoreApiTable&, const AmdExtTable&) {
if(auto locked = trace.lock()) locked->resource_deinit(cache);
});
break;
}
}
if(enable_intercepter)
+4
Zobrazit soubor
@@ -103,6 +103,7 @@ public:
private:
using client_id_map_t = std::unordered_map<ClientID, agent_callback_tuple_t>;
using agent_cache_map_t = std::unordered_map<uint32_t, AgentCache>;
using resource_alloc_t = void(const AgentCache&, const CoreApiTable&, const AmdExtTable&);
CoreApiTable _core_table = {};
AmdExtTable _ext_table = {};
@@ -110,6 +111,9 @@ private:
common::Synchronized<client_id_map_t> _callback_cache = {};
agent_cache_map_t _supported_agents = {};
common::Synchronized<hsa::profiler_serializer> _profiler_serializer;
std::vector<std::function<resource_alloc_t>> pre_initialize;
std::vector<std::function<resource_alloc_t>> pre_deinitialize;
};
QueueController*
+6
Zobrazit soubor
@@ -0,0 +1,6 @@
set(ROCPROFILER_LIB_THREAD_TRACE_SOURCES att_core.cpp att_service.cpp)
set(ROCPROFILER_LIB_THREAD_TRACE_HEADERS att_core.hpp)
target_sources(rocprofiler-object-library PRIVATE ${ROCPROFILER_LIB_THREAD_TRACE_SOURCES}
${ROCPROFILER_LIB_THREAD_TRACE_HEADERS})
# if(ROCPROFILER_BUILD_TESTS) add_subdirectory(tests) endif()
+238
Zobrazit soubor
@@ -0,0 +1,238 @@
// MIT License
//
// Copyright (c) 2024 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.
#include <rocprofiler-sdk/fwd.h>
#include <rocprofiler-sdk/intercept_table.h>
#include <rocprofiler-sdk/rocprofiler.h>
#include "lib/common/container/stable_vector.hpp"
#include "lib/common/utility.hpp"
#include "lib/rocprofiler-sdk/buffer.hpp"
#include "lib/rocprofiler-sdk/context/context.hpp"
#include "lib/rocprofiler-sdk/hsa/queue_controller.hpp"
#include "lib/rocprofiler-sdk/internal_threading.hpp"
#include "lib/rocprofiler-sdk/registration.hpp"
#include <hsa/hsa_api_trace.h>
#include <atomic>
#include <cstdint>
#include <mutex>
#include <stdexcept>
#include <string>
#include <vector>
#define CHECK_HSA(fn, message) \
{ \
auto _status = (fn); \
if(_status != HSA_STATUS_SUCCESS) \
{ \
LOG(ERROR) << "HSA Err: " << _status << '\n'; \
throw std::runtime_error(message); \
} \
}
namespace rocprofiler
{
using AQLPacketOwner = std::unique_ptr<hsa::AQLPacket>;
using inst_pkt_t = common::container::small_vector<std::pair<AQLPacketOwner, int64_t>, 4>;
using corr_id_map_t = hsa::Queue::queue_info_session_t::external_corr_id_map_t;
struct cbdata_t
{
void* tool_userdata;
rocprofiler_att_shader_data_callback_t cb_fn;
std::vector<uint8_t>* memory_space;
};
/**
* Callback we get from HSA interceptor when a kernel packet is being enqueued.
* We return an AQLPacket containing the start/stop/read packets for injection.
*/
AQLPacketOwner
pre_kernel_call(ThreadTracer& tracer,
const hsa::Queue& queue,
const hsa::rocprofiler_packet& kern_pkt,
uint64_t kernel_id,
const corr_id_map_t& extern_corr_ids,
const context::correlation_id* corr_id)
{
(void) extern_corr_ids;
(void) corr_id;
rocprofiler_correlation_id_t temp_corr_id;
temp_corr_id.internal = 0;
temp_corr_id.external.value = 0;
temp_corr_id.external.ptr = nullptr;
auto control_flags = tracer.params->dispatch_cb_fn(queue.get_id(),
queue.get_agent().get_rocp_agent(),
temp_corr_id,
&kern_pkt.kernel_dispatch,
kernel_id,
tracer.params->callback_userdata);
if(control_flags == ROCPROFILER_ATT_CONTROL_NONE) return nullptr;
assert(control_flags == ROCPROFILER_ATT_CONTROL_START_AND_STOP && "Error: Not implemented");
uint64_t agent = queue.get_agent().get_hsa_agent().handle;
std::lock_guard<std::mutex> lk(tracer.trace_resources_mut);
try
{
auto moved = std::move(tracer.resources.at(agent));
tracer.resources.erase(agent);
return moved;
} catch(std::out_of_range& e)
{
LOG(WARNING) << "Attempt to initialize ATT without allocated resources!\n";
return nullptr;
}
}
hsa_status_t
thread_trace_callback(uint32_t shader, void* buffer, uint64_t size, void* callback_data)
{
void* tool_userdata = static_cast<cbdata_t*>(callback_data)->tool_userdata;
auto callback_fn = *static_cast<cbdata_t*>(callback_data)->cb_fn;
std::vector<uint8_t>& cpu_data = *static_cast<cbdata_t*>(callback_data)->memory_space;
// TODO(gbaraldi): Handle parallel callbacks
static std::mutex mut;
std::lock_guard<std::mutex> lk(mut);
if(size > cpu_data.size()) cpu_data.resize(size + cpu_data.size());
auto status = hsa::get_queue_controller()->get_core_table().hsa_memory_copy_fn(
cpu_data.data(), buffer, size);
if(status != HSA_STATUS_SUCCESS)
{
LOG(WARNING) << "Failed to copy hsa memory!";
return HSA_STATUS_SUCCESS;
}
callback_fn(shader, 0, "", cpu_data.data(), size, tool_userdata);
return HSA_STATUS_SUCCESS;
}
void
post_kernel_call(ThreadTracer& tracer, inst_pkt_t& aql)
{
std::vector<uint8_t> cpu_data{};
auto pair = cbdata_t{tracer.params->callback_userdata, tracer.params->shader_cb_fn, &cpu_data};
(void) pair;
for(auto& aql_pkt : aql)
{
auto* pkt = dynamic_cast<hsa::TraceAQLPacket*>(aql_pkt.first.get());
if(!pkt) continue;
// auto status = aqlprofile_att_iterate_data(pkt->GetHandle(), thread_trace_callback,
// &pair); CHECK_HSA(status, "Failed to iterate ATT data");
std::lock_guard<std::mutex> lk(tracer.trace_resources_mut);
if(tracer.agent_active_queues.find(pkt->GetAgent()) != tracer.agent_active_queues.end())
tracer.resources[pkt->GetAgent()] = std::move(aql_pkt.first);
}
}
common::Synchronized<std::optional<int64_t>> client;
void
ThreadTracer::start_context()
{
// Only one thread should be attempting to enable/disable this context
client.wlock([&](auto& client_id) {
if(client_id) return;
client_id = hsa::get_queue_controller()->add_callback(
std::nullopt,
[=](const hsa::Queue& q,
const hsa::rocprofiler_packet& kern_pkt,
uint64_t kernel_id,
rocprofiler_user_data_t* user_data,
const hsa::Queue::queue_info_session_t::external_corr_id_map_t& extern_corr_ids,
const context::correlation_id* corr_id) {
(void) user_data;
return pre_kernel_call(*this, q, kern_pkt, kernel_id, extern_corr_ids, corr_id);
},
[=](const hsa::Queue& q,
hsa::rocprofiler_packet kern_pkt,
const hsa::Queue::queue_info_session_t& session,
inst_pkt_t& aql) {
post_kernel_call(*this, aql);
(void) session;
(void) kern_pkt;
(void) q;
});
});
}
void
ThreadTracer::stop_context()
{
client.wlock([&](auto& client_id) {
if(!client_id) return;
// Remove our callbacks from HSA's queue controller
hsa::get_queue_controller()->remove_callback(*client_id);
client_id = std::nullopt;
});
}
void
ThreadTracer::resource_init(const hsa::AgentCache& cache,
const CoreApiTable& coreapi,
const AmdExtTable& ext)
{
uint64_t agent = cache.get_hsa_agent().handle;
std::lock_guard<std::mutex> lk(trace_resources_mut);
if(agent_active_queues.find(agent) != agent_active_queues.end())
{
agent_active_queues.at(agent).fetch_add(1);
return;
}
auto factory = aql::ThreadTraceAQLPacketFactory(cache, this->params, coreapi, ext);
resources[agent] = factory.construct_packet();
agent_active_queues[agent] = 1;
}
void
ThreadTracer::resource_deinit(const hsa::AgentCache& cache)
{
uint64_t agent = cache.get_hsa_agent().handle;
std::lock_guard<std::mutex> lk(trace_resources_mut);
try
{
if(agent_active_queues.at(agent).fetch_add(-1) > 1) return;
} catch(std::out_of_range&)
{}
agent_active_queues.erase(agent);
resources.erase(agent);
}
} // namespace rocprofiler
+75
Zobrazit soubor
@@ -0,0 +1,75 @@
// MIT License
//
// Copyright (c) 2024 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/intercept_table.h>
#include <tuple>
#include "include/rocprofiler-sdk/thread_trace.h"
namespace rocprofiler
{
struct thread_trace_parameters
{
rocprofiler_context_id_t context_id;
rocprofiler_att_dispatch_callback_t dispatch_cb_fn;
rocprofiler_att_shader_data_callback_t shader_cb_fn;
void* callback_userdata;
// Parameters
rocprofiler_att_parameter_flag_t flags;
uint64_t buffer_size;
uint8_t target_cu;
uint8_t simd_select;
uint8_t reserved;
uint8_t vmid_mask;
uint16_t perfcounter_mask;
uint8_t perfcounter_ctrl;
uint64_t shader_engine_mask;
// GFX9 Only
std::vector<std::string> perfcounters;
};
namespace hsa
{
class AQLPacket;
};
class ThreadTracer
{
public:
ThreadTracer(std::shared_ptr<thread_trace_parameters>& _params)
: params(_params){};
virtual void start_context();
virtual void stop_context();
virtual void resource_init(const hsa::AgentCache&, const CoreApiTable&, const AmdExtTable&);
virtual void resource_deinit(const hsa::AgentCache&);
virtual ~ThreadTracer() = default;
std::shared_ptr<thread_trace_parameters> params;
std::mutex trace_resources_mut;
std::unordered_map<uint64_t, std::unique_ptr<hsa::AQLPacket>> resources;
std::unordered_map<uint64_t, std::atomic<int>> agent_active_queues;
}; // namespace thread_trace
} // namespace rocprofiler
+81
Zobrazit soubor
@@ -0,0 +1,81 @@
// MIT License
//
// Copyright (c) 2024 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.
#include <rocprofiler-sdk/rocprofiler.h>
#include "lib/rocprofiler-sdk/aql/helpers.hpp"
#include "lib/rocprofiler-sdk/context/context.hpp"
#include "lib/rocprofiler-sdk/hsa/agent_cache.hpp"
extern "C" {
/**
* @brief Configure buffered dispatch profile Counting Service.
* Collects the counters in dispatch packets and stores them
* in buffer_id. The buffer may contain packets from more than
* one dispatch (denoted by correlation id). Will trigger the
* callback based on the parameters setup in buffer_id_t.
*
* @param [in] context_id context id
* @param [in] buffer_id id of the buffer to use for the counting service
* @param [in] profile profile config to use for dispatch
* @return ::rocprofiler_status_t
*/
rocprofiler_status_t ROCPROFILER_API
rocprofiler_configure_thread_trace_service(rocprofiler_context_id_t context_id,
rocprofiler_att_parameters_t parameters,
rocprofiler_att_dispatch_callback_t dispatch_callback,
rocprofiler_att_shader_data_callback_t shader_callback,
void* callback_userdata)
{
auto* ctx = rocprofiler::context::get_mutable_registered_context(context_id);
if(!ctx) return ROCPROFILER_STATUS_ERROR_CONTEXT_NOT_STARTED;
if(ctx->thread_trace) return ROCPROFILER_STATUS_ERROR_SERVICE_ALREADY_CONFIGURED;
if(parameters.flags.raw != 0) return ROCPROFILER_STATUS_ERROR_NOT_IMPLEMENTED;
auto thread_tracer = std::make_shared<rocprofiler::thread_trace_parameters>();
thread_tracer->context_id = context_id;
thread_tracer->dispatch_cb_fn = dispatch_callback;
thread_tracer->shader_cb_fn = shader_callback;
thread_tracer->callback_userdata = callback_userdata;
thread_tracer->flags = parameters.flags;
thread_tracer->buffer_size = parameters.buffer_size;
thread_tracer->target_cu = parameters.target_cu;
thread_tracer->simd_select = parameters.simd_select;
thread_tracer->vmid_mask = parameters.vmid_mask;
thread_tracer->perfcounter_mask = parameters.perfcounter_mask;
thread_tracer->perfcounter_ctrl = parameters.perfcounter_ctrl;
for(int i = 0; i < parameters.perfcounter_num; i++)
thread_tracer->perfcounters.emplace_back(parameters.perfcounter[i]);
thread_tracer->shader_engine_mask = 0;
for(int i = 0; i < parameters.shader_num; i++)
thread_tracer->shader_engine_mask |= 1ul << parameters.shader_ids[i];
ctx->thread_trace = std::make_shared<rocprofiler::ThreadTracer>(thread_tracer);
return ROCPROFILER_STATUS_SUCCESS;
}
}