diff --git a/CMakeLists.txt b/CMakeLists.txt index f79fe074d..f0b8fcce9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -134,6 +134,7 @@ list(APPEND VIEW_FILES src/view/src/compute/rocprofvis_compute_workload_view.cpp src/view/src/compute/rocprofvis_compute_kernel_metric_table.cpp src/view/src/compute/rocprofvis_compute_comparison.cpp + src/view/src/compute/rocprofvis_compute_code_view.cpp src/view/src/compute/rocprofvis_compute_tester.cpp src/view/src/model/compute/rocprofvis_compute_data_model.cpp src/view/src/widgets/rocprofvis_compute_widget.cpp diff --git a/src/controller/CMakeLists.txt b/src/controller/CMakeLists.txt index d4177212c..7fc82b760 100644 --- a/src/controller/CMakeLists.txt +++ b/src/controller/CMakeLists.txt @@ -47,6 +47,7 @@ list(APPEND rocprofvis_controller_source_files src/compute/rocprofvis_controller_trace_compute.cpp src/compute/rocprofvis_controller_workload.cpp src/compute/rocprofvis_controller_kernel.cpp + src/compute/rocprofvis_controller_pc_sampling.cpp src/compute/rocprofvis_controller_metrics_container.cpp src/compute/rocprofvis_controller_roofline.cpp src/compute/rocprofvis_controller_table_compute_pivot.cpp diff --git a/src/controller/inc/rocprofvis_controller.h b/src/controller/inc/rocprofvis_controller.h index e348e53ba..c28bce24c 100644 --- a/src/controller/inc/rocprofvis_controller.h +++ b/src/controller/inc/rocprofvis_controller.h @@ -280,6 +280,16 @@ void rocprofvis_controller_metrics_container_free(rocprofvis_controller_metrics_ * @returns kRocProfVisResultSuccess or an error code. */ rocprofvis_result_t rocprofvis_controller_metric_fetch_async(rocprofvis_controller_t* controller, rocprofvis_controller_arguments_t* args, rocprofvis_controller_future_t* result, rocprofvis_controller_metrics_container_t* output); + +/* +* Fetch PC sampling data for a specific kernel and source file asynchronously. +* @param controller The controller +* @param args Input arguments (workload id, kernel id, source file id) +* @param result The future to wait on +* @param output The PC sampling handle to write to +* @returns kRocProfVisResultSuccess or an error code. +*/ +rocprofvis_result_t rocprofvis_controller_pc_sampling_fetch_async(rocprofvis_controller_t* controller, rocprofvis_controller_arguments_t* args, rocprofvis_controller_future_t* result, rocprofvis_handle_t* output); #endif /* diff --git a/src/controller/inc/rocprofvis_controller_enums.h b/src/controller/inc/rocprofvis_controller_enums.h index 377c37cc7..c4508774b 100644 --- a/src/controller/inc/rocprofvis_controller_enums.h +++ b/src/controller/inc/rocprofvis_controller_enums.h @@ -117,6 +117,8 @@ typedef enum rocprofvis_controller_object_type_t kRPVControllerObjectTypeMetricsContainer = 103, // Roofline object kRPVControllerObjectTypeRoofline = 104, + //PcSampling + kRPVControllerObjectTypePCSampling = 105, #endif } rocprofvis_controller_object_type_t; @@ -898,9 +900,58 @@ typedef enum rocprofvis_controller_kernel_properties_t : uint32_t kRPVControllerKernelDurationMax, kRPVControllerKernelDurationMedian, kRPVControllerKernelDurationMean, + kRPVControllerKernelPcSampling, __kRPVControllerKernelPropertiesLast } rocprofvis_controller_kernel_properties_t; +/* + * Pc Sampling data for kernels + */ +typedef enum rocprofvis_controller_pc_sampling_data_properties_t : uint32_t +{ + __kRPVControllerPCSamplingPropertiesFirst, + kRPVControllerPCSamplingNumSourceFiles = __kRPVControllerPCSamplingPropertiesFirst, + kRPVControllerPCSamplingSourceFileId, + kRPVControllerPCSamplingFilePath, + kRPVControllerPCSamplingSourceFileChecksum, + kRPVControllerPCSamplingNumSourceLines, + kRPVControllerPCSamplingSourceLineId, + kRPVControllerPCSamplingSourceLineSourceFileId, + kRPVControllerPCSamplingSourceLineNumber, + kRPVControllerPCSamplingSourceLineContent, + kRPVControllerPCSamplingNumCodeObjects, + kRPVControllerPCSamplingCodeObjectId, + kRPVControllerPCSamplingCodeObjectUri, + kRPVControllerPCSamplingCodeObjectChecksum, + kRPVControllerPCSamplingNumIsaLines, + kRPVControllerPCSamplingIsaLineId, + kRPVControllerPCSamplingIsaLineCodeObjectId, + kRPVControllerPCSamplingIsaLineCodeObjectOffset, + kRPVControllerPCSamplingIsaLineInstructionTypeId, + kRPVControllerPCSamplingIsaLineInstruction, + kRPVControllerPCSamplingIsaLineComment, + kRPVControllerPCSamplingNumIsaToIsaDeps, + kRPVControllerPCSamplingIsaToIsaDependentIsaLineId, + kRPVControllerPCSamplingIsaToIsaDependencyIsaLineId, + kRPVControllerPCSamplingNumIsaToSourceDeps, + kRPVControllerPCSamplingIsaToSourceIsaLineId, + kRPVControllerPCSamplingIsaToSourceSourceLineId, + kRPVControllerPCSamplingIsaToSourceDepth, + kRPVControllerPCSamplingNumStallRecords, + kRPVControllerPCSamplingStallRecordId, + kRPVControllerPCSamplingStallRecordIsaLineId, + kRPVControllerPCSamplingStallRecordDispatchId, + kRPVControllerPCSamplingStallRecordAvgActiveLanes, + kRPVControllerPCSamplingStallRecordWaveIssuedCount, + kRPVControllerPCSamplingStallRecordTotalSampleCount, + kRPVControllerPCSamplingNumStallReasonCounts, + kRPVControllerPCSamplingStallReasonRecordId, + kRPVControllerPCSamplingStallReasonTypeId, + kRPVControllerPCSamplingStallReasonCount, + __kRPVControllerPCSamplingPropertiesLast + +} rocprofvis_controller_pc_sampling_data_properties_t; + /* * Arguments for fetching metric values. */ @@ -915,6 +966,16 @@ typedef enum rocprofvis_controller_metric_arguments_t : uint32_t kRPVControllerMetricArgsMetricEntryIdIndexed, } rocprofvis_controller_metric_arguments_t; +/* + * Arguments for fetching PC sampling data for a specific source file. + */ +typedef enum rocprofvis_controller_pc_sampling_arguments_t : uint32_t +{ + kRPVControllerPcSamplingArgsWorkloadId, + kRPVControllerPcSamplingArgsKernelId, + kRPVControllerPcSamplingArgsSourceFileId, +} rocprofvis_controller_pc_sampling_arguments_t; + /* * Arguments for fetching dynamic metrics matrix (pivot table). */ diff --git a/src/controller/src/compute/rocprofvis_controller_kernel.cpp b/src/controller/src/compute/rocprofvis_controller_kernel.cpp index c86ff2276..0dd2f4e8c 100644 --- a/src/controller/src/compute/rocprofvis_controller_kernel.cpp +++ b/src/controller/src/compute/rocprofvis_controller_kernel.cpp @@ -88,6 +88,25 @@ rocprofvis_result_t Kernel::GetUInt64(rocprofvis_property_t property, uint64_t i return result; } +rocprofvis_result_t Kernel::GetObject(rocprofvis_property_t property, uint64_t index, rocprofvis_handle_t** value) +{ + (void)index; + rocprofvis_result_t result = kRocProfVisResultInvalidArgument; + if(value) + { + if(property == kRPVControllerKernelPcSampling) + { + *value = (rocprofvis_handle_t*)&m_pc_sampling_data; + result = kRocProfVisResultSuccess; + } + else + { + result = UnhandledProperty(property); + } + } + return result; +} + rocprofvis_result_t Kernel::GetString(rocprofvis_property_t property, uint64_t index, char* value, uint32_t* length) { (void)index; diff --git a/src/controller/src/compute/rocprofvis_controller_kernel.h b/src/controller/src/compute/rocprofvis_controller_kernel.h index d8ff0ad2e..10e658b29 100644 --- a/src/controller/src/compute/rocprofvis_controller_kernel.h +++ b/src/controller/src/compute/rocprofvis_controller_kernel.h @@ -5,6 +5,7 @@ #include "rocprofvis_controller_handle.h" #include "rocprofvis_c_interface_types.h" +#include "rocprofvis_controller_pc_sampling.h" #include namespace RocProfVis @@ -23,6 +24,7 @@ class Kernel : public Handle rocprofvis_result_t GetUInt64(rocprofvis_property_t property, uint64_t index, uint64_t* value) final; rocprofvis_result_t GetString(rocprofvis_property_t property, uint64_t index, char* value, uint32_t* length) final; + rocprofvis_result_t GetObject(rocprofvis_property_t property, uint64_t index, rocprofvis_handle_t** value) final; rocprofvis_result_t SetUInt64(rocprofvis_property_t property, uint64_t index, uint64_t value) final; rocprofvis_result_t SetString(rocprofvis_property_t property, uint64_t index, char const* value) final; @@ -38,6 +40,7 @@ class Kernel : public Handle uint32_t m_duration_max; uint32_t m_duration_median; uint32_t m_duration_mean; + PcSampling m_pc_sampling_data; }; } diff --git a/src/controller/src/compute/rocprofvis_controller_pc_sampling.cpp b/src/controller/src/compute/rocprofvis_controller_pc_sampling.cpp new file mode 100644 index 000000000..a3550e534 --- /dev/null +++ b/src/controller/src/compute/rocprofvis_controller_pc_sampling.cpp @@ -0,0 +1,955 @@ +// Copyright Advanced Micro Devices, Inc. +// SPDX-License-Identifier: MIT + +#include "rocprofvis_controller_pc_sampling.h" + +namespace RocProfVis +{ +namespace Controller +{ + +PcSampling::PcSampling() +: Handle(__kRPVControllerPCSamplingPropertiesFirst, __kRPVControllerPCSamplingPropertiesLast) +{} + +PcSampling::~PcSampling() {} + +rocprofvis_controller_object_type_t PcSampling::GetType(void) +{ + return kRPVControllerObjectTypePCSampling; +} + +rocprofvis_result_t PcSampling::GetUInt64(rocprofvis_property_t property, uint64_t index, uint64_t* value) +{ + rocprofvis_result_t result = kRocProfVisResultInvalidArgument; + if(value) + { + switch(property) + { + case kRPVControllerPCSamplingNumSourceFiles: + { + (void)index; + *value = m_source_files.size(); + result = kRocProfVisResultSuccess; + break; + } + case kRPVControllerPCSamplingSourceFileId: + { + if(index < m_source_files.size()) + { + *value = m_source_files[index].id; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingNumSourceLines: + { + (void)index; + *value = m_source_lines.size(); + result = kRocProfVisResultSuccess; + break; + } + case kRPVControllerPCSamplingSourceLineId: + { + if(index < m_source_lines.size()) + { + *value = m_source_lines[index].id; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingSourceLineSourceFileId: + { + if(index < m_source_lines.size()) + { + *value = m_source_lines[index].source_file_id; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingSourceLineNumber: + { + if(index < m_source_lines.size()) + { + *value = m_source_lines[index].line_number; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingNumCodeObjects: + { + (void)index; + *value = m_code_objects.size(); + result = kRocProfVisResultSuccess; + break; + } + case kRPVControllerPCSamplingCodeObjectId: + { + if(index < m_code_objects.size()) + { + *value = m_code_objects[index].id; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingNumIsaLines: + { + (void)index; + *value = m_isa_lines.size(); + result = kRocProfVisResultSuccess; + break; + } + case kRPVControllerPCSamplingIsaLineId: + { + if(index < m_isa_lines.size()) + { + *value = m_isa_lines[index].id; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingIsaLineCodeObjectId: + { + if(index < m_isa_lines.size()) + { + *value = m_isa_lines[index].code_object_id; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingIsaLineCodeObjectOffset: + { + if(index < m_isa_lines.size()) + { + *value = m_isa_lines[index].code_object_offset; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingIsaLineInstructionTypeId: + { + if(index < m_isa_lines.size()) + { + *value = m_isa_lines[index].instruction_type_id; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingNumIsaToIsaDeps: + { + (void)index; + *value = m_isa_to_isa_deps.size(); + result = kRocProfVisResultSuccess; + break; + } + case kRPVControllerPCSamplingIsaToIsaDependentIsaLineId: + { + if(index < m_isa_to_isa_deps.size()) + { + *value = m_isa_to_isa_deps[index].dependent_isa_line_id; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingIsaToIsaDependencyIsaLineId: + { + if(index < m_isa_to_isa_deps.size()) + { + *value = m_isa_to_isa_deps[index].dependency_isa_line_id; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingNumIsaToSourceDeps: + { + (void)index; + *value = m_isa_to_source_deps.size(); + result = kRocProfVisResultSuccess; + break; + } + case kRPVControllerPCSamplingIsaToSourceIsaLineId: + { + if(index < m_isa_to_source_deps.size()) + { + *value = m_isa_to_source_deps[index].isa_line_id; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingIsaToSourceSourceLineId: + { + if(index < m_isa_to_source_deps.size()) + { + *value = m_isa_to_source_deps[index].source_line_id; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingIsaToSourceDepth: + { + if(index < m_isa_to_source_deps.size()) + { + *value = m_isa_to_source_deps[index].depth; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingNumStallRecords: + { + (void)index; + *value = m_stall_records.size(); + result = kRocProfVisResultSuccess; + break; + } + case kRPVControllerPCSamplingStallRecordId: + { + if(index < m_stall_records.size()) + { + *value = m_stall_records[index].id; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingStallRecordIsaLineId: + { + if(index < m_stall_records.size()) + { + *value = m_stall_records[index].isa_line_id; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingStallRecordDispatchId: + { + if(index < m_stall_records.size()) + { + *value = m_stall_records[index].dispatch_id; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingStallRecordWaveIssuedCount: + { + if(index < m_stall_records.size()) + { + *value = m_stall_records[index].wave_issued_count; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingStallRecordTotalSampleCount: + { + if(index < m_stall_records.size()) + { + *value = m_stall_records[index].total_sample_count; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingNumStallReasonCounts: + { + (void)index; + *value = m_stall_reason_counts.size(); + result = kRocProfVisResultSuccess; + break; + } + case kRPVControllerPCSamplingStallReasonRecordId: + { + if(index < m_stall_reason_counts.size()) + { + *value = m_stall_reason_counts[index].record_id; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingStallReasonTypeId: + { + if(index < m_stall_reason_counts.size()) + { + *value = m_stall_reason_counts[index].type_id; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingStallReasonCount: + { + if(index < m_stall_reason_counts.size()) + { + *value = m_stall_reason_counts[index].count; + result = kRocProfVisResultSuccess; + } + break; + } + default: + { + result = UnhandledProperty(property); + break; + } + } + } + return result; +} + +rocprofvis_result_t PcSampling::SetUInt64(rocprofvis_property_t property, uint64_t index, uint64_t value) +{ + rocprofvis_result_t result = kRocProfVisResultInvalidArgument; + switch(property) + { + case kRPVControllerPCSamplingNumSourceFiles: + { + (void)index; + m_source_files.resize(value); + result = kRocProfVisResultSuccess; + break; + } + case kRPVControllerPCSamplingSourceFileId: + { + if(index < m_source_files.size()) + { + m_source_files[index].id = static_cast(value); + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingNumSourceLines: + { + (void)index; + m_source_lines.resize(value); + result = kRocProfVisResultSuccess; + break; + } + case kRPVControllerPCSamplingSourceLineId: + { + if(index < m_source_lines.size()) + { + m_source_lines[index].id = static_cast(value); + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingSourceLineSourceFileId: + { + if(index < m_source_lines.size()) + { + m_source_lines[index].source_file_id = static_cast(value); + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingSourceLineNumber: + { + if(index < m_source_lines.size()) + { + m_source_lines[index].line_number = static_cast(value); + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingNumCodeObjects: + { + (void)index; + m_code_objects.resize(value); + result = kRocProfVisResultSuccess; + break; + } + case kRPVControllerPCSamplingCodeObjectId: + { + if(index < m_code_objects.size()) + { + m_code_objects[index].id = static_cast(value); + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingNumIsaLines: + { + (void)index; + m_isa_lines.resize(value); + result = kRocProfVisResultSuccess; + break; + } + case kRPVControllerPCSamplingIsaLineId: + { + if(index < m_isa_lines.size()) + { + m_isa_lines[index].id = static_cast(value); + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingIsaLineCodeObjectId: + { + if(index < m_isa_lines.size()) + { + m_isa_lines[index].code_object_id = static_cast(value); + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingIsaLineCodeObjectOffset: + { + if(index < m_isa_lines.size()) + { + m_isa_lines[index].code_object_offset = value; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingIsaLineInstructionTypeId: + { + if(index < m_isa_lines.size()) + { + m_isa_lines[index].instruction_type_id = static_cast(value); + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingNumIsaToIsaDeps: + { + (void)index; + m_isa_to_isa_deps.resize(value); + result = kRocProfVisResultSuccess; + break; + } + case kRPVControllerPCSamplingIsaToIsaDependentIsaLineId: + { + if(index < m_isa_to_isa_deps.size()) + { + m_isa_to_isa_deps[index].dependent_isa_line_id = static_cast(value); + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingIsaToIsaDependencyIsaLineId: + { + if(index < m_isa_to_isa_deps.size()) + { + m_isa_to_isa_deps[index].dependency_isa_line_id = static_cast(value); + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingNumIsaToSourceDeps: + { + (void)index; + m_isa_to_source_deps.resize(value); + result = kRocProfVisResultSuccess; + break; + } + case kRPVControllerPCSamplingIsaToSourceIsaLineId: + { + if(index < m_isa_to_source_deps.size()) + { + m_isa_to_source_deps[index].isa_line_id = static_cast(value); + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingIsaToSourceSourceLineId: + { + if(index < m_isa_to_source_deps.size()) + { + m_isa_to_source_deps[index].source_line_id = static_cast(value); + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingIsaToSourceDepth: + { + if(index < m_isa_to_source_deps.size()) + { + m_isa_to_source_deps[index].depth = static_cast(value); + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingNumStallRecords: + { + (void)index; + m_stall_records.resize(value); + result = kRocProfVisResultSuccess; + break; + } + case kRPVControllerPCSamplingStallRecordId: + { + if(index < m_stall_records.size()) + { + m_stall_records[index].id = static_cast(value); + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingStallRecordIsaLineId: + { + if(index < m_stall_records.size()) + { + m_stall_records[index].isa_line_id = static_cast(value); + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingStallRecordDispatchId: + { + if(index < m_stall_records.size()) + { + m_stall_records[index].dispatch_id = value; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingStallRecordWaveIssuedCount: + { + if(index < m_stall_records.size()) + { + m_stall_records[index].wave_issued_count = static_cast(value); + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingStallRecordTotalSampleCount: + { + if(index < m_stall_records.size()) + { + m_stall_records[index].total_sample_count = static_cast(value); + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingNumStallReasonCounts: + { + (void)index; + m_stall_reason_counts.resize(value); + result = kRocProfVisResultSuccess; + break; + } + case kRPVControllerPCSamplingStallReasonRecordId: + { + if(index < m_stall_reason_counts.size()) + { + m_stall_reason_counts[index].record_id = static_cast(value); + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingStallReasonTypeId: + { + if(index < m_stall_reason_counts.size()) + { + m_stall_reason_counts[index].type_id = static_cast(value); + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingStallReasonCount: + { + if(index < m_stall_reason_counts.size()) + { + m_stall_reason_counts[index].count = static_cast(value); + result = kRocProfVisResultSuccess; + } + break; + } + default: + { + result = UnhandledProperty(property); + break; + } + } + return result; +} + +rocprofvis_result_t PcSampling::GetDouble(rocprofvis_property_t property, uint64_t index, double* value) +{ + rocprofvis_result_t result = kRocProfVisResultInvalidArgument; + if(value) + { + switch(property) + { + case kRPVControllerPCSamplingStallRecordAvgActiveLanes: + { + if(index < m_stall_records.size()) + { + *value = static_cast(m_stall_records[index].avg_active_lanes); + result = kRocProfVisResultSuccess; + } + break; + } + default: + { + result = UnhandledProperty(property); + break; + } + } + } + return result; +} + +rocprofvis_result_t PcSampling::SetDouble(rocprofvis_property_t property, uint64_t index, double value) +{ + rocprofvis_result_t result = kRocProfVisResultInvalidArgument; + switch(property) + { + case kRPVControllerPCSamplingStallRecordAvgActiveLanes: + { + if(index < m_stall_records.size()) + { + m_stall_records[index].avg_active_lanes = static_cast(value); + result = kRocProfVisResultSuccess; + } + break; + } + default: + { + result = UnhandledProperty(property); + break; + } + } + return result; +} + +rocprofvis_result_t PcSampling::GetString(rocprofvis_property_t property, uint64_t index, char* value, uint32_t* length) +{ + rocprofvis_result_t result = kRocProfVisResultInvalidArgument; + if(length) + { + switch(property) + { + case kRPVControllerPCSamplingFilePath: + { + if(index < m_source_files.size()) + { + result = GetStdStringImpl(value, length, m_source_files[index].file_path); + } + break; + } + case kRPVControllerPCSamplingSourceFileChecksum: + { + if(index < m_source_files.size()) + { + result = GetStdStringImpl(value, length, m_source_files[index].content_checksum); + } + break; + } + case kRPVControllerPCSamplingSourceLineContent: + { + if(index < m_source_lines.size()) + { + result = GetStdStringImpl(value, length, m_source_lines[index].content); + } + break; + } + case kRPVControllerPCSamplingCodeObjectUri: + { + if(index < m_code_objects.size()) + { + result = GetStdStringImpl(value, length, m_code_objects[index].uri); + } + break; + } + case kRPVControllerPCSamplingCodeObjectChecksum: + { + if(index < m_code_objects.size()) + { + result = GetStdStringImpl(value, length, m_code_objects[index].content_checksum); + } + break; + } + case kRPVControllerPCSamplingIsaLineInstruction: + { + if(index < m_isa_lines.size()) + { + result = GetStdStringImpl(value, length, m_isa_lines[index].instruction); + } + break; + } + case kRPVControllerPCSamplingIsaLineComment: + { + if(index < m_isa_lines.size()) + { + result = GetStdStringImpl(value, length, m_isa_lines[index].comment); + } + break; + } + default: + { + result = UnhandledProperty(property); + break; + } + } + } + return result; +} + +rocprofvis_result_t PcSampling::SetString(rocprofvis_property_t property, uint64_t index, char const* value) +{ + rocprofvis_result_t result = kRocProfVisResultInvalidArgument; + switch(property) + { + case kRPVControllerPCSamplingFilePath: + { + if(index < m_source_files.size()) + { + m_source_files[index].file_path = value; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingSourceFileChecksum: + { + if(index < m_source_files.size()) + { + m_source_files[index].content_checksum = value; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingSourceLineContent: + { + if(index < m_source_lines.size()) + { + m_source_lines[index].content = value; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingCodeObjectUri: + { + if(index < m_code_objects.size()) + { + m_code_objects[index].uri = value; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingCodeObjectChecksum: + { + if(index < m_code_objects.size()) + { + m_code_objects[index].content_checksum = value; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingIsaLineInstruction: + { + if(index < m_isa_lines.size()) + { + m_isa_lines[index].instruction = value; + result = kRocProfVisResultSuccess; + } + break; + } + case kRPVControllerPCSamplingIsaLineComment: + { + if(index < m_isa_lines.size()) + { + m_isa_lines[index].comment = value; + result = kRocProfVisResultSuccess; + } + break; + } + default: + { + result = UnhandledProperty(property); + break; + } + } + return result; +} + +bool PcSampling::QueryToPropertyEnum(rocprofvis_db_compute_column_enum_t in, rocprofvis_property_t& property, rocprofvis_controller_primitive_type_t& type) const +{ + bool valid = true; + switch(in) + { + case kRPVComputeColumnPcSamplingSourceFileId: + { + property = kRPVControllerPCSamplingSourceFileId; + type = kRPVControllerPrimitiveTypeUInt64; + break; + } + case kRPVComputeColumnPcSamplingSourceFilePath: + { + property = kRPVControllerPCSamplingFilePath; + type = kRPVControllerPrimitiveTypeString; + break; + } + case kRPVComputeColumnPcSamplingSourceFileChecksum: + { + property = kRPVControllerPCSamplingSourceFileChecksum; + type = kRPVControllerPrimitiveTypeString; + break; + } + case kRPVComputeColumnPcSamplingSourceLineId: + { + property = kRPVControllerPCSamplingSourceLineId; + type = kRPVControllerPrimitiveTypeUInt64; + break; + } + case kRPVComputeColumnPcSamplingSourceLineFileId: + { + property = kRPVControllerPCSamplingSourceLineSourceFileId; + type = kRPVControllerPrimitiveTypeUInt64; + break; + } + case kRPVComputeColumnPcSamplingSourceLineNumber: + { + property = kRPVControllerPCSamplingSourceLineNumber; + type = kRPVControllerPrimitiveTypeUInt64; + break; + } + case kRPVComputeColumnPcSamplingSourceLineContent: + { + property = kRPVControllerPCSamplingSourceLineContent; + type = kRPVControllerPrimitiveTypeString; + break; + } + case kRPVComputeColumnPcSamplingCodeObjectId: + { + property = kRPVControllerPCSamplingCodeObjectId; + type = kRPVControllerPrimitiveTypeUInt64; + break; + } + case kRPVComputeColumnPcSamplingCodeObjectUri: + { + property = kRPVControllerPCSamplingCodeObjectUri; + type = kRPVControllerPrimitiveTypeString; + break; + } + case kRPVComputeColumnPcSamplingCodeObjectChecksum: + { + property = kRPVControllerPCSamplingCodeObjectChecksum; + type = kRPVControllerPrimitiveTypeString; + break; + } + case kRPVComputeColumnPcSamplingIsaLineId: + { + property = kRPVControllerPCSamplingIsaLineId; + type = kRPVControllerPrimitiveTypeUInt64; + break; + } + case kRPVComputeColumnPcSamplingIsaLineCodeObjectId: + { + property = kRPVControllerPCSamplingIsaLineCodeObjectId; + type = kRPVControllerPrimitiveTypeUInt64; + break; + } + case kRPVComputeColumnPcSamplingIsaLineCodeObjectOffset: + { + property = kRPVControllerPCSamplingIsaLineCodeObjectOffset; + type = kRPVControllerPrimitiveTypeUInt64; + break; + } + case kRPVComputeColumnPcSamplingIsaLineInstructionTypeId: + { + property = kRPVControllerPCSamplingIsaLineInstructionTypeId; + type = kRPVControllerPrimitiveTypeUInt64; + break; + } + case kRPVComputeColumnPcSamplingIsaLineInstruction: + { + property = kRPVControllerPCSamplingIsaLineInstruction; + type = kRPVControllerPrimitiveTypeString; + break; + } + case kRPVComputeColumnPcSamplingIsaLineComment: + { + property = kRPVControllerPCSamplingIsaLineComment; + type = kRPVControllerPrimitiveTypeString; + break; + } + case kRPVComputeColumnPcSamplingIsaToIsaDependentIsaLineId: + { + property = kRPVControllerPCSamplingIsaToIsaDependentIsaLineId; + type = kRPVControllerPrimitiveTypeUInt64; + break; + } + case kRPVComputeColumnPcSamplingIsaToIsaDependencyIsaLineId: + { + property = kRPVControllerPCSamplingIsaToIsaDependencyIsaLineId; + type = kRPVControllerPrimitiveTypeUInt64; + break; + } + case kRPVComputeColumnPcSamplingIsaToSourceIsaLineId: + { + property = kRPVControllerPCSamplingIsaToSourceIsaLineId; + type = kRPVControllerPrimitiveTypeUInt64; + break; + } + case kRPVComputeColumnPcSamplingIsaToSourceSourceLineId: + { + property = kRPVControllerPCSamplingIsaToSourceSourceLineId; + type = kRPVControllerPrimitiveTypeUInt64; + break; + } + case kRPVComputeColumnPcSamplingIsaToSourceDepth: + { + property = kRPVControllerPCSamplingIsaToSourceDepth; + type = kRPVControllerPrimitiveTypeUInt64; + break; + } + case kRPVComputeColumnPcSamplingStallRecordId: + { + property = kRPVControllerPCSamplingStallRecordId; + type = kRPVControllerPrimitiveTypeUInt64; + break; + } + case kRPVComputeColumnPcSamplingStallRecordIsaLineId: + { + property = kRPVControllerPCSamplingStallRecordIsaLineId; + type = kRPVControllerPrimitiveTypeUInt64; + break; + } + case kRPVComputeColumnPcSamplingStallRecordDispatchId: + { + property = kRPVControllerPCSamplingStallRecordDispatchId; + type = kRPVControllerPrimitiveTypeUInt64; + break; + } + case kRPVComputeColumnPcSamplingStallRecordAvgActiveLanes: + { + property = kRPVControllerPCSamplingStallRecordAvgActiveLanes; + type = kRPVControllerPrimitiveTypeDouble; + break; + } + case kRPVComputeColumnPcSamplingStallRecordWaveIssuedCount: + { + property = kRPVControllerPCSamplingStallRecordWaveIssuedCount; + type = kRPVControllerPrimitiveTypeUInt64; + break; + } + case kRPVComputeColumnPcSamplingStallRecordTotalSampleCount: + { + property = kRPVControllerPCSamplingStallRecordTotalSampleCount; + type = kRPVControllerPrimitiveTypeUInt64; + break; + } + case kRPVComputeColumnPcSamplingStallReasonRecordId: + { + property = kRPVControllerPCSamplingStallReasonRecordId; + type = kRPVControllerPrimitiveTypeUInt64; + break; + } + case kRPVComputeColumnPcSamplingStallReasonTypeId: + { + property = kRPVControllerPCSamplingStallReasonTypeId; + type = kRPVControllerPrimitiveTypeUInt64; + break; + } + case kRPVComputeColumnPcSamplingStallReasonCount: + { + property = kRPVControllerPCSamplingStallReasonCount; + type = kRPVControllerPrimitiveTypeUInt64; + break; + } + default: + { + valid = false; + break; + } + } + return valid; +} + +} +} diff --git a/src/controller/src/compute/rocprofvis_controller_pc_sampling.h b/src/controller/src/compute/rocprofvis_controller_pc_sampling.h new file mode 100644 index 000000000..05c3f56be --- /dev/null +++ b/src/controller/src/compute/rocprofvis_controller_pc_sampling.h @@ -0,0 +1,103 @@ +// Copyright Advanced Micro Devices, Inc. +// SPDX-License-Identifier: MIT + +#pragma once + +#include "rocprofvis_controller_handle.h" +#include "rocprofvis_c_interface_types.h" +#include +#include + +namespace RocProfVis +{ +namespace Controller +{ + +class PcSampling : public Handle +{ +public: + PcSampling(); + virtual ~PcSampling(); + + rocprofvis_controller_object_type_t GetType(void) final; + + rocprofvis_result_t GetUInt64(rocprofvis_property_t property, uint64_t index, uint64_t* value) final; + rocprofvis_result_t GetString(rocprofvis_property_t property, uint64_t index, char* value, uint32_t* length) final; + + rocprofvis_result_t SetUInt64(rocprofvis_property_t property, uint64_t index, uint64_t value) final; + rocprofvis_result_t SetDouble(rocprofvis_property_t property, uint64_t index, double value) final; + rocprofvis_result_t GetDouble(rocprofvis_property_t property, uint64_t index, double* value) final; + rocprofvis_result_t SetString(rocprofvis_property_t property, uint64_t index, char const* value) final; + + bool QueryToPropertyEnum(rocprofvis_db_compute_column_enum_t in, rocprofvis_property_t& property, rocprofvis_controller_primitive_type_t& type) const; + +private: + struct SourceLine + { + uint32_t id = 0; + uint32_t source_file_id = 0; + uint32_t line_number = 0; + std::string content; + }; + struct SourceFile + { + uint32_t id = 0; + std::string file_path; + std::string content_checksum; + }; + struct IsaLine + { + uint32_t id = 0; + uint32_t code_object_id = 0; + uint64_t code_object_offset = 0; + uint32_t instruction_type_id = 0; + std::string instruction; + std::string comment; + }; + struct CodeObject + { + uint32_t id = 0; + std::string uri; + std::string content_checksum; + }; + struct IsaToIsaDep + { + uint32_t dependent_isa_line_id = 0; + uint32_t dependency_isa_line_id = 0; + }; + struct IsaToSourceDep + { + uint32_t isa_line_id = 0; + uint32_t source_line_id = 0; + uint32_t depth = 0; + }; + struct StallRecord + { + uint32_t id = 0; + uint32_t isa_line_id = 0; + uint64_t dispatch_id = 0; + float avg_active_lanes = 0.0f; + uint32_t wave_issued_count = 0; + uint32_t total_sample_count = 0; + }; + struct StallReasonCount + { + uint32_t record_id = 0; + uint32_t type_id = 0; + uint32_t count = 0; + }; + + std::vector m_source_files; + std::vector m_source_lines; + std::vector m_code_objects; + std::vector m_isa_lines; + std::vector m_isa_to_isa_deps; + std::vector m_isa_to_source_deps; + std::vector m_stall_records; + std::vector m_stall_reason_counts; + +}; + + +} +} diff --git a/src/controller/src/compute/rocprofvis_controller_trace_compute.cpp b/src/controller/src/compute/rocprofvis_controller_trace_compute.cpp index 34ef5e7cd..9599e04c7 100644 --- a/src/controller/src/compute/rocprofvis_controller_trace_compute.cpp +++ b/src/controller/src/compute/rocprofvis_controller_trace_compute.cpp @@ -8,6 +8,8 @@ #include "rocprofvis_controller_kernel.h" #include "rocprofvis_controller_roofline.h" #include "rocprofvis_controller_future.h" +#include "rocprofvis_controller_reference.h" +#include "rocprofvis_controller_pc_sampling.h" #include "rocprofvis_core_assert.h" #include "rocprofvis_controller_table_compute_pivot.h" #include "json.h" @@ -20,6 +22,8 @@ namespace RocProfVis namespace Controller { +typedef Reference PcSamplingRef; + ComputeTrace::ComputeTrace(const std::string& filename) : Trace(__kRPVControllerComputePropertiesFirst, __kRPVControllerComputePropertiesLast, filename) @@ -309,6 +313,256 @@ rocprofvis_result_t ComputeTrace::AsyncFetch(Table& table, Arguments& args, Futu return error; } + +rocprofvis_result_t ComputeTrace::AsyncFetchPcSampling(Arguments& args, Future& future, PcSampling& output) +{ + uint64_t workload_id = 0; + uint64_t kernel_id = 0; + uint64_t source_file_id = 0; + + if(kRocProfVisResultSuccess != args.GetUInt64(kRPVControllerPcSamplingArgsWorkloadId, 0, &workload_id) || + kRocProfVisResultSuccess != args.GetUInt64(kRPVControllerPcSamplingArgsKernelId, 0, &kernel_id) || + kRocProfVisResultSuccess != args.GetUInt64(kRPVControllerPcSamplingArgsSourceFileId, 0, &source_file_id)) + { + return kRocProfVisResultInvalidArgument; + } + + future.Set(JobSystem::Get().IssueJob([this, &output, kernel_id, source_file_id](Future* future) -> rocprofvis_result_t { + rocprofvis_dm_database_t db = rocprofvis_dm_get_property_as_handle(m_dm_handle, kRPVDMDatabaseHandle, 0); + + FetchCodeObjectsAndIsaLines(db, future, kernel_id, output); + FetchIsaLineDepsAndStalls(db, future, output); + FetchSourceFileAndLines(db, future, source_file_id, output); + + if(future->IsCancelled()) + return kRocProfVisResultCancelled; + return kRocProfVisResultSuccess; + }, &future)); + + return future.IsValid() ? kRocProfVisResultSuccess : kRocProfVisResultUnknownError; +} + + +void +ComputeTrace::FetchCodeObjectsAndIsaLines(rocprofvis_dm_database_t db, Future* future, + uint64_t kernel_id, PcSampling& output) +{ + QueryArgumentStore query_args = { {kRPVComputeParamKernelId, std::to_string(kernel_id)} }; + QueryDataStore query_out = { + { + { kRPVComputeColumnPcSamplingCodeObjectId, std::nullopt }, + { kRPVComputeColumnPcSamplingCodeObjectUri, std::nullopt }, + { kRPVComputeColumnPcSamplingCodeObjectChecksum, std::nullopt }, + }, {} + }; + ExecuteQuery(db, m_dm_handle, nullptr, future, kRPVComputeFetchKernelCodeObjects, query_args, query_out, + [this, &output](const QueryDataStore& data_store){ + output.SetUInt64(kRPVControllerPCSamplingNumCodeObjects, 0, data_store.rows.size()); + rocprofvis_property_t property; + rocprofvis_controller_primitive_type_t type; + for(size_t i = 0; i < data_store.rows.size(); i++) + for(const auto& column : data_store.columns) + if(output.QueryToPropertyEnum(column.first, property, type)) + SetObjectProperty((rocprofvis_handle_t*)&output, property, i, data_store.rows[i][column.second.value()], type); + }); + + uint64_t num_code_objects = 0; + output.GetUInt64(kRPVControllerPCSamplingNumCodeObjects, 0, &num_code_objects); + uint64_t isa_offset = 0; + for(uint64_t ci = 0; ci < num_code_objects; ci++) + { + uint64_t code_object_id = 0; + output.GetUInt64(kRPVControllerPCSamplingCodeObjectId, ci, &code_object_id); + query_args = { {kRPVComputeParamCodeObjectId, std::to_string(code_object_id)} }; + query_out = { + { + { kRPVComputeColumnPcSamplingIsaLineId, std::nullopt }, + { kRPVComputeColumnPcSamplingIsaLineCodeObjectId, std::nullopt }, + { kRPVComputeColumnPcSamplingIsaLineCodeObjectOffset, std::nullopt }, + { kRPVComputeColumnPcSamplingIsaLineInstructionTypeId,std::nullopt }, + { kRPVComputeColumnPcSamplingIsaLineInstruction, std::nullopt }, + { kRPVComputeColumnPcSamplingIsaLineComment, std::nullopt }, + }, {} + }; + ExecuteQuery(db, m_dm_handle, nullptr, future, kRPVComputeFetchCodeObjectIsaLines, query_args, query_out, + [this, &output, &isa_offset](const QueryDataStore& data_store){ + output.SetUInt64(kRPVControllerPCSamplingNumIsaLines, 0, isa_offset + data_store.rows.size()); + rocprofvis_property_t property; + rocprofvis_controller_primitive_type_t type; + for(size_t i = 0; i < data_store.rows.size(); i++) + for(const auto& column : data_store.columns) + if(output.QueryToPropertyEnum(column.first, property, type)) + SetObjectProperty((rocprofvis_handle_t*)&output, property, isa_offset + i, data_store.rows[i][column.second.value()], type); + isa_offset += data_store.rows.size(); + }); + } +} + +void +ComputeTrace::FetchIsaLineDepsAndStalls(rocprofvis_dm_database_t db, Future* future, PcSampling& output) +{ + uint64_t num_isa_lines = 0; + output.GetUInt64(kRPVControllerPCSamplingNumIsaLines, 0, &num_isa_lines); + + uint64_t isa_to_isa_offset = 0, isa_to_source_offset = 0, stall_offset = 0; + for(uint64_t ii = 0; ii < num_isa_lines; ii++) + { + uint64_t isa_line_id = 0; + output.GetUInt64(kRPVControllerPCSamplingIsaLineId, ii, &isa_line_id); + + QueryArgumentStore query_args = { {kRPVComputeParamIsaLineId, std::to_string(isa_line_id)} }; + QueryDataStore query_out = { + { + { kRPVComputeColumnPcSamplingIsaToIsaDependentIsaLineId, std::nullopt }, + { kRPVComputeColumnPcSamplingIsaToIsaDependencyIsaLineId, std::nullopt }, + }, {} + }; + ExecuteQuery(db, m_dm_handle, nullptr, future, kRPVComputeFetchIsaLineIsaLineDeps, query_args, query_out, + [this, &output, &isa_to_isa_offset](const QueryDataStore& data_store){ + output.SetUInt64(kRPVControllerPCSamplingNumIsaToIsaDeps, 0, isa_to_isa_offset + data_store.rows.size()); + rocprofvis_property_t property; + rocprofvis_controller_primitive_type_t type; + for(size_t i = 0; i < data_store.rows.size(); i++) + for(const auto& column : data_store.columns) + if(output.QueryToPropertyEnum(column.first, property, type)) + SetObjectProperty((rocprofvis_handle_t*)&output, property, isa_to_isa_offset + i, data_store.rows[i][column.second.value()], type); + isa_to_isa_offset += data_store.rows.size(); + }); + + query_args = { {kRPVComputeParamIsaLineId, std::to_string(isa_line_id)} }; + query_out = { + { + { kRPVComputeColumnPcSamplingIsaToSourceIsaLineId, std::nullopt }, + { kRPVComputeColumnPcSamplingIsaToSourceSourceLineId, std::nullopt }, + { kRPVComputeColumnPcSamplingIsaToSourceDepth, std::nullopt }, + }, {} + }; + ExecuteQuery(db, m_dm_handle, nullptr, future, kRPVComputeFetchIsaLineSourceLineDeps, query_args, query_out, + [this, &output, &isa_to_source_offset](const QueryDataStore& data_store){ + output.SetUInt64(kRPVControllerPCSamplingNumIsaToSourceDeps, 0, isa_to_source_offset + data_store.rows.size()); + rocprofvis_property_t property; + rocprofvis_controller_primitive_type_t type; + for(size_t i = 0; i < data_store.rows.size(); i++) + for(const auto& column : data_store.columns) + if(output.QueryToPropertyEnum(column.first, property, type)) + SetObjectProperty((rocprofvis_handle_t*)&output, property, isa_to_source_offset + i, data_store.rows[i][column.second.value()], type); + isa_to_source_offset += data_store.rows.size(); + }); + + query_args = { {kRPVComputeParamIsaLineId, std::to_string(isa_line_id)} }; + query_out = { + { + { kRPVComputeColumnPcSamplingStallRecordId, std::nullopt }, + { kRPVComputeColumnPcSamplingStallRecordIsaLineId, std::nullopt }, + { kRPVComputeColumnPcSamplingStallRecordDispatchId, std::nullopt }, + { kRPVComputeColumnPcSamplingStallRecordAvgActiveLanes, std::nullopt }, + { kRPVComputeColumnPcSamplingStallRecordWaveIssuedCount, std::nullopt }, + { kRPVComputeColumnPcSamplingStallRecordTotalSampleCount,std::nullopt }, + }, {} + }; + ExecuteQuery(db, m_dm_handle, nullptr, future, kRPVComputeFetchIsaLineStallRecord, query_args, query_out, + [this, &output, &stall_offset](const QueryDataStore& data_store){ + output.SetUInt64(kRPVControllerPCSamplingNumStallRecords, 0, stall_offset + data_store.rows.size()); + rocprofvis_property_t property; + rocprofvis_controller_primitive_type_t type; + for(size_t i = 0; i < data_store.rows.size(); i++) + for(const auto& column : data_store.columns) + if(output.QueryToPropertyEnum(column.first, property, type)) + SetObjectProperty((rocprofvis_handle_t*)&output, property, stall_offset + i, data_store.rows[i][column.second.value()], type); + stall_offset += data_store.rows.size(); + }); + + FetchStallReasonCounts(db, future, output); + } +} + +void +ComputeTrace::FetchStallReasonCounts(rocprofvis_dm_database_t db, Future* future, PcSampling& output) +{ + uint64_t num_stall_records = 0; + output.GetUInt64(kRPVControllerPCSamplingNumStallRecords, 0, &num_stall_records); + + uint64_t stall_reason_offset = 0; + for(uint64_t si = 0; si < num_stall_records; si++) + { + uint64_t stall_record_id = 0; + output.GetUInt64(kRPVControllerPCSamplingStallRecordId, si, &stall_record_id); + + QueryArgumentStore query_args = { {kRPVComputeParamStallRecordId, std::to_string(stall_record_id)} }; + QueryDataStore query_out = { + { + { kRPVComputeColumnPcSamplingStallReasonRecordId, std::nullopt }, + { kRPVComputeColumnPcSamplingStallReasonTypeId, std::nullopt }, + { kRPVComputeColumnPcSamplingStallReasonCount, std::nullopt }, + }, {} + }; + ExecuteQuery(db, m_dm_handle, nullptr, future, kRPVComputeFetchStallRecordReasonCounts, query_args, query_out, + [this, &output, &stall_reason_offset](const QueryDataStore& data_store){ + output.SetUInt64(kRPVControllerPCSamplingNumStallReasonCounts, 0, stall_reason_offset + data_store.rows.size()); + rocprofvis_property_t property; + rocprofvis_controller_primitive_type_t type; + for(size_t i = 0; i < data_store.rows.size(); i++) + for(const auto& column : data_store.columns) + if(output.QueryToPropertyEnum(column.first, property, type)) + SetObjectProperty((rocprofvis_handle_t*)&output, property, stall_reason_offset + i, data_store.rows[i][column.second.value()], type); + stall_reason_offset += data_store.rows.size(); + }); + } +} + +void +ComputeTrace::FetchSourceFileAndLines(rocprofvis_dm_database_t db, Future* future, + uint64_t source_file_id, PcSampling& output) +{ + QueryArgumentStore query_args = { {kRPVComputeParamSourceFileId, std::to_string(source_file_id)} }; + QueryDataStore query_out = { + { + { kRPVComputeColumnPcSamplingSourceFileId, std::nullopt }, + { kRPVComputeColumnPcSamplingSourceFilePath, std::nullopt }, + { kRPVComputeColumnPcSamplingSourceFileChecksum, std::nullopt }, + }, {} + }; + ExecuteQuery(db, m_dm_handle, nullptr, future, kRPVComputeFetchKernelSourceFiles, query_args, query_out, + [this, &output](const QueryDataStore& data_store){ + output.SetUInt64(kRPVControllerPCSamplingNumSourceFiles, 0, data_store.rows.size()); + rocprofvis_property_t property; + rocprofvis_controller_primitive_type_t type; + for(size_t i = 0; i < data_store.rows.size(); i++) + for(const auto& column : data_store.columns) + if(output.QueryToPropertyEnum(column.first, property, type)) + SetObjectProperty((rocprofvis_handle_t*)&output, property, i, data_store.rows[i][column.second.value()], type); + }); + + uint64_t num_source_files = 0; + output.GetUInt64(kRPVControllerPCSamplingNumSourceFiles, 0, &num_source_files); + uint64_t source_line_offset = 0; + for(uint64_t fi = 0; fi < num_source_files; fi++) + { + uint64_t sf_id = 0; + output.GetUInt64(kRPVControllerPCSamplingSourceFileId, fi, &sf_id); + query_args = { {kRPVComputeParamSourceFileId, std::to_string(sf_id)} }; + query_out = { + { + { kRPVComputeColumnPcSamplingSourceLineId, std::nullopt }, + { kRPVComputeColumnPcSamplingSourceLineFileId, std::nullopt }, + { kRPVComputeColumnPcSamplingSourceLineNumber, std::nullopt }, + { kRPVComputeColumnPcSamplingSourceLineContent, std::nullopt }, + }, {} + }; + ExecuteQuery(db, m_dm_handle, nullptr, future, kRPVComputeFetchSourceFileSourceLines, query_args, query_out, + [this, &output, &source_line_offset](const QueryDataStore& data_store){ + output.SetUInt64(kRPVControllerPCSamplingNumSourceLines, 0, source_line_offset + data_store.rows.size()); + rocprofvis_property_t property; + rocprofvis_controller_primitive_type_t type; + for(size_t i = 0; i < data_store.rows.size(); i++) + for(const auto& column : data_store.columns) + if(output.QueryToPropertyEnum(column.first, property, type)) + SetObjectProperty((rocprofvis_handle_t*)&output, property, source_line_offset + i, data_store.rows[i][column.second.value()], type); + source_line_offset += data_store.rows.size(); + }); + } +} + rocprofvis_result_t ComputeTrace::LoadRocpd(Future* future) { rocprofvis_result_t result = kRocProfVisResultInvalidArgument; @@ -490,12 +744,307 @@ rocprofvis_result_t ComputeTrace::LoadRocpd(Future* future) SetObjectProperty((rocprofvis_handle_t*)kernel, property, 0, data_store.rows[i][column.second.value()], type); } } - workload->SetObject(kRPVControllerWorkloadKernelIndexed, i, (rocprofvis_handle_t*)kernel); + workload->SetObject(kRPVControllerWorkloadKernelIndexed, i, (rocprofvis_handle_t*)kernel); uint64_t id = std::stoull(data_store.rows[i][data_store.columns.at(kRPVComputeColumnKernelUUID).value()]); kernel_ids.push_back(static_cast(id)); } }); - } + } + if(dm_result == kRocProfVisDmResultSuccess) + { + for(size_t ki = 0; ki < kernel_ids.size(); ki++) + { + rocprofvis_handle_t* kernel_handle = nullptr; + if(kRocProfVisResultSuccess != workload->GetObject(kRPVControllerWorkloadKernelIndexed, ki, &kernel_handle) || !kernel_handle) + continue; + Kernel* kernel = (Kernel*)kernel_handle; + m_query_arguments = { {kRPVComputeParamKernelId, std::to_string(kernel_ids[ki])} }; + m_query_output = { + { + { kRPVComputeColumnPcSamplingCodeObjectId, std::nullopt }, + { kRPVComputeColumnPcSamplingCodeObjectUri, std::nullopt }, + { kRPVComputeColumnPcSamplingCodeObjectChecksum, std::nullopt }, + }, + {} + }; + future->ResetProgress(); + ExecuteQuery(db, m_dm_handle, object2wait, nullptr, kRPVComputeFetchKernelCodeObjects, m_query_arguments, m_query_output, [this, &kernel](const QueryDataStore& data_store){ + rocprofvis_handle_t* pc_handle = nullptr; + kernel->GetObject(kRPVControllerKernelPcSampling, 0, &pc_handle); + PcSamplingRef pc_sampling(pc_handle); + if(!pc_sampling.IsValid()) + return; + pc_sampling->SetUInt64(kRPVControllerPCSamplingNumCodeObjects, 0, data_store.rows.size()); + rocprofvis_property_t property; + rocprofvis_controller_primitive_type_t type; + for(size_t i = 0; i < data_store.rows.size(); i++) + { + for(const std::pair>& column : data_store.columns) + { + if(pc_sampling->QueryToPropertyEnum(column.first, property, type)) + { + SetObjectProperty(pc_handle, property, i, data_store.rows[i][column.second.value()], type); + } + } + } + }); + { + rocprofvis_handle_t* pc_handle = nullptr; + kernel->GetObject(kRPVControllerKernelPcSampling, 0, &pc_handle); + PcSamplingRef pc_sampling(pc_handle); + if(pc_sampling.IsValid()) + { + uint64_t num_code_objects = 0; + pc_sampling->GetUInt64(kRPVControllerPCSamplingNumCodeObjects, 0, &num_code_objects); + uint64_t isa_offset = 0; + for(uint64_t ci = 0; ci < num_code_objects; ci++) + { + uint64_t code_object_id = 0; + pc_sampling->GetUInt64(kRPVControllerPCSamplingCodeObjectId, ci, &code_object_id); + m_query_arguments = { {kRPVComputeParamCodeObjectId, std::to_string(code_object_id)} }; + m_query_output = { + { + { kRPVComputeColumnPcSamplingIsaLineId, std::nullopt }, + { kRPVComputeColumnPcSamplingIsaLineCodeObjectId, std::nullopt }, + { kRPVComputeColumnPcSamplingIsaLineCodeObjectOffset, std::nullopt }, + { kRPVComputeColumnPcSamplingIsaLineInstructionTypeId, std::nullopt }, + { kRPVComputeColumnPcSamplingIsaLineInstruction, std::nullopt }, + { kRPVComputeColumnPcSamplingIsaLineComment, std::nullopt }, + }, + {} + }; + future->ResetProgress(); + ExecuteQuery(db, m_dm_handle, object2wait, nullptr, kRPVComputeFetchCodeObjectIsaLines, m_query_arguments, m_query_output, [this, &pc_sampling, &pc_handle, &isa_offset](const QueryDataStore& data_store){ + pc_sampling->SetUInt64(kRPVControllerPCSamplingNumIsaLines, 0, isa_offset + data_store.rows.size()); + rocprofvis_property_t property; + rocprofvis_controller_primitive_type_t type; + for(size_t ii = 0; ii < data_store.rows.size(); ii++) + { + uint64_t flat_index = isa_offset + ii; + for(const std::pair>& column : data_store.columns) + { + if(pc_sampling->QueryToPropertyEnum(column.first, property, type)) + { + SetObjectProperty(pc_handle, property, flat_index, data_store.rows[ii][column.second.value()], type); + } + } + } + isa_offset += data_store.rows.size(); + }); + } + } + } + { + rocprofvis_handle_t* pc_handle2 = nullptr; + kernel->GetObject(kRPVControllerKernelPcSampling, 0, &pc_handle2); + PcSamplingRef pc_sampling(pc_handle2); + if(pc_sampling.IsValid()) + { + uint64_t num_isa_lines = 0; + pc_sampling->GetUInt64(kRPVControllerPCSamplingNumIsaLines, 0, &num_isa_lines); + uint64_t isa_to_isa_offset = 0; + uint64_t isa_to_source_offset = 0; + uint64_t stall_offset = 0; + for(uint64_t ii = 0; ii < num_isa_lines; ii++) + { + uint64_t isa_line_id = 0; + pc_sampling->GetUInt64(kRPVControllerPCSamplingIsaLineId, ii, &isa_line_id); + m_query_arguments = { {kRPVComputeParamIsaLineId, std::to_string(isa_line_id)} }; + m_query_output = { + { + { kRPVComputeColumnPcSamplingIsaToIsaDependentIsaLineId, std::nullopt }, + { kRPVComputeColumnPcSamplingIsaToIsaDependencyIsaLineId, std::nullopt }, + }, + {} + }; + future->ResetProgress(); + ExecuteQuery(db, m_dm_handle, object2wait, nullptr, kRPVComputeFetchIsaLineIsaLineDeps, m_query_arguments, m_query_output, [this, &pc_sampling, &pc_handle2, &isa_to_isa_offset](const QueryDataStore& data_store){ + pc_sampling->SetUInt64(kRPVControllerPCSamplingNumIsaToIsaDeps, 0, isa_to_isa_offset + data_store.rows.size()); + rocprofvis_property_t property; + rocprofvis_controller_primitive_type_t type; + for(size_t di = 0; di < data_store.rows.size(); di++) + { + uint64_t flat_index = isa_to_isa_offset + di; + for(const std::pair>& column : data_store.columns) + { + if(pc_sampling->QueryToPropertyEnum(column.first, property, type)) + { + SetObjectProperty(pc_handle2, property, flat_index, data_store.rows[di][column.second.value()], type); + } + } + } + isa_to_isa_offset += data_store.rows.size(); + }); + m_query_arguments = { {kRPVComputeParamIsaLineId, std::to_string(isa_line_id)} }; + m_query_output = { + { + { kRPVComputeColumnPcSamplingIsaToSourceIsaLineId, std::nullopt }, + { kRPVComputeColumnPcSamplingIsaToSourceSourceLineId, std::nullopt }, + { kRPVComputeColumnPcSamplingIsaToSourceDepth, std::nullopt }, + }, + {} + }; + future->ResetProgress(); + ExecuteQuery(db, m_dm_handle, object2wait, nullptr, kRPVComputeFetchIsaLineSourceLineDeps, m_query_arguments, m_query_output, [this, &pc_sampling, &pc_handle2, &isa_to_source_offset](const QueryDataStore& data_store){ + pc_sampling->SetUInt64(kRPVControllerPCSamplingNumIsaToSourceDeps, 0, isa_to_source_offset + data_store.rows.size()); + rocprofvis_property_t property; + rocprofvis_controller_primitive_type_t type; + for(size_t si = 0; si < data_store.rows.size(); si++) + { + uint64_t flat_index = isa_to_source_offset + si; + for(const std::pair>& column : data_store.columns) + { + if(pc_sampling->QueryToPropertyEnum(column.first, property, type)) + { + SetObjectProperty(pc_handle2, property, flat_index, data_store.rows[si][column.second.value()], type); + } + } + } + isa_to_source_offset += data_store.rows.size(); + }); + m_query_arguments = { {kRPVComputeParamIsaLineId, std::to_string(isa_line_id)} }; + m_query_output = { + { + { kRPVComputeColumnPcSamplingStallRecordId, std::nullopt }, + { kRPVComputeColumnPcSamplingStallRecordIsaLineId, std::nullopt }, + { kRPVComputeColumnPcSamplingStallRecordDispatchId, std::nullopt }, + { kRPVComputeColumnPcSamplingStallRecordAvgActiveLanes, std::nullopt }, + { kRPVComputeColumnPcSamplingStallRecordWaveIssuedCount, std::nullopt }, + { kRPVComputeColumnPcSamplingStallRecordTotalSampleCount, std::nullopt }, + }, + {} + }; + future->ResetProgress(); + ExecuteQuery(db, m_dm_handle, object2wait, nullptr, kRPVComputeFetchIsaLineStallRecord, m_query_arguments, m_query_output, [this, &pc_sampling, &pc_handle2, &stall_offset](const QueryDataStore& data_store){ + pc_sampling->SetUInt64(kRPVControllerPCSamplingNumStallRecords, 0, stall_offset + data_store.rows.size()); + rocprofvis_property_t property; + rocprofvis_controller_primitive_type_t type; + for(size_t ri = 0; ri < data_store.rows.size(); ri++) + { + uint64_t flat_index = stall_offset + ri; + for(const std::pair>& column : data_store.columns) + { + if(pc_sampling->QueryToPropertyEnum(column.first, property, type)) + { + SetObjectProperty(pc_handle2, property, flat_index, data_store.rows[ri][column.second.value()], type); + } + } + } + stall_offset += data_store.rows.size(); + }); + // Fetch stall reason counts for each stall record of this ISA line + uint64_t num_stall_records = 0; + pc_sampling->GetUInt64(kRPVControllerPCSamplingNumStallRecords, 0, &num_stall_records); + uint64_t stall_reason_offset = 0; + for(uint64_t si = 0; si < num_stall_records; si++) + { + uint64_t stall_record_id = 0; + pc_sampling->GetUInt64(kRPVControllerPCSamplingStallRecordId, si, &stall_record_id); + m_query_arguments = { {kRPVComputeParamStallRecordId, std::to_string(stall_record_id)} }; + m_query_output = { + { + { kRPVComputeColumnPcSamplingStallReasonRecordId, std::nullopt }, + { kRPVComputeColumnPcSamplingStallReasonTypeId, std::nullopt }, + { kRPVComputeColumnPcSamplingStallReasonCount, std::nullopt }, + }, + {} + }; + future->ResetProgress(); + ExecuteQuery(db, m_dm_handle, object2wait, nullptr, kRPVComputeFetchStallRecordReasonCounts, m_query_arguments, m_query_output, [this, &pc_sampling, &pc_handle2, &stall_reason_offset](const QueryDataStore& data_store){ + pc_sampling->SetUInt64(kRPVControllerPCSamplingNumStallReasonCounts, 0, stall_reason_offset + data_store.rows.size()); + rocprofvis_property_t property; + rocprofvis_controller_primitive_type_t type; + for(size_t ri = 0; ri < data_store.rows.size(); ri++) + { + uint64_t flat_index = stall_reason_offset + ri; + for(const std::pair>& column : data_store.columns) + { + if(pc_sampling->QueryToPropertyEnum(column.first, property, type)) + { + SetObjectProperty(pc_handle2, property, flat_index, data_store.rows[ri][column.second.value()], type); + } + } + } + stall_reason_offset += data_store.rows.size(); + }); + } + } + } + } + m_query_arguments = { {kRPVComputeParamKernelId, std::to_string(kernel_ids[ki])} }; + m_query_output = { + { + { kRPVComputeColumnPcSamplingSourceFileId, std::nullopt }, + { kRPVComputeColumnPcSamplingSourceFilePath, std::nullopt }, + { kRPVComputeColumnPcSamplingSourceFileChecksum, std::nullopt }, + }, + {} + }; + future->ResetProgress(); + ExecuteQuery(db, m_dm_handle, object2wait, nullptr, kRPVComputeFetchKernelSourceFiles, m_query_arguments, m_query_output, [this, &kernel](const QueryDataStore& data_store){ + rocprofvis_handle_t* pc_handle = nullptr; + kernel->GetObject(kRPVControllerKernelPcSampling, 0, &pc_handle); + PcSamplingRef pc_sampling(pc_handle); + if(!pc_sampling.IsValid()) + return; + pc_sampling->SetUInt64(kRPVControllerPCSamplingNumSourceFiles, 0, data_store.rows.size()); + rocprofvis_property_t property; + rocprofvis_controller_primitive_type_t type; + for(size_t i = 0; i < data_store.rows.size(); i++) + { + for(const std::pair>& column : data_store.columns) + { + if(pc_sampling->QueryToPropertyEnum(column.first, property, type)) + { + SetObjectProperty(pc_handle, property, i, data_store.rows[i][column.second.value()], type); + } + } + } + }); + rocprofvis_handle_t* pc_handle = nullptr; + kernel->GetObject(kRPVControllerKernelPcSampling, 0, &pc_handle); + PcSamplingRef pc_sampling(pc_handle); + if(pc_sampling.IsValid()) + { + uint64_t num_source_files = 0; + pc_sampling->GetUInt64(kRPVControllerPCSamplingNumSourceFiles, 0, &num_source_files); + uint64_t source_line_offset = 0; + for(uint64_t fi = 0; fi < num_source_files; fi++) + { + uint64_t source_file_id = 0; + pc_sampling->GetUInt64(kRPVControllerPCSamplingSourceFileId, fi, &source_file_id); + m_query_arguments = { {kRPVComputeParamSourceFileId, std::to_string(source_file_id)} }; + m_query_output = { + { + { kRPVComputeColumnPcSamplingSourceLineId, std::nullopt }, + { kRPVComputeColumnPcSamplingSourceLineFileId, std::nullopt }, + { kRPVComputeColumnPcSamplingSourceLineNumber, std::nullopt }, + { kRPVComputeColumnPcSamplingSourceLineContent, std::nullopt }, + }, + {} + }; + future->ResetProgress(); + ExecuteQuery(db, m_dm_handle, object2wait, nullptr, kRPVComputeFetchSourceFileSourceLines, m_query_arguments, m_query_output, [this, &pc_sampling, &pc_handle, &source_line_offset](const QueryDataStore& data_store){ + pc_sampling->SetUInt64(kRPVControllerPCSamplingNumSourceLines, 0, source_line_offset + data_store.rows.size()); + rocprofvis_property_t property; + rocprofvis_controller_primitive_type_t type; + for(size_t li = 0; li < data_store.rows.size(); li++) + { + uint64_t flat_index = source_line_offset + li; + for(const std::pair>& column : data_store.columns) + { + if(pc_sampling->QueryToPropertyEnum(column.first, property, type)) + { + SetObjectProperty(pc_handle, property, flat_index, data_store.rows[li][column.second.value()], type); + } + } + } + source_line_offset += data_store.rows.size(); + }); + } + } + } + } if(dm_result == kRocProfVisDmResultSuccess) { Roofline* roofline = new Roofline(); diff --git a/src/controller/src/compute/rocprofvis_controller_trace_compute.h b/src/controller/src/compute/rocprofvis_controller_trace_compute.h index 51fa9f67a..b3ff6527f 100644 --- a/src/controller/src/compute/rocprofvis_controller_trace_compute.h +++ b/src/controller/src/compute/rocprofvis_controller_trace_compute.h @@ -23,6 +23,7 @@ class Future; class Workload; class MetricsContainer; class MetricID; +class PcSampling; class Table; class ComputePivotTable; @@ -44,6 +45,7 @@ class ComputeTrace : public Trace rocprofvis_result_t AsyncFetch(Arguments& args, Future& future, MetricsContainer& output); rocprofvis_result_t AsyncFetch(Table& table, Arguments& args, Future& future, Array& array); + rocprofvis_result_t AsyncFetchPcSampling(Arguments& args, Future& future, PcSampling& output); private: class MetricID @@ -71,6 +73,15 @@ class ComputeTrace : public Trace typedef std::function QueryCallback; rocprofvis_result_t LoadRocpd(Future* future); + + void FetchCodeObjectsAndIsaLines(rocprofvis_dm_database_t db, Future* future, + uint64_t kernel_id, PcSampling& output); + void FetchIsaLineDepsAndStalls(rocprofvis_dm_database_t db, Future* future, + PcSampling& output); + void FetchStallReasonCounts(rocprofvis_dm_database_t db, Future* future, + PcSampling& output); + void FetchSourceFileAndLines(rocprofvis_dm_database_t db, Future* future, + uint64_t source_file_id, PcSampling& output); rocprofvis_result_t SetObjectProperty(rocprofvis_handle_t* object, rocprofvis_property_t property, uint64_t index, diff --git a/src/controller/src/rocprofvis_controller.cpp b/src/controller/src/rocprofvis_controller.cpp index ca93a6f2e..3aea77b20 100644 --- a/src/controller/src/rocprofvis_controller.cpp +++ b/src/controller/src/rocprofvis_controller.cpp @@ -22,6 +22,7 @@ #ifdef COMPUTE_UI_SUPPORT #include "compute/rocprofvis_controller_metrics_container.h" #include "compute/rocprofvis_controller_trace_compute.h" +#include "compute/rocprofvis_controller_pc_sampling.h" #endif #include "rocprofvis_c_interface.h" @@ -46,6 +47,7 @@ typedef Reference ComputeTraceRef; typedef Reference MetricsContainerRef; +typedef Reference PcSamplingRef; #endif } } @@ -461,7 +463,7 @@ void rocprofvis_controller_metrics_container_free(rocprofvis_controller_metrics_ } rocprofvis_result_t rocprofvis_controller_metric_fetch_async( - rocprofvis_controller_t* controller, rocprofvis_controller_arguments_t* args, + rocprofvis_controller_t* controller, rocprofvis_controller_arguments_t* args, rocprofvis_controller_future_t* result, rocprofvis_controller_metrics_container_t* output) { rocprofvis_result_t error = kRocProfVisResultInvalidArgument; @@ -475,6 +477,22 @@ rocprofvis_result_t rocprofvis_controller_metric_fetch_async( } return error; } + +rocprofvis_result_t rocprofvis_controller_pc_sampling_fetch_async( + rocprofvis_controller_t* controller, rocprofvis_controller_arguments_t* args, + rocprofvis_controller_future_t* result, rocprofvis_handle_t* output) +{ + rocprofvis_result_t error = kRocProfVisResultInvalidArgument; + RocProfVis::Controller::ComputeTraceRef trace(controller); + RocProfVis::Controller::ArgumentsRef args_ref(args); + RocProfVis::Controller::FutureRef future(result); + RocProfVis::Controller::PcSamplingRef pc_sampling(output); + if(trace.IsValid() && args_ref.IsValid() && future.IsValid() && pc_sampling.IsValid()) + { + error = trace->AsyncFetchPcSampling(*args_ref, *future, *pc_sampling); + } + return error; +} #endif void rocprofvis_controller_summary_metric_free(rocprofvis_controller_summary_metrics_t* object) diff --git a/src/model/inc/rocprofvis_interface_types.h b/src/model/inc/rocprofvis_interface_types.h index 662403b4f..70ddd4091 100644 --- a/src/model/inc/rocprofvis_interface_types.h +++ b/src/model/inc/rocprofvis_interface_types.h @@ -517,6 +517,44 @@ typedef enum rocprofvis_db_compute_column_enum_t kRPVComputeColumnDynamicMetricValue, kRPVComputeColumnDynamicKernelUUID, + + kRPVComputeColumnPcSamplingSourceFileId, + kRPVComputeColumnPcSamplingSourceFilePath, + kRPVComputeColumnPcSamplingSourceFileChecksum, + + kRPVComputeColumnPcSamplingSourceLineId, + kRPVComputeColumnPcSamplingSourceLineFileId, + kRPVComputeColumnPcSamplingSourceLineNumber, + kRPVComputeColumnPcSamplingSourceLineContent, + + kRPVComputeColumnPcSamplingCodeObjectId, + kRPVComputeColumnPcSamplingCodeObjectUri, + kRPVComputeColumnPcSamplingCodeObjectChecksum, + + kRPVComputeColumnPcSamplingIsaLineId, + kRPVComputeColumnPcSamplingIsaLineCodeObjectId, + kRPVComputeColumnPcSamplingIsaLineCodeObjectOffset, + kRPVComputeColumnPcSamplingIsaLineInstructionTypeId, + kRPVComputeColumnPcSamplingIsaLineInstruction, + kRPVComputeColumnPcSamplingIsaLineComment, + + kRPVComputeColumnPcSamplingIsaToIsaDependentIsaLineId, + kRPVComputeColumnPcSamplingIsaToIsaDependencyIsaLineId, + + kRPVComputeColumnPcSamplingIsaToSourceIsaLineId, + kRPVComputeColumnPcSamplingIsaToSourceSourceLineId, + kRPVComputeColumnPcSamplingIsaToSourceDepth, + + kRPVComputeColumnPcSamplingStallRecordId, + kRPVComputeColumnPcSamplingStallRecordIsaLineId, + kRPVComputeColumnPcSamplingStallRecordDispatchId, + kRPVComputeColumnPcSamplingStallRecordAvgActiveLanes, + kRPVComputeColumnPcSamplingStallRecordWaveIssuedCount, + kRPVComputeColumnPcSamplingStallRecordTotalSampleCount, + + kRPVComputeColumnPcSamplingStallReasonRecordId, + kRPVComputeColumnPcSamplingStallReasonTypeId, + kRPVComputeColumnPcSamplingStallReasonCount, } rocprofvis_db_compute_column_enum_t; // Compute database query use case enumerations @@ -534,6 +572,14 @@ typedef enum rocprofvis_db_compute_use_case_enum_t kRPVComputeFetchKernelMetricsMatrix, kRPVComputeFetchWorkloadMetricValueNames, kRPVComputeFetchMetricValuesByWorkload, + kRPVComputeFetchKernelSourceFiles, + kRPVComputeFetchSourceFileSourceLines, + kRPVComputeFetchKernelCodeObjects, + kRPVComputeFetchCodeObjectIsaLines, + kRPVComputeFetchIsaLineIsaLineDeps, + kRPVComputeFetchIsaLineSourceLineDeps, + kRPVComputeFetchIsaLineStallRecord, + kRPVComputeFetchStallRecordReasonCounts, } rocprofvis_db_compute_use_case_enum_t; // Compute database query parameter enumeration @@ -541,6 +587,10 @@ typedef enum rocprofvis_db_compute_param_enum_t { kRPVComputeParamWorkloadId, kRPVComputeParamKernelId, + kRPVComputeParamSourceFileId, + kRPVComputeParamCodeObjectId, + kRPVComputeParamIsaLineId, + kRPVComputeParamStallRecordId, kRPVComputeParamMetricId, kRPVComputeParamMetricSelector, kRPVComputeParamSortColumnIndex, diff --git a/src/model/src/database/rocprofvis_db_compute.cpp b/src/model/src/database/rocprofvis_db_compute.cpp index f0ef7e0cd..59bd14d92 100644 --- a/src/model/src/database/rocprofvis_db_compute.cpp +++ b/src/model/src/database/rocprofvis_db_compute.cpp @@ -20,7 +20,15 @@ namespace DataModel {kRPVComputeFetchMetricValues, "Fetch kernel aggregated values of metrics"}, {kRPVComputeFetchKernelMetricsMatrix, "Fetch kernel metrics matrix with pivoted metric columns"}, {kRPVComputeFetchWorkloadMetricValueNames, "Fetch distinct value names per metric in a workload"}, - {kRPVComputeFetchMetricValuesByWorkload, "Fetch workload aggregated values of metrics"} + {kRPVComputeFetchMetricValuesByWorkload, "Fetch workload aggregated values of metrics"}, + {kRPVComputeFetchKernelSourceFiles, "Fetch source files for a kernel"}, + {kRPVComputeFetchSourceFileSourceLines, "Fetch source lines for a source file"}, + {kRPVComputeFetchKernelCodeObjects, "Fetch code objects for a kernel"}, + {kRPVComputeFetchCodeObjectIsaLines, "Fetch ISA lines for a code object"}, + {kRPVComputeFetchIsaLineIsaLineDeps, "Fetch ISA-to-ISA dependency edges for an ISA line"}, + {kRPVComputeFetchIsaLineSourceLineDeps, "Fetch ISA-to-source-line mapping for an ISA line"}, + {kRPVComputeFetchIsaLineStallRecord, "Fetch stall record for an ISA line"}, + {kRPVComputeFetchStallRecordReasonCounts, "Fetch stall reason counts for a stall record"} }; static const std::unordered_map ColumnNameToEnum { @@ -54,6 +62,36 @@ namespace DataModel {"value", kRPVComputeColumnMetricValue}, {"unit", kRPVComputeColumnMetricUnit}, {"__id", kRPVComputeColumnDynamicKernelUUID}, + {"id", kRPVComputeColumnPcSamplingSourceFileId}, + {"file_path", kRPVComputeColumnPcSamplingSourceFilePath}, + {"content_checksum", kRPVComputeColumnPcSamplingSourceFileChecksum}, + {"source_line_id", kRPVComputeColumnPcSamplingSourceLineId}, + {"source_file_id", kRPVComputeColumnPcSamplingSourceLineFileId}, + {"line_number", kRPVComputeColumnPcSamplingSourceLineNumber}, + {"content", kRPVComputeColumnPcSamplingSourceLineContent}, + {"code_object_id", kRPVComputeColumnPcSamplingCodeObjectId}, + {"uri", kRPVComputeColumnPcSamplingCodeObjectUri}, + {"code_object_checksum", kRPVComputeColumnPcSamplingCodeObjectChecksum}, + {"isa_line_id", kRPVComputeColumnPcSamplingIsaLineId}, + {"isa_code_object_id", kRPVComputeColumnPcSamplingIsaLineCodeObjectId}, + {"code_object_offset", kRPVComputeColumnPcSamplingIsaLineCodeObjectOffset}, + {"instruction_type_id", kRPVComputeColumnPcSamplingIsaLineInstructionTypeId}, + {"instruction", kRPVComputeColumnPcSamplingIsaLineInstruction}, + {"comment", kRPVComputeColumnPcSamplingIsaLineComment}, + {"dependent_isa_line_id", kRPVComputeColumnPcSamplingIsaToIsaDependentIsaLineId}, + {"dependency_isa_line_id", kRPVComputeColumnPcSamplingIsaToIsaDependencyIsaLineId}, + {"isa_to_source_isa_line_id", kRPVComputeColumnPcSamplingIsaToSourceIsaLineId}, + {"isa_to_source_source_line_id", kRPVComputeColumnPcSamplingIsaToSourceSourceLineId}, + {"depth", kRPVComputeColumnPcSamplingIsaToSourceDepth}, + {"stall_record_id", kRPVComputeColumnPcSamplingStallRecordId}, + {"stall_isa_line_id", kRPVComputeColumnPcSamplingStallRecordIsaLineId}, + {"dispatch_id", kRPVComputeColumnPcSamplingStallRecordDispatchId}, + {"avg_active_lanes", kRPVComputeColumnPcSamplingStallRecordAvgActiveLanes}, + {"wave_issued_count", kRPVComputeColumnPcSamplingStallRecordWaveIssuedCount}, + {"total_sample_count", kRPVComputeColumnPcSamplingStallRecordTotalSampleCount}, + {"stall_reason_record_id", kRPVComputeColumnPcSamplingStallReasonRecordId}, + {"stall_reason_type_id", kRPVComputeColumnPcSamplingStallReasonTypeId}, + {"stall_reason_count", kRPVComputeColumnPcSamplingStallReasonCount}, }; static const std::unordered_map RooflineBenchParamToEnum{ @@ -217,6 +255,114 @@ namespace DataModel return query; } + std::string ComputeQueryFactory::GetComputeKernelSourceFiles(rocprofvis_db_num_of_params_t num, rocprofvis_db_compute_params_t params) { + std::string query; + if (num == 1 && params != nullptr && params[0].param_type == kRPVComputeParamKernelId) + { + query = + "SELECT id, file_path, content_checksum " + "FROM source_files " + "WHERE kernel_id = "; + query += params[0].param_str; + } + return query; + } + + std::string ComputeQueryFactory::GetComputeSourceFileSourceLines(rocprofvis_db_num_of_params_t num, rocprofvis_db_compute_params_t params) { + std::string query; + if (num == 1 && params != nullptr && params[0].param_type == kRPVComputeParamSourceFileId) + { + query = + "SELECT id AS source_line_id, source_file_id, line_number, content " + "FROM source_lines " + "WHERE source_file_id = "; + query += params[0].param_str; + } + return query; + } + + std::string ComputeQueryFactory::GetComputeKernelCodeObjects(rocprofvis_db_num_of_params_t num, rocprofvis_db_compute_params_t params) { + std::string query; + if (num == 1 && params != nullptr && params[0].param_type == kRPVComputeParamKernelId) + { + query = + "SELECT id AS code_object_id, uri, content_checksum AS code_object_checksum " + "FROM code_objects " + "WHERE kernel_id = "; + query += params[0].param_str; + } + return query; + } + + std::string ComputeQueryFactory::GetComputeCodeObjectIsaLines(rocprofvis_db_num_of_params_t num, rocprofvis_db_compute_params_t params) { + std::string query; + if (num == 1 && params != nullptr && params[0].param_type == kRPVComputeParamCodeObjectId) + { + query = + "SELECT id AS isa_line_id, code_object_id AS isa_code_object_id, " + "code_object_offset, instruction_type_id, instruction, comment " + "FROM isa_lines " + "WHERE code_object_id = "; + query += params[0].param_str; + } + return query; + } + + std::string ComputeQueryFactory::GetComputeIsaLineIsaLineDeps(rocprofvis_db_num_of_params_t num, rocprofvis_db_compute_params_t params) { + std::string query; + if (num == 1 && params != nullptr && params[0].param_type == kRPVComputeParamIsaLineId) + { + query = + "SELECT dependent_isa_line_id, dependency_isa_line_id " + "FROM isa_line_to_isa_line_junction " + "WHERE dependent_isa_line_id = "; + query += params[0].param_str; + } + return query; + } + + std::string ComputeQueryFactory::GetComputeIsaLineSourceLineDeps(rocprofvis_db_num_of_params_t num, rocprofvis_db_compute_params_t params) { + std::string query; + if (num == 1 && params != nullptr && params[0].param_type == kRPVComputeParamIsaLineId) + { + query = + "SELECT isa_line_id AS isa_to_source_isa_line_id, " + "source_line_id AS isa_to_source_source_line_id, depth " + "FROM isa_line_to_source_line_junction " + "WHERE isa_line_id = "; + query += params[0].param_str; + } + return query; + } + + std::string ComputeQueryFactory::GetComputeIsaLineStallRecord(rocprofvis_db_num_of_params_t num, rocprofvis_db_compute_params_t params) { + std::string query; + if (num == 1 && params != nullptr && params[0].param_type == kRPVComputeParamIsaLineId) + { + query = + "SELECT id AS stall_record_id, isa_line AS stall_isa_line_id, " + "dispatch_id, avg_active_lanes, wave_issued_count, total_sample_count " + "FROM pc_sampling_stall_record " + "WHERE isa_line = "; + query += params[0].param_str; + } + return query; + } + + std::string ComputeQueryFactory::GetComputeStallRecordReasonCounts(rocprofvis_db_num_of_params_t num, rocprofvis_db_compute_params_t params) { + std::string query; + if (num == 1 && params != nullptr && params[0].param_type == kRPVComputeParamStallRecordId) + { + query = + "SELECT pc_sampling_record_id AS stall_reason_record_id, " + "stall_reason_type_id, count AS stall_reason_count " + "FROM pc_sampling_stall_reason_counts " + "WHERE pc_sampling_record_id = "; + query += params[0].param_str; + } + return query; + } + std::string ComputeQueryFactory::GetComputeKernelMetricCategoriesList(rocprofvis_db_num_of_params_t num, rocprofvis_db_compute_params_t params) { std::string query; if (num == 1 && params != nullptr && params[0].param_type == kRPVComputeParamKernelId) @@ -714,6 +860,30 @@ void ComputeQueryFactory::ParseMetricParam(std::string metric_str, uint32_t work case kRPVComputeFetchWorkloadMetricValueNames: query = m_query_factory.GetComputeWorkloadMetricValueNames(num, params); break; + case kRPVComputeFetchKernelSourceFiles: + query = m_query_factory.GetComputeKernelSourceFiles(num, params); + break; + case kRPVComputeFetchSourceFileSourceLines: + query = m_query_factory.GetComputeSourceFileSourceLines(num, params); + break; + case kRPVComputeFetchKernelCodeObjects: + query = m_query_factory.GetComputeKernelCodeObjects(num, params); + break; + case kRPVComputeFetchCodeObjectIsaLines: + query = m_query_factory.GetComputeCodeObjectIsaLines(num, params); + break; + case kRPVComputeFetchIsaLineIsaLineDeps: + query = m_query_factory.GetComputeIsaLineIsaLineDeps(num, params); + break; + case kRPVComputeFetchIsaLineSourceLineDeps: + query = m_query_factory.GetComputeIsaLineSourceLineDeps(num, params); + break; + case kRPVComputeFetchIsaLineStallRecord: + query = m_query_factory.GetComputeIsaLineStallRecord(num, params); + break; + case kRPVComputeFetchStallRecordReasonCounts: + query = m_query_factory.GetComputeStallRecordReasonCounts(num, params); + break; default: return kRocProfVisDmResultInvalidParameter; } @@ -770,6 +940,14 @@ void ComputeQueryFactory::ParseMetricParam(std::string metric_str, uint32_t work case kRPVComputeFetchMetricValues: case kRPVComputeFetchMetricValuesByWorkload: case kRPVComputeFetchWorkloadMetricValueNames: + case kRPVComputeFetchKernelSourceFiles: + case kRPVComputeFetchSourceFileSourceLines: + case kRPVComputeFetchKernelCodeObjects: + case kRPVComputeFetchCodeObjectIsaLines: + case kRPVComputeFetchIsaLineIsaLineDeps: + case kRPVComputeFetchIsaLineSourceLineDeps: + case kRPVComputeFetchIsaLineStallRecord: + case kRPVComputeFetchStallRecordReasonCounts: callback = CallbackGetComputeGeneric; break; case kRPVComputeFetchWorkloadRooflineCeiling: diff --git a/src/model/src/database/rocprofvis_db_compute.h b/src/model/src/database/rocprofvis_db_compute.h index 677af07cd..970d78a7c 100644 --- a/src/model/src/database/rocprofvis_db_compute.h +++ b/src/model/src/database/rocprofvis_db_compute.h @@ -36,6 +36,14 @@ namespace DataModel std::string GetComputeMetricValues(rocprofvis_db_num_of_params_t num, rocprofvis_db_compute_params_t params); std::string GetComputeMetricValuesByWorkload(rocprofvis_db_num_of_params_t num, rocprofvis_db_compute_params_t params); std::string GetComputeKernelMetricsMatrix(rocprofvis_db_num_of_params_t num, rocprofvis_db_compute_params_t params); + std::string GetComputeKernelSourceFiles(rocprofvis_db_num_of_params_t num, rocprofvis_db_compute_params_t params); + std::string GetComputeSourceFileSourceLines(rocprofvis_db_num_of_params_t num, rocprofvis_db_compute_params_t params); + std::string GetComputeKernelCodeObjects(rocprofvis_db_num_of_params_t num, rocprofvis_db_compute_params_t params); + std::string GetComputeCodeObjectIsaLines(rocprofvis_db_num_of_params_t num, rocprofvis_db_compute_params_t params); + std::string GetComputeIsaLineIsaLineDeps(rocprofvis_db_num_of_params_t num, rocprofvis_db_compute_params_t params); + std::string GetComputeIsaLineSourceLineDeps(rocprofvis_db_num_of_params_t num, rocprofvis_db_compute_params_t params); + std::string GetComputeIsaLineStallRecord(rocprofvis_db_num_of_params_t num, rocprofvis_db_compute_params_t params); + std::string GetComputeStallRecordReasonCounts(rocprofvis_db_num_of_params_t num, rocprofvis_db_compute_params_t params); private: MetricIdFormat ClassifyMetricIdFormat(const std::string& s); std::string SanitizeMetricValueName(const std::string& name); diff --git a/src/view/src/compute/rocprofvis_compute_code_view.cpp b/src/view/src/compute/rocprofvis_compute_code_view.cpp new file mode 100644 index 000000000..88b1564a3 --- /dev/null +++ b/src/view/src/compute/rocprofvis_compute_code_view.cpp @@ -0,0 +1,608 @@ +// Copyright Advanced Micro Devices, Inc. +// SPDX-License-Identifier: MIT + +#include "rocprofvis_compute_code_view.h" +#include "rocprofvis_compute_selection.h" +#include "rocprofvis_data_provider.h" +#include "rocprofvis_events.h" +#include "rocprofvis_font_manager.h" +#include "rocprofvis_requests.h" + +#include +#include +#include + +namespace RocProfVis +{ +namespace View +{ + +ComputeCodeView::ComputeCodeView(DataProvider& data_provider) +: RocWidget() +, m_settings(SettingsManager::GetInstance()) +, m_data_provider(data_provider) +, m_control_panel_height(0.0f) +{ + m_source_code = std::make_shared(m_line_selection); + m_isa_code = std::make_shared(m_line_selection); + + auto source_item = LayoutItem::CreateFromWidget(m_source_code); + source_item->m_child_flags = ImGuiChildFlags_None; + + m_isa_layout_item = LayoutItem::CreateFromWidget(m_isa_code); + m_isa_layout_item->m_child_flags = ImGuiChildFlags_None; + m_isa_layout_item->m_visible = false; + + m_horizontal_split_container = std::make_shared(source_item, m_isa_layout_item); + m_horizontal_split_container->SetSplit(0.5f); + m_horizontal_split_container->ShowSplitter(true); + + SubscribeToEvents(); + + m_data_provider.SetFetchPcSamplingCallback( + [this](const std::string&, uint32_t kernel_id, uint32_t source_file_id, bool success) { + OnPcSamplingReady(kernel_id, source_file_id, success); + }); +} + +ComputeCodeView::~ComputeCodeView() +{ + EventManager::GetInstance()->Unsubscribe( + static_cast(RocEvents::kComputeKernelSelectionChanged), + m_kernel_selection_changed_token); +} + +void +ComputeCodeView::SubscribeToEvents() +{ + auto kernel_changed = [this](std::shared_ptr e) { + auto event = std::dynamic_pointer_cast(e); + if(event && event->GetSourceId() == m_data_provider.GetTraceFilePath()) + LoadData(event->GetId()); + }; + m_kernel_selection_changed_token = EventManager::GetInstance()->Subscribe( + static_cast(RocEvents::kComputeKernelSelectionChanged), kernel_changed); +} + +void +ComputeCodeView::LoadData(uint32_t kernel_id) +{ + m_current_kernel_id = kernel_id; + + for(const WorkloadInfo* workload : m_data_provider.ComputeModel().GetWorkloadList()) + { + if(workload->kernels.count(kernel_id)) + { + m_current_workload_id = workload->id; + break; + } + } + if(m_current_workload_id == ComputeSelection::INVALID_SELECTION_ID) + return; + + const KernelInfo* kernel_info = m_data_provider.ComputeModel().GetKernelInfo( + m_current_workload_id, kernel_id); + if(!kernel_info) + return; + + // Source file list is already populated eagerly — just refresh the selection. + LoadSourceFileList(kernel_info->pc_sampling_data); + + // Clear stale widget data and kick off the async fetch for the selected file. + m_source_code->Load({}, 0); + m_isa_code->Load({}, 0); + FetchPcSamplingForCurrentFile(); +} + +void +ComputeCodeView::FetchPcSamplingForCurrentFile() +{ + if(m_current_kernel_id == 0 || m_current_source_file_id == 0) + return; + m_data_provider.FetchPcSampling( + PcSamplingRequestParams(m_current_workload_id, m_current_kernel_id, m_current_source_file_id)); +} + +void +ComputeCodeView::OnPcSamplingReady(uint32_t kernel_id, uint32_t source_file_id, bool success) +{ + if(!success || kernel_id != m_current_kernel_id || source_file_id != m_current_source_file_id) + return; + + const KernelInfo* kernel_info = m_data_provider.ComputeModel().GetKernelInfo( + m_current_workload_id, m_current_kernel_id); + if(!kernel_info) + return; + + const PcSamplingData& data = kernel_info->pc_sampling_data; + + if(m_current_source_file_id != 0) + m_source_code->Load(data, m_current_source_file_id); + + if(!data.code_objects.empty()) + m_current_code_object_id = data.code_objects[0].id; + + if(m_current_code_object_id != 0) + m_isa_code->Load(data, m_current_code_object_id); +} + +void +ComputeCodeView::LoadSourceFileList(const PcSamplingData& data) +{ + m_source_files.clear(); + for (auto& file : data.source_files) + m_source_files.emplace(file.file_path, file.id); + + bool selection_valid = false; + for(const auto& [path, id] : m_source_files) + { + if(id == m_current_source_file_id) + { + selection_valid = true; + break; + } + } + if(!selection_valid) + m_current_source_file_id = m_source_files.empty() ? 0 : m_source_files.begin()->second; +} + +void +ComputeCodeView::Render() +{ + RenderControlPanel(); + + ImGui::PushFont(m_settings.GetFontManager().GetFont(FontType::kCode), 0.0f); + + m_horizontal_split_container->Render(); + + ImGui::PopFont(); +} + +void +ComputeCodeView::RenderControlPanel() +{ + const float fallbackHeight = + ImGui::GetFrameHeight() + + ImGui::GetStyle().WindowPadding.y * 2.0f; + + float topHeight = m_control_panel_height > 0.0f + ? m_control_panel_height + : fallbackHeight; + + ImGui::BeginChild("ControlPanel", ImVec2(0.0f, topHeight), true); + + ImVec2 start = ImGui::GetCursorPos(); + + ImGui::BeginGroup(); + + RenderSourceFileDropdown(); + + const float button_isa_width = ImGui::CalcTextSize("Hide ISA").x + ImGui::GetStyle().FramePadding.x * 2.0f; //TODO: thing how can avoid dublication of strings + const float button_stall_width = ImGui::CalcTextSize("Show Stalls").x + ImGui::GetStyle().FramePadding.x * 2.0f; + + const float button_comments_width = + m_isa_layout_item->m_visible ? + (ImGui::CalcTextSize("Show Comnents").x + ImGui::GetStyle().FramePadding.x * 2.0f) : 0; + + const float buttons_width = button_isa_width + button_stall_width + + button_comments_width + + ImGui::GetStyle().ItemSpacing.x * 2.0f; + + ImGui::SameLine(ImGui::GetContentRegionAvail().x + ImGui::GetCursorPosX() - buttons_width); + + if(ImGui::Button(m_isa_layout_item->m_visible ? "Hide ISA" : "Show ISA")) + m_isa_layout_item->m_visible = !m_isa_layout_item->m_visible; + + ImGui::SameLine(); + static bool show_metadata_enabled = false; + if(ImGui::Button(show_metadata_enabled ? "Hide Stalls" : "Show Stalls")) + { + show_metadata_enabled = !show_metadata_enabled; + m_source_code->ChangeStallVisibility(show_metadata_enabled); + m_isa_code->ChangeStallVisibility(show_metadata_enabled); + } + + if(m_isa_layout_item->m_visible) + { + ImGui::SameLine(); + static bool show_comments_enabled = false; + if(ImGui::Button(show_comments_enabled ? "Hide Comnents" : "Show Comments")) + { + show_comments_enabled = !show_comments_enabled; + m_isa_code->ShowComments(show_comments_enabled); + } + } + + + ImGui::EndGroup(); + + ImVec2 end = ImGui::GetCursorPos(); + + float contentHeight = end.y - start.y; + m_control_panel_height = + contentHeight + + ImGui::GetStyle().WindowPadding.y * 2.0f; + + ImGui::EndChild(); + +} + +void +ComputeCodeView::RenderSourceFileDropdown() +{ + constexpr const float DROPDAWN_SIZE = 300.0f; + if(m_source_files.empty()) + return; + + auto filename_of = [](const std::string& str) -> const char* { + const auto pos = str.find_last_of("/\\"); + return pos == std::string::npos ? str.c_str() : str.c_str() + pos + 1; + }; + + const auto selected_file_it = std::find_if(m_source_files.begin(), m_source_files.end(), + [this](const auto& pair) { return pair.second == m_current_source_file_id; }); + + const char* preview = selected_file_it != m_source_files.end() + ? filename_of(selected_file_it->first) + : ""; + + ImGui::AlignTextToFramePadding(); + ImGui::TextUnformatted("Source file:"); + ImGui::SameLine(); + + ImGui::SetNextItemWidth(DROPDAWN_SIZE); + if(ImGui::BeginCombo("##source_file", preview)) + { + for(const auto& [path, id] : m_source_files) + { + const bool selected = (id == m_current_source_file_id); + if(ImGui::Selectable(filename_of(path), selected) && !selected) + { + m_current_source_file_id = id; + m_source_code->Load({}, 0); + m_isa_code->Load({}, 0); + FetchPcSamplingForCurrentFile(); + } + if(selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } +} + +//---------------------------------------------------------------- + +BaseCodeWidget::BaseCodeWidget(LineSelection& selection) +: m_line_selection(selection) +, m_settings(SettingsManager::GetInstance()) +{ + m_selected_colour = + ImGui::GetColorU32(m_settings.GetColor(Colors::kSelection)); + m_hovered_colour = + ImGui::GetColorU32(m_settings.GetColor(Colors::kHighlightChart)); + + m_line_num_color = ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled); + m_comment_color = { 0.34f, 0.65f, 0.29f, 1.0f }; + m_table_flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_NoPadOuterX | + ImGuiTableFlags_BordersInnerV; +} + +void +BaseCodeWidget::CalcutlateLineNumberWidth(uint32_t count) +{ + for(uint32_t number = count; number >= 10; number /= 10) + m_line_num_digits++; + + m_line_num_width = + ImGui::CalcTextSize("0").x * static_cast(m_line_num_digits + 1); +} + +void +BaseCodeWidget::PushStyles() +{ + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, + ImVec2(ImGui::GetStyle().CellPadding.x, 0.0f)); + + ImGui::PushStyleColor(ImGuiCol_Header, m_settings.GetColor(Colors::kSelection)); + ImGui::PushStyleColor(ImGuiCol_HeaderHovered, + m_settings.GetColor(Colors::kHighlightChart)); + ImGui::PushStyleColor(ImGuiCol_HeaderActive, + m_settings.GetColor(Colors::kHighlightChart)); +} + +//---------------------------------------------------------------- + +SourceCodeWidget::SourceCodeWidget(LineSelection& selection) +: BaseCodeWidget(selection) +{ +} + +void +SourceCodeWidget::Load(const PcSamplingData& data, uint32_t source_file_id) +{ + m_lines.clear(); + m_line_selection = {0, 0}; + + const SourceFile* source_file = nullptr; + for(const auto& file : data.source_files) + { + if(file.id == source_file_id) + { + source_file = &file; + break; + } + } + if(!source_file) + return; + + // Build a map: source_line_id -> max total_sample_count from linked ISA lines + // so we can normalise the metadata column per source line. + std::unordered_map samples_by_source_line_id; + for(const auto& depend : data.isa_to_source_deps) + { + for(const auto& code_object : data.code_objects) + { + for(const auto& isa_line : code_object.isa_lines) + { + if(isa_line.id == depend.isa_line_id && depend.depth == 0) + { + auto& stall = samples_by_source_line_id[depend.source_line_id]; + stall = std::max(stall, isa_line.stall_record.total_sample_count); + } + } + } + } + + uint32_t max_samples = 1; + for(const auto& kv : samples_by_source_line_id) + max_samples = std::max(max_samples, kv.second); + + for(const auto& source_line : source_file->source_lines) + { + float stall = 0.0f; + auto it = samples_by_source_line_id.find(source_line.id); + if(it != samples_by_source_line_id.end()) + stall = + static_cast(it->second) / static_cast(max_samples) * 100.0f; + m_lines.push_back({ source_line.id, source_line.content, stall }); + } + + CalcutlateLineNumberWidth(m_lines.size()); +} + +void +SourceCodeWidget::Render() +{ + if(m_lines.empty()) + { + ImGui::TextDisabled("No file loaded"); + return; + } + + const int columns_count = IsStallShown() ? 3 : 2; + + if(!ImGui::BeginTable("SourceCode", columns_count, m_table_flags)) + return; + + ImGui::TableSetupScrollFreeze(0, 0); + + if(IsStallShown()) + ImGui::TableSetupColumn( + "Stalls", ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_WidthFixed, + ImGui::CalcTextSize("100.0%").x); + + ImGui::TableSetupColumn( + "#", ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_WidthFixed, + m_line_num_width); + ImGui::TableSetupColumn("Source code", ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableHeadersRow(); + PushStyles(); + + ImGuiListClipper clipper; + clipper.Begin(m_lines.size()); + + while(clipper.Step()) + { + for(int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + { + RenderLine(i, columns_count); + } + } + + ImGui::PopStyleColor(3); + ImGui::PopStyleVar(); + + ImGui::EndTable(); +} + +void +SourceCodeWidget::RenderLine(uint32_t index, uint32_t columns_count) +{ + const SourceRow& source_row = m_lines[index]; + uint32_t display_num = index + 1; + + ImGui::TableNextRow(); + + ImGui::TableSetColumnIndex(0); + ImGui::PushID(static_cast(source_row.id)); + if(ImGui::Selectable("##row", source_row.id == m_line_selection.selected_line, + ImGuiSelectableFlags_SpanAllColumns, + ImVec2(0.0f, ImGui::GetTextLineHeight()))) + { + m_line_selection.selected_line = source_row.id; + } + if(ImGui::IsItemHovered()) m_line_selection.hovered_line = source_row.id; + + if(source_row.id == m_line_selection.selected_line) + ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, m_selected_colour); + else if(source_row.id == m_line_selection.hovered_line && + m_line_selection.hovered_line != 0) + ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, m_hovered_colour); + + ImGui::SameLine(0.0f, 0.0f); + ImGui::PopID(); + + if(IsStallShown()) + { + ImGui::TextDisabled("%.1f%%", source_row.metadata); + ImGui::TableSetColumnIndex(1); + } + + ImGui::TextColored(m_line_num_color, "%*u", m_line_num_digits, display_num); + + ImGui::TableSetColumnIndex(columns_count - 1); + ImGui::TextUnformatted(source_row.content.c_str()); +} + +//---------------------------------------------------------------- + +IsaCodeWidget::IsaCodeWidget(LineSelection& selection) +: BaseCodeWidget(selection) +{ +} + +void +IsaCodeWidget::Load(const PcSamplingData& data, uint32_t code_object_id) +{ + m_entries.clear(); + m_line_selection = {0, 0}; + + const CodeObject* code_object = nullptr; + for(const auto& code_obj : data.code_objects) + { + if(code_obj.id == code_object_id) + { + code_object = &code_obj; + break; + } + } + if(!code_object) + return; + + // Build depth-0 source_line_id lookup: isa_line_id -> source_line_id + std::unordered_map source_by_isa; + for(const auto& dep : data.isa_to_source_deps) + { + if(dep.depth == 0) + source_by_isa.emplace(dep.isa_line_id, dep.source_line_id); + } + + // Find max sample count across this code object's ISA lines for normalisation + uint32_t max_samples = 1; + for(const auto& il : code_object->isa_lines) + max_samples = std::max(max_samples, il.stall_record.total_sample_count); + + for(const auto& il : code_object->isa_lines) + { + uint32_t source_line_id = 0; + auto sit = source_by_isa.find(il.id); + if(sit != source_by_isa.end()) + source_line_id = sit->second; + + float metadata = static_cast(il.stall_record.total_sample_count) / + static_cast(max_samples) * 100.0f; + + m_entries.push_back({il.id, source_line_id, il.instruction, il.comment, metadata}); + } + + CalcutlateLineNumberWidth(m_entries.size()); +} + +void +IsaCodeWidget::Render() +{ + if(m_entries.empty()) + { + ImGui::TextDisabled("No ISA loaded"); + return; + } + + const int columns_count = 2 + (IsStallShown() ? 1 : 0) + (m_show_comments ? 1 : 0); + + if(!ImGui::BeginTable("IsaCode", columns_count, m_table_flags)) + return; + + if(IsStallShown()) + ImGui::TableSetupColumn( + "Stalls", ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_WidthFixed, + ImGui::CalcTextSize("100.0%").x); + + ImGui::TableSetupColumn( + "#", ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_WidthFixed, + m_line_num_width); + ImGui::TableSetupColumn("ISA", ImGuiTableColumnFlags_WidthStretch); + + if(m_show_comments) + ImGui::TableSetupColumn("Comments", ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableHeadersRow(); + PushStyles(); + + ImGuiListClipper clipper; + clipper.Begin(m_entries.size()); + while(clipper.Step()) + { + for(uint32_t i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + { + RenderLine(i, columns_count); + } + } + + ImGui::PopStyleColor(3); + ImGui::PopStyleVar(); + + ImGui::EndTable(); +} + +void +IsaCodeWidget::RenderLine(uint32_t index, uint32_t columns_count) +{ + const IsaRow& isa_row = m_entries[index]; + const bool row_selected = isa_row.source_line_id != 0 && + isa_row.source_line_id == m_line_selection.selected_line; + const bool row_hovered = isa_row.source_line_id != 0 && + isa_row.source_line_id == m_line_selection.hovered_line; + + ImGui::TableNextRow(); + + if(row_selected) + ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, m_selected_colour); + else if(row_hovered && m_line_selection.hovered_line != 0) + ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, m_hovered_colour); + + int column = 0; + ImGui::TableSetColumnIndex(column); + ImGui::PushID(static_cast(isa_row.id)); + if(ImGui::Selectable("##row", row_selected, + ImGuiSelectableFlags_SpanAllColumns, + ImVec2(0.0f, ImGui::GetTextLineHeight()))) + { + m_line_selection.selected_line = isa_row.source_line_id; + } + if(ImGui::IsItemHovered()) + m_line_selection.hovered_line = isa_row.source_line_id; + + ImGui::SameLine(0.0f, 0.0f); + ImGui::PopID(); + + if(IsStallShown()) + { + ImGui::TextDisabled("%.1f%%", isa_row.stall); + ImGui::TableSetColumnIndex(++column); + } + + ImGui::TextColored(m_line_num_color, "%*u", m_line_num_digits, index + 1); + + ImGui::TableSetColumnIndex(++column); + ImGui::TextUnformatted(isa_row.instruction.c_str()); + + if(m_show_comments) + { + ImGui::TableSetColumnIndex(++column); + ImGui::TextColored(m_comment_color, "%s", ("//" + isa_row.comment).c_str()); + } +} + +} // namespace View +} // namespace RocProfVis diff --git a/src/view/src/compute/rocprofvis_compute_code_view.h b/src/view/src/compute/rocprofvis_compute_code_view.h new file mode 100644 index 000000000..5453534db --- /dev/null +++ b/src/view/src/compute/rocprofvis_compute_code_view.h @@ -0,0 +1,154 @@ +// Copyright Advanced Micro Devices, Inc. +// SPDX-License-Identifier: MIT + +#pragma once + +#include "widgets/rocprofvis_widget.h" +#include "rocprofvis_settings_manager.h" +#include "rocprofvis_event_manager.h" +#include "widgets/rocprofvis_split_containers.h" +#include "model/compute/rocprofvis_compute_model_types.h" + +#include +#include + +namespace RocProfVis +{ +namespace View +{ + +class SourceCodeWidget; +class IsaCodeWidget; +class DataProvider; + +struct LineSelection +{ + uint32_t hovered_line = 0; + uint32_t selected_line = 0; +}; + +class ComputeCodeView : public RocWidget +{ +public: + explicit ComputeCodeView(DataProvider& data_provider); + ~ComputeCodeView(); + + void Render() override; +private: + void RenderControlPanel(); + void RenderSourceFileDropdown(); + void SubscribeToEvents(); + void LoadData(uint32_t kernel_id); + void LoadSourceFileList(const PcSamplingData& data); + void FetchPcSamplingForCurrentFile(); + void OnPcSamplingReady(uint32_t kernel_id, uint32_t source_file_id, bool success); + + SettingsManager& m_settings; + DataProvider& m_data_provider; + + std::shared_ptr m_source_code; + std::shared_ptr m_isa_code; + LayoutItem::Ptr m_isa_layout_item; + std::shared_ptr m_horizontal_split_container; + + uint32_t m_current_source_file_id = 0; + uint32_t m_current_code_object_id = 0; + uint32_t m_current_kernel_id = 0; + uint32_t m_current_workload_id = 0; + + std::map m_source_files; + LineSelection m_line_selection; + + float m_control_panel_height; + + EventManager::SubscriptionToken m_kernel_selection_changed_token; +}; + +struct CodeLine +{ + std::string content; + float stall; +}; + +class BaseCodeWidget : public RocWidget +{ +public: + BaseCodeWidget(LineSelection& selection); + ~BaseCodeWidget() = default; + + virtual void Render() override = 0; + + bool IsStallShown() { return m_show_stall; }; + void ChangeStallVisibility(bool show) { m_show_stall = show; }; + +protected: + void CalcutlateLineNumberWidth(uint32_t count); + void PushStyles(); + + bool m_show_stall = false; + + LineSelection& m_line_selection; + uint32_t m_line_num_width = 0; + uint32_t m_line_num_digits = 1; + + SettingsManager& m_settings; + ImGuiTableFlags m_table_flags; + + ImU32 m_selected_colour; + ImU32 m_hovered_colour; + + ImVec4 m_line_num_color; + ImVec4 m_comment_color; +}; + +class SourceCodeWidget : public BaseCodeWidget +{ +public: + SourceCodeWidget(LineSelection& selection); + void Render() override; + + void Load(const PcSamplingData& data, uint32_t source_file_id); + + uint32_t GetSelectedLine() const { return m_line_selection.selected_line; } + uint32_t GetHoveredLine() const { return m_line_selection.hovered_line; } + +private: + void RenderLine(uint32_t index, uint32_t column_count); + + struct SourceRow + { + uint32_t id; + std::string content; + float metadata; + }; + + std::vector m_lines; +}; + +class IsaCodeWidget : public BaseCodeWidget +{ +public: + IsaCodeWidget(LineSelection& selection); + void Render() override; + + void Load(const PcSamplingData& data, uint32_t code_object_id); + void ShowComments(bool show) { m_show_comments = show; }; + +private: + void RenderLine(uint32_t index, uint32_t column_count); + + struct IsaRow + { + uint32_t id; + uint32_t source_line_id; + std::string instruction; + std::string comment; + float stall; + }; + + bool m_show_comments = false; + std::vector m_entries; +}; + +} // namespace View +} // namespace RocProfVis diff --git a/src/view/src/compute/rocprofvis_compute_view.cpp b/src/view/src/compute/rocprofvis_compute_view.cpp index 85e96dba9..e5fbb5184 100644 --- a/src/view/src/compute/rocprofvis_compute_view.cpp +++ b/src/view/src/compute/rocprofvis_compute_view.cpp @@ -18,6 +18,7 @@ #include "rocprofvis_settings_manager.h" #include "widgets/rocprofvis_gui_helpers.h" #include "widgets/rocprofvis_notification_manager.h" +#include "rocprofvis_compute_code_view.h" #include "spdlog/spdlog.h" @@ -169,6 +170,10 @@ ComputeView::CreateView() std::make_shared(m_data_provider, m_compute_selection), false}); + + m_code_view = std::make_shared(m_data_provider); + m_tab_container->AddTab( + TabItem{"Source Code View", "compute_code_view", m_code_view, false}); #ifdef ROCPROFVIS_DEVELOPER_MODE m_tab_container->AddTab( TabItem{"Compute Tester", "compute_tester_view", @@ -182,6 +187,7 @@ void ComputeView::DestroyView() { m_view_created = false; + m_code_view = nullptr; } bool diff --git a/src/view/src/compute/rocprofvis_compute_view.h b/src/view/src/compute/rocprofvis_compute_view.h index 64960fa6a..8dc7097c2 100644 --- a/src/view/src/compute/rocprofvis_compute_view.h +++ b/src/view/src/compute/rocprofvis_compute_view.h @@ -12,6 +12,7 @@ namespace View { class ComputeSelection; +class ComputeCodeView; class PresetBrowser; class ComputeView : public RootView @@ -43,6 +44,7 @@ class ComputeView : public RootView std::shared_ptr m_compute_selection; std::unique_ptr m_preset_browser; + std::shared_ptr m_code_view; std::shared_ptr m_tab_container; diff --git a/src/view/src/model/compute/rocprofvis_compute_data_model.cpp b/src/view/src/model/compute/rocprofvis_compute_data_model.cpp index 9980fbaab..0e605bb78 100644 --- a/src/view/src/model/compute/rocprofvis_compute_data_model.cpp +++ b/src/view/src/model/compute/rocprofvis_compute_data_model.cpp @@ -475,9 +475,19 @@ ComputeDataModel::GetKernelInfo(uint32_t workload_id, uint32_t kernel_id) const { const WorkloadInfo& workload = m_workloads.at(workload_id); if(workload.kernels.count(kernel_id)) - { return &workload.kernels.at(kernel_id); - } + } + return nullptr; +} + +KernelInfo* +ComputeDataModel::GetKernelInfoMutable(uint32_t workload_id, uint32_t kernel_id) +{ + if(m_workloads.count(workload_id)) + { + WorkloadInfo& workload = m_workloads.at(workload_id); + if(workload.kernels.count(kernel_id)) + return &workload.kernels.at(kernel_id); } return nullptr; } diff --git a/src/view/src/model/compute/rocprofvis_compute_data_model.h b/src/view/src/model/compute/rocprofvis_compute_data_model.h index 6ccdb4b60..f19db15a4 100644 --- a/src/view/src/model/compute/rocprofvis_compute_data_model.h +++ b/src/view/src/model/compute/rocprofvis_compute_data_model.h @@ -113,6 +113,7 @@ class ComputeDataModel std::vector GetKernelInfoList(uint32_t workload_id) const; const KernelInfo* GetKernelInfo(uint32_t workload_id, uint32_t kernel_id) const; + KernelInfo* GetKernelInfoMutable(uint32_t workload_id, uint32_t kernel_id); private: void OrderAvailableMetrics(WorkloadInfo& workload); diff --git a/src/view/src/model/compute/rocprofvis_compute_model_types.h b/src/view/src/model/compute/rocprofvis_compute_model_types.h index 6e36c174e..8bded6dc3 100644 --- a/src/view/src/model/compute/rocprofvis_compute_model_types.h +++ b/src/view/src/model/compute/rocprofvis_compute_model_types.h @@ -4,6 +4,7 @@ #pragma once #include "rocprofvis_controller_enums.h" +#include #include #include #include @@ -55,6 +56,84 @@ struct Point double y; }; +struct PcStallReason +{ + int32_t type_id = 0; + std::string type_name; + int32_t count = 0; +}; + +struct StallRecord +{ + uint32_t id = 0; + uint32_t isa_line_id = 0; + uint64_t dispatch_id = 0; + float avg_active_lanes = 0.0f; + uint32_t wave_issued_count = 0; + uint32_t total_sample_count = 0; + + std::vector stall_reasons; +}; + +struct IsaToIsaDep +{ + uint32_t dependent_isa_line_id = 0; + uint32_t dependency_isa_line_id = 0; +}; + +struct IsaToSourceDep +{ + uint32_t isa_line_id = 0; + uint32_t source_line_id = 0; + uint32_t depth = 0; +}; + +struct IsaLine +{ + uint32_t id = 0; + uint64_t code_object_offset = 0; + uint32_t instruction_type_id = 0; + std::string instruction; + std::string comment; + + StallRecord stall_record; + std::vector + source_line_ids; +}; + +struct CodeObject +{ + uint32_t id = 0; + std::string uri; + std::string content_checksum; + std::vector isa_lines; +}; + +struct SourceLine +{ + uint32_t id = 0; + uint32_t line_number = 0; + std::string content; + std::vector isa_line_ids; +}; + +struct SourceFile +{ + uint32_t id = 0; + std::string file_path; + std::string content_checksum; + + std::vector source_lines; +}; + +struct PcSamplingData +{ + std::vector code_objects; + std::vector source_files; + std::vector isa_to_isa_deps; + std::vector isa_to_source_deps; +}; + struct KernelInfo { enum DispatchMetric @@ -82,6 +161,7 @@ struct KernelInfo std::string name; std::array dispatch_metrics; Roofline roofline; + PcSamplingData pc_sampling_data; }; struct WorkloadInfo diff --git a/src/view/src/rocprofvis_data_provider.cpp b/src/view/src/rocprofvis_data_provider.cpp index f88e58213..4b161d450 100644 --- a/src/view/src/rocprofvis_data_provider.cpp +++ b/src/view/src/rocprofvis_data_provider.cpp @@ -2954,6 +2954,11 @@ DataProvider::ProcessRequest(RequestInfo& req) ProcessMetricPivotTable(req); break; } + case RequestType::kFetchPcSampling: + { + ProcessPcSamplingRequest(req); + break; + } #endif default: { @@ -4349,6 +4354,108 @@ void DataProvider::SetFetchMetricsCallback( m_metrics_fetch_callback = callback; } +void DataProvider::SetFetchPcSamplingCallback( + const std::function& callback) +{ + m_pc_sampling_fetch_callback = callback; +} + +bool +DataProvider::FetchPcSampling(const PcSamplingRequestParams& params) +{ + if(m_state != ProviderState::kReady) + { + spdlog::debug("Cannot fetch PC sampling, provider not ready, state: {}", + static_cast(m_state)); + return false; + } + + // Use kernel_id + source_file_id as the unique request key. + uint64_t request_id = RequestIdBuilder::MakeClientRequestId( + RequestType::kFetchPcSampling, + (static_cast(params.m_kernel_id) << 32) | params.m_source_file_id); + + // Cancel any in-flight request for the same kernel (different source file selection). + for(auto it = m_requests.begin(); it != m_requests.end(); ) + { + if(it->second.request_type == RequestType::kFetchPcSampling) + { + if(it->second.request_future) + rocprofvis_controller_future_cancel(it->second.request_future); + it = m_requests.erase(it); + } + else + { + ++it; + } + } + + rocprofvis_controller_future_t* future = rocprofvis_controller_future_alloc(); + rocprofvis_controller_arguments_t* args = rocprofvis_controller_arguments_alloc(); + + // Get the PcSampling handle for this kernel by iterating workloads on the controller. + rocprofvis_handle_t* pc_handle = nullptr; + { + uint64_t num_workloads = 0; + rocprofvis_controller_get_uint64(m_trace_controller, kRPVControllerNumWorkloads, 0, &num_workloads); + for(uint64_t wi = 0; wi < num_workloads && !pc_handle; wi++) + { + rocprofvis_handle_t* workload_handle = nullptr; + rocprofvis_controller_get_object(m_trace_controller, kRPVControllerWorkloadIndexed, wi, &workload_handle); + if(!workload_handle) continue; + + uint64_t workload_id = 0; + rocprofvis_controller_get_uint64(workload_handle, kRPVControllerWorkloadId, 0, &workload_id); + if(static_cast(workload_id) != params.m_workload_id) continue; + + uint64_t num_kernels = 0; + rocprofvis_controller_get_uint64(workload_handle, kRPVControllerWorkloadNumKernels, 0, &num_kernels); + for(uint64_t ki = 0; ki < num_kernels; ki++) + { + rocprofvis_handle_t* kernel_handle = nullptr; + rocprofvis_controller_get_object(workload_handle, kRPVControllerWorkloadKernelIndexed, ki, &kernel_handle); + if(!kernel_handle) continue; + + uint64_t kernel_id = 0; + rocprofvis_controller_get_uint64(kernel_handle, kRPVControllerKernelId, 0, &kernel_id); + if(static_cast(kernel_id) != params.m_kernel_id) continue; + + rocprofvis_controller_get_object(kernel_handle, kRPVControllerKernelPcSampling, 0, &pc_handle); + break; + } + } + } + + if(!future || !args || !pc_handle) + { + if(future) rocprofvis_controller_future_free(future); + if(args) rocprofvis_controller_arguments_free(args); + return false; + } + + rocprofvis_controller_set_uint64(args, kRPVControllerPcSamplingArgsWorkloadId, 0, params.m_workload_id); + rocprofvis_controller_set_uint64(args, kRPVControllerPcSamplingArgsKernelId, 0, params.m_kernel_id); + rocprofvis_controller_set_uint64(args, kRPVControllerPcSamplingArgsSourceFileId, 0, params.m_source_file_id); + + rocprofvis_result_t result = rocprofvis_controller_pc_sampling_fetch_async( + m_trace_controller, args, future, pc_handle); + + if(result == kRocProfVisResultSuccess) + { + m_requests.emplace( + request_id, + RequestInfo{ request_id, future, nullptr, pc_handle, args, + RequestState::kLoading, RequestType::kFetchPcSampling, + std::make_shared(params) }); + return true; + } + + rocprofvis_controller_future_free(future); + rocprofvis_controller_arguments_free(args); + spdlog::error("Failed to fetch PC sampling, result: {}", static_cast(result)); + return false; +} + void DataProvider::ProcessLoadComputeTrace(RequestInfo& req) { @@ -4368,361 +4475,663 @@ DataProvider::ProcessLoadComputeTrace(RequestInfo& req) rocprofvis_result_t result = rocprofvis_controller_get_uint64( m_trace_controller, kRPVControllerNumWorkloads, 0, &num_workloads); ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - for(uint64_t i = 0; i < num_workloads; i++) - { - rocprofvis_handle_t* workload_handle = nullptr; - result = rocprofvis_controller_get_object( - m_trace_controller, kRPVControllerWorkloadIndexed, i, &workload_handle); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess && workload_handle); - uint64_t uint64_data = 0; - WorkloadInfo workload; + for(uint64_t workload_index = 0; workload_index < num_workloads; workload_index++) + { + LoadWorkload(workload_index); + } + m_state = ProviderState::kReady; + + if(m_trace_data_ready_callback) + { + m_trace_data_ready_callback(m_model.GetTraceFilePath(), kRocProfVisResultSuccess); + } +} + +inline void +DataProvider::LoadWorkload(uint64_t workload_index) +{ + rocprofvis_handle_t* workload_handle = nullptr; + rocprofvis_result_t result = rocprofvis_controller_get_object( + m_trace_controller, kRPVControllerWorkloadIndexed, workload_index, + &workload_handle); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess && workload_handle); + uint64_t uint64_data = 0; + WorkloadInfo workload; + result = rocprofvis_controller_get_uint64(workload_handle, kRPVControllerWorkloadId, + 0, &uint64_data); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + workload.id = static_cast(uint64_data); + workload.name = GetString(workload_handle, kRPVControllerWorkloadName, 0); + + LoadSystemInfo(workload, workload_handle); + + LoadProfilingConfig(workload, workload_handle); + + LoadMetricList(workload, workload_handle); + + LoadValueNames(workload, workload_handle); + + LoadKernels(workload, workload_handle); + + LoadRoofLine(workload, workload_handle); + + m_compute_model.AddWorkload(workload); +} + +inline void +DataProvider::LoadSystemInfo(WorkloadInfo& workload, + rocprofvis_handle_t* workload_handle) +{ + uint64_t num_entries = 0; + rocprofvis_result_t result = rocprofvis_controller_get_uint64( + workload_handle, kRPVControllerWorkloadSystemInfoNumEntries, 0, &num_entries); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + workload.system_info.resize(2); + workload.system_info[0].resize(num_entries); + workload.system_info[1].resize(num_entries); + for(uint64_t i = 0; i < num_entries; i++) + { + workload.system_info[0][i] = GetString( + workload_handle, kRPVControllerWorkloadSystemInfoEntryNameIndexed, i); + workload.system_info[1][i] = GetString( + workload_handle, kRPVControllerWorkloadSystemInfoEntryValueIndexed, i); + } +} + +inline void +DataProvider::LoadProfilingConfig(WorkloadInfo& workload, + rocprofvis_handle_t* workload_handle) +{ + uint64_t num_entries = 0; + rocprofvis_result_t result = rocprofvis_controller_get_uint64( + workload_handle, kRPVControllerWorkloadConfigurationNumEntries, 0, &num_entries); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + workload.profiling_config.resize(2); + workload.profiling_config[0].resize(num_entries); + workload.profiling_config[1].resize(num_entries); + for(uint64_t i = 0; i < num_entries; i++) + { + workload.profiling_config[0][i] = GetString( + workload_handle, kRPVControllerWorkloadConfigurationEntryNameIndexed, i); + workload.profiling_config[1][i] = GetString( + workload_handle, kRPVControllerWorkloadConfigurationEntryValueIndexed, i); + } +} + +inline void +DataProvider::LoadMetricList(WorkloadInfo& workload, rocprofvis_handle_t* workload_handle) +{ + uint64_t uint64_data = 0; + uint64_t num_entries = 0; + rocprofvis_result_t result = rocprofvis_controller_get_uint64( + workload_handle, kRPVControllerWorkloadNumAvailableMetrics, 0, &num_entries); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + workload.available_metrics.list.resize(num_entries); + for(uint64_t j = 0; j < num_entries; j++) + { result = rocprofvis_controller_get_uint64( - workload_handle, kRPVControllerWorkloadId, 0, &uint64_data); + workload_handle, kRPVControllerWorkloadAvailableMetricCategoryIdIndexed, j, + &uint64_data); ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - workload.id = static_cast(uint64_data); - workload.name = GetString(workload_handle, kRPVControllerWorkloadName, 0); - uint64_t num_entries = 0; - result = rocprofvis_controller_get_uint64( - workload_handle, kRPVControllerWorkloadSystemInfoNumEntries, 0, &num_entries); + workload.available_metrics.list[j].index = static_cast(j); + workload.available_metrics.list[j].category_id = + static_cast(uint64_data); + result = rocprofvis_controller_get_uint64( + workload_handle, kRPVControllerWorkloadAvailableMetricTableIdIndexed, j, + &uint64_data); ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - workload.system_info.resize(2); - workload.system_info[0].resize(num_entries); - workload.system_info[1].resize(num_entries); - for(uint64_t j = 0; j < num_entries; j++) - { - workload.system_info[0][j] = GetString( - workload_handle, kRPVControllerWorkloadSystemInfoEntryNameIndexed, j); - workload.system_info[1][j] = GetString( - workload_handle, kRPVControllerWorkloadSystemInfoEntryValueIndexed, j); - } - num_entries = 0; - result = rocprofvis_controller_get_uint64( - workload_handle, kRPVControllerWorkloadConfigurationNumEntries, 0, - &num_entries); + workload.available_metrics.list[j].table_id = static_cast(uint64_data); + workload.available_metrics.list[j].name = GetString( + workload_handle, kRPVControllerWorkloadAvailableMetricNameIndexed, j); + workload.available_metrics.list[j].description = GetString( + workload_handle, kRPVControllerWorkloadAvailableMetricDescriptionIndexed, j); + workload.available_metrics.list[j].unit = GetString( + workload_handle, kRPVControllerWorkloadAvailableMetricUnitIndexed, j); + AvailableMetrics::Category& category = + workload.available_metrics + .tree[workload.available_metrics.list[j].category_id]; + category.id = workload.available_metrics.list[j].category_id; + category.name = GetString( + workload_handle, kRPVControllerWorkloadAvailableMetricCategoryNameIndexed, j); + AvailableMetrics::Table& table = + category.tables[workload.available_metrics.list[j].table_id]; + table.id = workload.available_metrics.list[j].table_id; + table.name = GetString(workload_handle, + kRPVControllerWorkloadAvailableMetricTableNameIndexed, j); + // Last position of id is not returned, for now assume index... + workload.available_metrics.list[j].id = + static_cast(table.entries.size()); + table.entries.insert({ static_cast(table.entries.size()), + workload.available_metrics.list[j] }); + } +} + +inline void +DataProvider::LoadValueNames(WorkloadInfo& workload, rocprofvis_handle_t* workload_handle) +{ + uint64_t num_value_names = 0; + rocprofvis_result_t result = rocprofvis_controller_get_uint64( + workload_handle, kRPVControllerWorkloadNumMetricValueNames, 0, &num_value_names); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + for(uint64_t k = 0; k < num_value_names; k++) + { + uint64_t cat_id = 0; + uint64_t tbl_id = 0; + result = rocprofvis_controller_get_uint64( + workload_handle, kRPVControllerWorkloadMetricValueNameCategoryIdIndexed, k, + &cat_id); ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - workload.profiling_config.resize(2); - workload.profiling_config[0].resize(num_entries); - workload.profiling_config[1].resize(num_entries); - for(uint64_t j = 0; j < num_entries; j++) - { - workload.profiling_config[0][j] = GetString( - workload_handle, kRPVControllerWorkloadConfigurationEntryNameIndexed, j); - workload.profiling_config[1][j] = GetString( - workload_handle, kRPVControllerWorkloadConfigurationEntryValueIndexed, j); - } - num_entries = 0; - result = rocprofvis_controller_get_uint64( - workload_handle, kRPVControllerWorkloadNumAvailableMetrics, 0, &num_entries); + result = rocprofvis_controller_get_uint64( + workload_handle, kRPVControllerWorkloadMetricValueNameTableIdIndexed, k, + &tbl_id); ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - workload.available_metrics.list.resize(num_entries); - for(uint64_t j = 0; j < num_entries; j++) + std::string name = GetString( + workload_handle, kRPVControllerWorkloadMetricValueNameStringIndexed, k); + auto cat_it = workload.available_metrics.tree.find(static_cast(cat_id)); + if(cat_it != workload.available_metrics.tree.end()) { - result = rocprofvis_controller_get_uint64( - workload_handle, kRPVControllerWorkloadAvailableMetricCategoryIdIndexed, - j, &uint64_data); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - workload.available_metrics.list[j].index = static_cast(j); - workload.available_metrics.list[j].category_id = - static_cast(uint64_data); - result = rocprofvis_controller_get_uint64( - workload_handle, kRPVControllerWorkloadAvailableMetricTableIdIndexed, j, - &uint64_data); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - workload.available_metrics.list[j].table_id = - static_cast(uint64_data); - workload.available_metrics.list[j].name = GetString( - workload_handle, kRPVControllerWorkloadAvailableMetricNameIndexed, j); - workload.available_metrics.list[j].description = - GetString(workload_handle, - kRPVControllerWorkloadAvailableMetricDescriptionIndexed, j); - workload.available_metrics.list[j].unit = GetString( - workload_handle, kRPVControllerWorkloadAvailableMetricUnitIndexed, j); - AvailableMetrics::Category& category = - workload.available_metrics - .tree[workload.available_metrics.list[j].category_id]; - category.id = workload.available_metrics.list[j].category_id; - category.name = - GetString(workload_handle, - kRPVControllerWorkloadAvailableMetricCategoryNameIndexed, j); - AvailableMetrics::Table& table = - category.tables[workload.available_metrics.list[j].table_id]; - table.id = workload.available_metrics.list[j].table_id; - table.name = - GetString(workload_handle, - kRPVControllerWorkloadAvailableMetricTableNameIndexed, j); - // Last position of id is not returned, for now assume index... - workload.available_metrics.list[j].id = - static_cast(table.entries.size()); - table.entries.insert({ static_cast(table.entries.size()), - workload.available_metrics.list[j] }); + auto tbl_it = cat_it->second.tables.find(static_cast(tbl_id)); + if(tbl_it != cat_it->second.tables.end()) + { + tbl_it->second.value_names.push_back(std::move(name)); + } } - uint64_t num_value_names = 0; + } +} + +inline void +DataProvider::LoadKernels(WorkloadInfo& workload, rocprofvis_handle_t* workload_handle) +{ + uint64_t uint64_data = 0; + uint64_t num_entries = 0; + rocprofvis_result_t result = rocprofvis_controller_get_uint64( + workload_handle, kRPVControllerWorkloadNumKernels, 0, &num_entries); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + for(uint64_t j = 0; j < num_entries; j++) + { + rocprofvis_handle_t* kernel_handle = nullptr; + result = rocprofvis_controller_get_object( + workload_handle, kRPVControllerWorkloadKernelIndexed, j, &kernel_handle); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess && kernel_handle); + KernelInfo kernel; + result = rocprofvis_controller_get_uint64(kernel_handle, kRPVControllerKernelId, + 0, &uint64_data); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + kernel.id = static_cast(uint64_data); + kernel.name = GetString(kernel_handle, kRPVControllerKernelName, 0); + kernel.dispatch_metrics = {}; + result = rocprofvis_controller_get_uint64( + kernel_handle, kRPVControllerKernelInvocationCount, 0, &uint64_data); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + kernel.dispatch_metrics[KernelInfo::InvocationCount] = uint64_data; result = rocprofvis_controller_get_uint64( - workload_handle, kRPVControllerWorkloadNumMetricValueNames, 0, - &num_value_names); + kernel_handle, kRPVControllerKernelDurationTotal, 0, &uint64_data); ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - for(uint64_t k = 0; k < num_value_names; k++) + kernel.dispatch_metrics[KernelInfo::DurationTotal] = uint64_data; + result = rocprofvis_controller_get_uint64( + kernel_handle, kRPVControllerKernelDurationMin, 0, &uint64_data); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + kernel.dispatch_metrics[KernelInfo::DurationMin] = + static_cast(uint64_data); + result = rocprofvis_controller_get_uint64( + kernel_handle, kRPVControllerKernelDurationMax, 0, &uint64_data); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + kernel.dispatch_metrics[KernelInfo::DurationMax] = + static_cast(uint64_data); + result = rocprofvis_controller_get_uint64( + kernel_handle, kRPVControllerKernelDurationMean, 0, &uint64_data); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + kernel.dispatch_metrics[KernelInfo::DurationMean] = + static_cast(uint64_data); + result = rocprofvis_controller_get_uint64( + kernel_handle, kRPVControllerKernelDurationMedian, 0, &uint64_data); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + kernel.dispatch_metrics[KernelInfo::DurationMedian] = + static_cast(uint64_data); + // Load only the source file list eagerly (for the dropdown). + // Full ISA/source/stall data is loaded on-demand via FetchPcSampling. { - uint64_t cat_id = 0; - uint64_t tbl_id = 0; - result = rocprofvis_controller_get_uint64( - workload_handle, - kRPVControllerWorkloadMetricValueNameCategoryIdIndexed, k, &cat_id); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - result = rocprofvis_controller_get_uint64( - workload_handle, - kRPVControllerWorkloadMetricValueNameTableIdIndexed, k, &tbl_id); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - std::string name = GetString( - workload_handle, - kRPVControllerWorkloadMetricValueNameStringIndexed, k); - auto cat_it = - workload.available_metrics.tree.find(static_cast(cat_id)); - if(cat_it != workload.available_metrics.tree.end()) + rocprofvis_handle_t* pc_handle = nullptr; + if(kRocProfVisResultSuccess == rocprofvis_controller_get_object( + kernel_handle, kRPVControllerKernelPcSampling, 0, &pc_handle) && pc_handle) { - auto tbl_it = - cat_it->second.tables.find(static_cast(tbl_id)); - if(tbl_it != cat_it->second.tables.end()) - { - tbl_it->second.value_names.push_back(std::move(name)); - } + LoadPcSamplingSourceFiles(kernel, pc_handle); } } - num_entries = 0; - result = rocprofvis_controller_get_uint64( - workload_handle, kRPVControllerWorkloadNumKernels, 0, &num_entries); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - for(uint64_t j = 0; j < num_entries; j++) + workload.kernels[kernel.id] = std::move(kernel); + } +} + +inline void +DataProvider::LoadPcSamplingData(KernelInfo& kernel, rocprofvis_handle_t* kernel_handle) +{ + rocprofvis_handle_t* pc_handle = nullptr; + if(kRocProfVisResultSuccess != rocprofvis_controller_get_object( + kernel_handle, kRPVControllerKernelPcSampling, 0, &pc_handle) || !pc_handle) + return; + + LoadPcSamplingCodeObjects(kernel, pc_handle); + LoadPcSamplingJunctions(kernel, pc_handle); + LoadPcSamplingStallRecords(kernel, pc_handle); + LoadPcSamplingStallReasonCounts(kernel, pc_handle); + LoadPcSamplingSourceFiles(kernel, pc_handle); +} + +inline void +DataProvider::LoadPcSamplingCodeObjects(KernelInfo& kernel, rocprofvis_handle_t* pc_handle) +{ + uint64_t num_code_objects = 0; + if(kRocProfVisResultSuccess != rocprofvis_controller_get_uint64( + pc_handle, kRPVControllerPCSamplingNumCodeObjects, 0, &num_code_objects)) + return; + + kernel.pc_sampling_data.code_objects.resize(num_code_objects); + for(uint64_t i = 0; i < num_code_objects; i++) + { + uint64_t id = 0; + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingCodeObjectId, i, &id); + kernel.pc_sampling_data.code_objects[i].id = static_cast(id); + kernel.pc_sampling_data.code_objects[i].uri = GetString(pc_handle, kRPVControllerPCSamplingCodeObjectUri, i); + kernel.pc_sampling_data.code_objects[i].content_checksum = GetString(pc_handle, kRPVControllerPCSamplingCodeObjectChecksum, i); + } + + uint64_t num_isa_lines = 0; + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingNumIsaLines, 0, &num_isa_lines); + for(uint64_t ii = 0; ii < num_isa_lines; ii++) + { + uint64_t co_id = 0; + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingIsaLineCodeObjectId, ii, &co_id); + for(uint64_t i = 0; i < num_code_objects; i++) { - rocprofvis_handle_t* kernel_handle = nullptr; - result = rocprofvis_controller_get_object( - workload_handle, kRPVControllerWorkloadKernelIndexed, j, &kernel_handle); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess && kernel_handle); - KernelInfo kernel; - result = rocprofvis_controller_get_uint64( - kernel_handle, kRPVControllerKernelId, 0, &uint64_data); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - kernel.id = static_cast(uint64_data); - kernel.name = GetString(kernel_handle, kRPVControllerKernelName, 0); - kernel.dispatch_metrics = {}; - result = rocprofvis_controller_get_uint64( - kernel_handle, kRPVControllerKernelInvocationCount, 0, &uint64_data); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - kernel.dispatch_metrics[KernelInfo::InvocationCount] = uint64_data; - result = rocprofvis_controller_get_uint64( - kernel_handle, kRPVControllerKernelDurationTotal, 0, &uint64_data); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - kernel.dispatch_metrics[KernelInfo::DurationTotal] = uint64_data; - result = rocprofvis_controller_get_uint64( - kernel_handle, kRPVControllerKernelDurationMin, 0, &uint64_data); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - kernel.dispatch_metrics[KernelInfo::DurationMin] = - static_cast(uint64_data); - result = rocprofvis_controller_get_uint64( - kernel_handle, kRPVControllerKernelDurationMax, 0, &uint64_data); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - kernel.dispatch_metrics[KernelInfo::DurationMax] = - static_cast(uint64_data); - result = rocprofvis_controller_get_uint64( - kernel_handle, kRPVControllerKernelDurationMean, 0, &uint64_data); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - kernel.dispatch_metrics[KernelInfo::DurationMean] = - static_cast(uint64_data); - result = rocprofvis_controller_get_uint64( - kernel_handle, kRPVControllerKernelDurationMedian, 0, &uint64_data); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - kernel.dispatch_metrics[KernelInfo::DurationMedian] = - static_cast(uint64_data); - workload.kernels[kernel.id] = std::move(kernel); + if(kernel.pc_sampling_data.code_objects[i].id == static_cast(co_id)) + { + kernel.pc_sampling_data.code_objects[i].isa_lines.emplace_back(); + LoadPcSamplingIsaLine(kernel.pc_sampling_data.code_objects[i].isa_lines.back(), pc_handle, ii); + break; + } } - rocprofvis_handle_t* roofline_handle = nullptr; - result = rocprofvis_controller_get_object( - workload_handle, kRPVControllerWorkloadRoofline, 0, &roofline_handle); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess && roofline_handle); - double double_data = 0.0; - num_entries = 0; - result = rocprofvis_controller_get_uint64( - roofline_handle, kRPVControllerRooflineNumCeilingsRidge, 0, &num_entries); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - workload.roofline.max = { DBL_MIN, DBL_MIN }; - workload.roofline.min = { DBL_MAX, DBL_MAX }; - std::unordered_map< - rocprofvis_controller_roofline_ceiling_compute_type_t, - std::unordered_map> - compute_ridge; - std::unordered_map< - rocprofvis_controller_roofline_ceiling_bandwidth_type_t, - std::unordered_map> - bandwidth_ridge; - for(uint64_t j = 0; j < num_entries; j++) + } +} + +inline void +DataProvider::LoadPcSamplingIsaLine(IsaLine& isa_line, rocprofvis_handle_t* pc_handle, uint64_t index) +{ + uint64_t isa_id = 0; + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingIsaLineId, index, &isa_id); + isa_line.id = static_cast(isa_id); + uint64_t offset = 0; + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingIsaLineCodeObjectOffset, index, &offset); + isa_line.code_object_offset = offset; + uint64_t type_id = 0; + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingIsaLineInstructionTypeId, index, &type_id); + isa_line.instruction_type_id = static_cast(type_id); + isa_line.instruction = GetString(pc_handle, kRPVControllerPCSamplingIsaLineInstruction, index); + isa_line.comment = GetString(pc_handle, kRPVControllerPCSamplingIsaLineComment, index); +} + +inline void +DataProvider::LoadPcSamplingJunctions(KernelInfo& kernel, rocprofvis_handle_t* pc_handle) +{ + uint64_t num_isa_to_isa = 0; + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingNumIsaToIsaDeps, 0, &num_isa_to_isa); + kernel.pc_sampling_data.isa_to_isa_deps.resize(num_isa_to_isa); + for(uint64_t i = 0; i < num_isa_to_isa; i++) + { + uint64_t dependent = 0, dependency = 0; + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingIsaToIsaDependentIsaLineId, i, &dependent); + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingIsaToIsaDependencyIsaLineId, i, &dependency); + kernel.pc_sampling_data.isa_to_isa_deps[i].dependent_isa_line_id = static_cast(dependent); + kernel.pc_sampling_data.isa_to_isa_deps[i].dependency_isa_line_id = static_cast(dependency); + } + + uint64_t num_isa_to_source = 0; + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingNumIsaToSourceDeps, 0, &num_isa_to_source); + kernel.pc_sampling_data.isa_to_source_deps.resize(num_isa_to_source); + for(uint64_t i = 0; i < num_isa_to_source; i++) + { + uint64_t isa_id = 0, source_id = 0, depth = 0; + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingIsaToSourceIsaLineId, i, &isa_id); + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingIsaToSourceSourceLineId, i, &source_id); + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingIsaToSourceDepth, i, &depth); + kernel.pc_sampling_data.isa_to_source_deps[i].isa_line_id = static_cast(isa_id); + kernel.pc_sampling_data.isa_to_source_deps[i].source_line_id = static_cast(source_id); + kernel.pc_sampling_data.isa_to_source_deps[i].depth = static_cast(depth); + } +} + +inline void +DataProvider::LoadPcSamplingStallRecords(KernelInfo& kernel, rocprofvis_handle_t* pc_handle) +{ + uint64_t num_stall_records = 0; + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingNumStallRecords, 0, &num_stall_records); + + for(uint64_t i = 0; i < num_stall_records; i++) + { + uint64_t isa_line_id = 0; + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingStallRecordIsaLineId, i, &isa_line_id); + + for(auto& code_object : kernel.pc_sampling_data.code_objects) { - rocprofvis_controller_roofline_ceiling_compute_type_t compute_type; - rocprofvis_controller_roofline_ceiling_bandwidth_type_t bandwidth_type; - Point position; - result = rocprofvis_controller_get_uint64( - roofline_handle, kRPVControllerRooflineCeilingRidgeComputeTypeIndexed, j, - &uint64_data); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - compute_type = - static_cast( - uint64_data); - result = rocprofvis_controller_get_uint64( - roofline_handle, kRPVControllerRooflineCeilingRidgeBandwidthTypeIndexed, - j, &uint64_data); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - bandwidth_type = - static_cast( - uint64_data); - result = rocprofvis_controller_get_double( - roofline_handle, kRPVControllerRooflineCeilingRidgeXIndexed, j, - &double_data); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - position.x = double_data; - result = rocprofvis_controller_get_double( - roofline_handle, kRPVControllerRooflineCeilingRidgeYIndexed, j, - &double_data); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - position.y = double_data; - compute_ridge[compute_type][bandwidth_type] = position; - bandwidth_ridge[bandwidth_type][compute_type] = std::move(position); + for(auto& isa_line : code_object.isa_lines) + { + if(isa_line.id != static_cast(isa_line_id)) + continue; + + uint64_t id = 0, dispatch_id = 0, wave_issued = 0, total_samples = 0; + double avg_lanes = 0.0; + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingStallRecordId, i, &id); + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingStallRecordDispatchId, i, &dispatch_id); + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingStallRecordWaveIssuedCount, i, &wave_issued); + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingStallRecordTotalSampleCount, i, &total_samples); + rocprofvis_controller_get_double(pc_handle, kRPVControllerPCSamplingStallRecordAvgActiveLanes, i, &avg_lanes); + + isa_line.stall_record.id = static_cast(id); + isa_line.stall_record.isa_line_id = static_cast(isa_line_id); + isa_line.stall_record.dispatch_id = dispatch_id; + isa_line.stall_record.avg_active_lanes = static_cast(avg_lanes); + isa_line.stall_record.wave_issued_count = static_cast(wave_issued); + isa_line.stall_record.total_sample_count = static_cast(total_samples); + break; + } } - num_entries = 0; - result = rocprofvis_controller_get_uint64( - roofline_handle, kRPVControllerRooflineNumCeilingsCompute, 0, &num_entries); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - for(uint64_t j = 0; j < num_entries; j++) + } +} + +inline void +DataProvider::LoadPcSamplingStallReasonCounts(KernelInfo& kernel, rocprofvis_handle_t* pc_handle) +{ + uint64_t num_reason_counts = 0; + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingNumStallReasonCounts, 0, &num_reason_counts); + + for(uint64_t i = 0; i < num_reason_counts; i++) + { + uint64_t record_id = 0, type_id = 0, count = 0; + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingStallReasonRecordId, i, &record_id); + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingStallReasonTypeId, i, &type_id); + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingStallReasonCount, i, &count); + + for(auto& code_object : kernel.pc_sampling_data.code_objects) { - WorkloadInfo::Roofline::Ceiling ceiling; - result = rocprofvis_controller_get_uint64( - roofline_handle, kRPVControllerRooflineCeilingComputeTypeIndexed, j, - &uint64_data); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - ceiling.compute_type = - static_cast( - uint64_data); - ROCPROFVIS_ASSERT(compute_ridge.count(ceiling.compute_type) > 0); - for(const std::pair< - const rocprofvis_controller_roofline_ceiling_bandwidth_type_t, Point>& - ridge : compute_ridge.at(ceiling.compute_type)) + for(auto& isa_line : code_object.isa_lines) { - ceiling.bandwidth_type = ridge.first; - ceiling.position.p1 = ridge.second; - result = rocprofvis_controller_get_double( - roofline_handle, kRPVControllerRooflineCeilingComputeXIndexed, j, - &double_data); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - ceiling.position.p2.x = double_data; - result = rocprofvis_controller_get_double( - roofline_handle, kRPVControllerRooflineCeilingComputeYIndexed, j, - &double_data); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - ceiling.position.p2.y = double_data; - result = rocprofvis_controller_get_double( - roofline_handle, kRPVControllerRooflineCeilingComputeThroughputIndexed, j, - &double_data); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - ceiling.throughput = double_data; - workload.roofline.max.x = - std::max(workload.roofline.max.x, ceiling.position.p2.x); - workload.roofline.max.y = - std::max(workload.roofline.max.y, ceiling.position.p2.y); - workload.roofline - .ceiling_compute[ceiling.compute_type][ceiling.bandwidth_type] = - ceiling; + if(isa_line.stall_record.id != static_cast(record_id)) + continue; + + isa_line.stall_record.stall_reasons.push_back({ + static_cast(type_id), + {}, + static_cast(count) + }); + break; } } - num_entries = 0; - result = rocprofvis_controller_get_uint64( - roofline_handle, kRPVControllerRooflineNumCeilingsBandwidth, 0, &num_entries); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - for(uint64_t j = 0; j < num_entries; j++) + } +} + +inline void +DataProvider::LoadPcSamplingSourceFiles(KernelInfo& kernel, rocprofvis_handle_t* pc_handle) +{ + uint64_t num_source_files = 0; + if(kRocProfVisResultSuccess != rocprofvis_controller_get_uint64( + pc_handle, kRPVControllerPCSamplingNumSourceFiles, 0, &num_source_files)) + return; + + kernel.pc_sampling_data.source_files.resize(num_source_files); + for(uint64_t i = 0; i < num_source_files; i++) + { + uint64_t id = 0; + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingSourceFileId, i, &id); + kernel.pc_sampling_data.source_files[i].id = static_cast(id); + kernel.pc_sampling_data.source_files[i].file_path = GetString(pc_handle, kRPVControllerPCSamplingFilePath, i); + kernel.pc_sampling_data.source_files[i].content_checksum = GetString(pc_handle, kRPVControllerPCSamplingSourceFileChecksum, i); + } + + uint64_t num_source_lines = 0; + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingNumSourceLines, 0, &num_source_lines); + for(uint64_t li = 0; li < num_source_lines; li++) + { + uint64_t sf_id = 0; + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingSourceLineSourceFileId, li, &sf_id); + for(uint64_t i = 0; i < num_source_files; i++) { - WorkloadInfo::Roofline::Ceiling ceiling; - result = rocprofvis_controller_get_uint64( - roofline_handle, kRPVControllerRooflineCeilingBandwidthTypeIndexed, j, - &uint64_data); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - ceiling.bandwidth_type = - static_cast( - uint64_data); - ROCPROFVIS_ASSERT(bandwidth_ridge.count(ceiling.bandwidth_type) > 0); - for(const std::pair< - const rocprofvis_controller_roofline_ceiling_compute_type_t, Point>& - ridge : bandwidth_ridge.at(ceiling.bandwidth_type)) + if(kernel.pc_sampling_data.source_files[i].id == static_cast(sf_id)) { - ceiling.compute_type = ridge.first; - result = rocprofvis_controller_get_double( - roofline_handle, kRPVControllerRooflineCeilingBandwidthXIndexed, j, - &double_data); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - ceiling.position.p1.x = double_data; - result = rocprofvis_controller_get_double( - roofline_handle, kRPVControllerRooflineCeilingBandwidthYIndexed, j, - &double_data); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - ceiling.position.p1.y = double_data; - ceiling.position.p2 = ridge.second; - result = rocprofvis_controller_get_double( - roofline_handle, kRPVControllerRooflineCeilingBandwidthThroughputIndexed, j, - &double_data); - ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - ceiling.throughput = double_data; - workload.roofline.min.x = - std::min(workload.roofline.min.x, ceiling.position.p1.x); - workload.roofline.min.y = - std::min(workload.roofline.min.y, ceiling.position.p1.y); - workload.roofline - .ceiling_bandwidth[ceiling.bandwidth_type][ceiling.compute_type] = - ceiling; + kernel.pc_sampling_data.source_files[i].source_lines.emplace_back(); + LoadPcSamplingSourceLine(kernel.pc_sampling_data.source_files[i].source_lines.back(), pc_handle, li); + break; } } - num_entries = 0; - result = rocprofvis_controller_get_uint64( - roofline_handle, kRPVControllerRooflineNumKernels, 0, &num_entries); + } +} + +inline void +DataProvider::LoadPcSamplingSourceLine(SourceLine& source_line, rocprofvis_handle_t* pc_handle, uint64_t index) +{ + uint64_t line_id = 0; + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingSourceLineId, index, &line_id); + source_line.id = static_cast(line_id); + uint64_t line_number = 0; + rocprofvis_controller_get_uint64(pc_handle, kRPVControllerPCSamplingSourceLineNumber, index, &line_number); + source_line.line_number = static_cast(line_number); + source_line.content = GetString(pc_handle, kRPVControllerPCSamplingSourceLineContent, index); +} + +inline void +DataProvider::LoadRoofLine(WorkloadInfo& workload, rocprofvis_handle_t* workload_handle) +{ + rocprofvis_handle_t* roofline_handle = nullptr; + rocprofvis_result_t result = rocprofvis_controller_get_object( + workload_handle, kRPVControllerWorkloadRoofline, 0, &roofline_handle); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess && roofline_handle); + + compute_ridge_map compute_ridge; + bandwidth_ridge_map bandwidth_ridge; + + LoadRoofLineCeilingsRidge(workload, roofline_handle, compute_ridge, bandwidth_ridge); + + LoadRoofLineCeilingsCompute(workload, roofline_handle, compute_ridge, bandwidth_ridge); + + LoadRoofLineCeilingsBandwidth(workload, roofline_handle, compute_ridge, bandwidth_ridge); + + LoadRoofLineNumKernels(workload, roofline_handle, compute_ridge, bandwidth_ridge); +} + +inline void +DataProvider::LoadRoofLineCeilingsRidge(WorkloadInfo& workload, + rocprofvis_handle_t* roofline_handle, + compute_ridge_map& compute_ridge, + bandwidth_ridge_map& bandwidth_ridge) +{ + double double_data = 0.0; + uint64_t uint64_data = 0; + uint64_t num_entries = 0; + rocprofvis_result_t result = rocprofvis_controller_get_uint64( + roofline_handle, kRPVControllerRooflineNumCeilingsRidge, 0, &num_entries); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + workload.roofline.max = { DBL_MIN, DBL_MIN }; + workload.roofline.min = { DBL_MAX, DBL_MAX }; + + for(uint64_t j = 0; j < num_entries; j++) + { + rocprofvis_controller_roofline_ceiling_compute_type_t compute_type; + rocprofvis_controller_roofline_ceiling_bandwidth_type_t bandwidth_type; + Point position; + result = rocprofvis_controller_get_uint64( + roofline_handle, kRPVControllerRooflineCeilingRidgeComputeTypeIndexed, j, + &uint64_data); ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - for(uint64_t j = 0; j < num_entries; j++) + compute_type = static_cast( + uint64_data); + result = rocprofvis_controller_get_uint64( + roofline_handle, kRPVControllerRooflineCeilingRidgeBandwidthTypeIndexed, j, + &uint64_data); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + bandwidth_type = + static_cast( + uint64_data); + result = rocprofvis_controller_get_double( + roofline_handle, kRPVControllerRooflineCeilingRidgeXIndexed, j, &double_data); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + position.x = double_data; + result = rocprofvis_controller_get_double( + roofline_handle, kRPVControllerRooflineCeilingRidgeYIndexed, j, &double_data); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + position.y = double_data; + compute_ridge[compute_type][bandwidth_type] = position; + bandwidth_ridge[bandwidth_type][compute_type] = std::move(position); + } +} + +inline void +DataProvider::LoadRoofLineCeilingsCompute(WorkloadInfo& workload, + rocprofvis_handle_t* roofline_handle, + compute_ridge_map& compute_ridge, + bandwidth_ridge_map& bandwidth_ridge) +{ + double double_data = 0.0; + uint64_t uint64_data = 0; + uint64_t num_entries = 0; + rocprofvis_result_t result = rocprofvis_controller_get_uint64( + roofline_handle, kRPVControllerRooflineNumCeilingsCompute, 0, &num_entries); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + for(uint64_t j = 0; j < num_entries; j++) + { + WorkloadInfo::Roofline::Ceiling ceiling; + result = rocprofvis_controller_get_uint64( + roofline_handle, kRPVControllerRooflineCeilingComputeTypeIndexed, j, + &uint64_data); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + ceiling.compute_type = + static_cast( + uint64_data); + ROCPROFVIS_ASSERT(compute_ridge.count(ceiling.compute_type) > 0); + for(const std::pair& ridge : compute_ridge.at(ceiling.compute_type)) { - KernelInfo::Roofline::Intensity intensity; - result = rocprofvis_controller_get_uint64( - roofline_handle, kRPVControllerRooflineKernelIntensityTypeIndexed, j, - &uint64_data); + ceiling.bandwidth_type = ridge.first; + ceiling.position.p1 = ridge.second; + result = rocprofvis_controller_get_double( + roofline_handle, kRPVControllerRooflineCeilingComputeXIndexed, j, + &double_data); ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - intensity.type = - static_cast( - uint64_data); - result = rocprofvis_controller_get_double( - roofline_handle, kRPVControllerRooflineKernelIntensityXIndexed, j, + ceiling.position.p2.x = double_data; + result = rocprofvis_controller_get_double( + roofline_handle, kRPVControllerRooflineCeilingComputeYIndexed, j, + &double_data); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + ceiling.position.p2.y = double_data; + result = rocprofvis_controller_get_double( + roofline_handle, kRPVControllerRooflineCeilingComputeThroughputIndexed, j, &double_data); ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - intensity.position.x = double_data; + ceiling.throughput = double_data; + workload.roofline.max.x = + std::max(workload.roofline.max.x, ceiling.position.p2.x); + workload.roofline.max.y = + std::max(workload.roofline.max.y, ceiling.position.p2.y); + workload.roofline + .ceiling_compute[ceiling.compute_type][ceiling.bandwidth_type] = ceiling; + } + } +} + +inline void +DataProvider::LoadRoofLineCeilingsBandwidth(WorkloadInfo& workload, + rocprofvis_handle_t* roofline_handle, + compute_ridge_map& compute_ridge, + bandwidth_ridge_map& bandwidth_ridge) +{ + double double_data = 0.0; + uint64_t uint64_data = 0; + uint64_t num_entries = 0; + rocprofvis_result_t result = rocprofvis_controller_get_uint64( + roofline_handle, kRPVControllerRooflineNumCeilingsBandwidth, 0, &num_entries); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + for(uint64_t j = 0; j < num_entries; j++) + { + WorkloadInfo::Roofline::Ceiling ceiling; + result = rocprofvis_controller_get_uint64( + roofline_handle, kRPVControllerRooflineCeilingBandwidthTypeIndexed, j, + &uint64_data); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + ceiling.bandwidth_type = + static_cast( + uint64_data); + ROCPROFVIS_ASSERT(bandwidth_ridge.count(ceiling.bandwidth_type) > 0); + for(const std::pair& ridge : bandwidth_ridge.at(ceiling.bandwidth_type)) + { + ceiling.compute_type = ridge.first; result = rocprofvis_controller_get_double( - roofline_handle, kRPVControllerRooflineKernelIntensityYIndexed, j, + roofline_handle, kRPVControllerRooflineCeilingBandwidthXIndexed, j, &double_data); ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - intensity.position.y = double_data; - uint32_t kernel_id; - result = rocprofvis_controller_get_uint64( - roofline_handle, kRPVControllerRooflineKernelIdIndexed, j, &uint64_data); + ceiling.position.p1.x = double_data; + result = rocprofvis_controller_get_double( + roofline_handle, kRPVControllerRooflineCeilingBandwidthYIndexed, j, + &double_data); ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); - kernel_id = static_cast(uint64_data); - ROCPROFVIS_ASSERT(workload.kernels.count(kernel_id)); - workload.roofline.max.y = - std::max(workload.roofline.max.y, intensity.position.y); + ceiling.position.p1.y = double_data; + ceiling.position.p2 = ridge.second; + result = rocprofvis_controller_get_double( + roofline_handle, kRPVControllerRooflineCeilingBandwidthThroughputIndexed, + j, &double_data); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + ceiling.throughput = double_data; + workload.roofline.min.x = + std::min(workload.roofline.min.x, ceiling.position.p1.x); workload.roofline.min.y = - std::min(workload.roofline.min.y, intensity.position.y); - workload.kernels[kernel_id].roofline.intensities[intensity.type] = - std::move(intensity); + std::min(workload.roofline.min.y, ceiling.position.p1.y); + workload.roofline + .ceiling_bandwidth[ceiling.bandwidth_type][ceiling.compute_type] = + ceiling; } - m_compute_model.AddWorkload(workload); } - m_state = ProviderState::kReady; +} - if(m_trace_data_ready_callback) +inline void +DataProvider::LoadRoofLineNumKernels(WorkloadInfo& workload, + rocprofvis_handle_t* roofline_handle, + compute_ridge_map& compute_ridge, + bandwidth_ridge_map& bandwidth_ridge) +{ + uint64_t num_entries = 0; + double double_data = 0.0; + uint64_t uint64_data = 0; + rocprofvis_result_t result = rocprofvis_controller_get_uint64( + roofline_handle, kRPVControllerRooflineNumKernels, 0, &num_entries); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + for(uint64_t j = 0; j < num_entries; j++) { - m_trace_data_ready_callback(m_model.GetTraceFilePath(), kRocProfVisResultSuccess); - } + KernelInfo::Roofline::Intensity intensity; + result = rocprofvis_controller_get_uint64( + roofline_handle, kRPVControllerRooflineKernelIntensityTypeIndexed, j, + &uint64_data); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + intensity.type = + static_cast( + uint64_data); + result = rocprofvis_controller_get_double( + roofline_handle, kRPVControllerRooflineKernelIntensityXIndexed, j, + &double_data); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + intensity.position.x = double_data; + result = rocprofvis_controller_get_double( + roofline_handle, kRPVControllerRooflineKernelIntensityYIndexed, j, + &double_data); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + intensity.position.y = double_data; + uint32_t kernel_id; + result = rocprofvis_controller_get_uint64( + roofline_handle, kRPVControllerRooflineKernelIdIndexed, j, &uint64_data); + ROCPROFVIS_ASSERT(result == kRocProfVisResultSuccess); + kernel_id = static_cast(uint64_data); + ROCPROFVIS_ASSERT(workload.kernels.count(kernel_id)); + workload.roofline.max.y = std::max(workload.roofline.max.y, intensity.position.y); + workload.roofline.min.y = std::min(workload.roofline.min.y, intensity.position.y); + workload.kernels[kernel_id].roofline.intensities[intensity.type] = + std::move(intensity); + } } void @@ -4927,6 +5336,62 @@ DataProvider::ProcessMetricPivotTable(RequestInfo& req) req.request_array = nullptr; } } + +void +DataProvider::ProcessPcSamplingRequest(RequestInfo& req) +{ + if(req.request_args) + { + rocprofvis_controller_arguments_free(req.request_args); + req.request_args = nullptr; + } + + std::shared_ptr params = + std::dynamic_pointer_cast(req.custom_params); + + if(!params) + return; + + const bool success = (req.response_code == kRocProfVisResultSuccess); + + if(success) + { + // The PcSampling handle (req.request_obj_handle) was written to by the async job. + // Now read the data out of it and populate the KernelInfo in the model. + rocprofvis_handle_t* pc_handle = req.request_obj_handle; + if(pc_handle) + { + uint32_t workload_id = params->m_workload_id; + uint32_t kernel_id = params->m_kernel_id; + + KernelInfo* kernel = m_compute_model.GetKernelInfoMutable(workload_id, kernel_id); + if(kernel) + { + kernel->pc_sampling_data = {}; + LoadPcSamplingCodeObjects(*kernel, pc_handle); + LoadPcSamplingJunctions(*kernel, pc_handle); + LoadPcSamplingStallRecords(*kernel, pc_handle); + LoadPcSamplingStallReasonCounts(*kernel, pc_handle); + LoadPcSamplingSourceFiles(*kernel, pc_handle); + } + } + } + else + { + spdlog::debug("PC sampling request failed with code {}", req.response_code); + } + + if(m_pc_sampling_fetch_callback) + { + m_pc_sampling_fetch_callback(m_model.GetTraceFilePath(), + params->m_kernel_id, + params->m_source_file_id, + success); + } + + req.request_obj_handle = nullptr; +} + #endif } // namespace View diff --git a/src/view/src/rocprofvis_data_provider.h b/src/view/src/rocprofvis_data_provider.h index adb790c79..46e29ee5b 100644 --- a/src/view/src/rocprofvis_data_provider.h +++ b/src/view/src/rocprofvis_data_provider.h @@ -355,21 +355,87 @@ class DataProvider #ifdef COMPUTE_UI_SUPPORT public: ComputeDataModel& ComputeModel(); - + bool FetchMetrics(const MetricsRequestParams& metrics_params); bool FetchMetricPivotTable(const ComputeTableRequestParams& params); + bool FetchPcSampling(const PcSamplingRequestParams& params); void SetFetchMetricsCallback( const std::function& callback); + void SetFetchPcSamplingCallback( + const std::function& callback); private: void ProcessLoadComputeTrace(RequestInfo& req); + inline void LoadWorkload(uint64_t workload_index); + inline void LoadSystemInfo(WorkloadInfo& workload, + rocprofvis_handle_t* workload_handle); + inline void LoadProfilingConfig(WorkloadInfo& workload, + rocprofvis_handle_t* workload_handle); + inline void LoadMetricList(WorkloadInfo& workload, + rocprofvis_handle_t* workload_handle); + inline void LoadValueNames(WorkloadInfo& workload, + rocprofvis_handle_t* workload_handle); + inline void LoadKernels(WorkloadInfo& workload, + rocprofvis_handle_t* workload_handle); + inline void LoadPcSamplingData(KernelInfo& kernel, + rocprofvis_handle_t* kernel_handle); + inline void LoadPcSamplingCodeObjects(KernelInfo& kernel, + rocprofvis_handle_t* pc_handle); + inline void LoadPcSamplingSourceFiles(KernelInfo& kernel, + rocprofvis_handle_t* pc_handle); + inline void LoadPcSamplingIsaLine(IsaLine& isa_line, + rocprofvis_handle_t* pc_handle, + uint64_t index); + inline void LoadPcSamplingSourceLine(SourceLine& source_line, + rocprofvis_handle_t* pc_handle, + uint64_t index); + inline void LoadPcSamplingJunctions(KernelInfo& kernel, + rocprofvis_handle_t* pc_handle); + inline void LoadPcSamplingStallRecords(KernelInfo& kernel, + rocprofvis_handle_t* pc_handle); + inline void LoadPcSamplingStallReasonCounts(KernelInfo& kernel, + rocprofvis_handle_t* pc_handle); + inline void LoadRoofLine(WorkloadInfo& workload, rocprofvis_handle_t* workload_handle); + + using compute_ridge_map = std::unordered_map< + rocprofvis_controller_roofline_ceiling_compute_type_t, + std::unordered_map>; + + using bandwidth_ridge_map = std::unordered_map< + rocprofvis_controller_roofline_ceiling_bandwidth_type_t, + std::unordered_map>; + + + inline void LoadRoofLineCeilingsRidge(WorkloadInfo& workload, + rocprofvis_handle_t* roofline_handle, + compute_ridge_map& compute_ridge, + bandwidth_ridge_map& bandwidth_ridge); + + inline void LoadRoofLineCeilingsCompute(WorkloadInfo& workload, + rocprofvis_handle_t* roofline_handle, + compute_ridge_map& compute_ridge, + bandwidth_ridge_map& bandwidth_ridge); + + inline void LoadRoofLineCeilingsBandwidth(WorkloadInfo& workload, + rocprofvis_handle_t* roofline_handle, + compute_ridge_map& compute_ridge, + bandwidth_ridge_map& bandwidth_ridge); + + inline void LoadRoofLineNumKernels(WorkloadInfo& workload, + rocprofvis_handle_t* roofline_handle, + compute_ridge_map& compute_ridge, + bandwidth_ridge_map& bandwidth_ridge); + void ProcessMetricsRequest(RequestInfo& req); void ProcessMetricPivotTable(RequestInfo& req); + void ProcessPcSamplingRequest(RequestInfo& req); ComputeDataModel m_compute_model; std::function m_metrics_fetch_callback; + std::function m_pc_sampling_fetch_callback; #endif }; diff --git a/src/view/src/rocprofvis_font_manager.cpp b/src/view/src/rocprofvis_font_manager.cpp index 874c1e965..7b69b5c11 100644 --- a/src/view/src/rocprofvis_font_manager.cpp +++ b/src/view/src/rocprofvis_font_manager.cpp @@ -139,6 +139,54 @@ FontManager::Init() m_text_font = io.Fonts->AddFontDefault(&fallback_config); } +#ifdef _WIN32 + const char* code_font_paths[] = { + "C:\\Windows\\Fonts\\CascadiaCode.ttf", + "C:\\Windows\\Fonts\\CascadiaMono.ttf", + "C:\\Windows\\Fonts\\consola.ttf", + "C:\\Windows\\Fonts\\cour.ttf" + }; +#elif __APPLE__ + const char* code_font_paths[] = { + "/System/Library/Fonts/SFMono-Regular.otf", + "/Library/Fonts/Menlo.ttc", + "/System/Library/Fonts/Menlo.ttc", + "/Library/Fonts/Courier New.ttf" + }; +#else + const char* code_font_paths[] = { + "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", + "/usr/share/fonts/dejavu/DejaVuSansMono.ttf", + "/usr/share/fonts/dejavu-sans-mono-fonts/DejaVuSansMono.ttf", + "/usr/share/fonts/truetype/liberation/LiberationMono-Regular.ttf", + "/usr/share/fonts/liberation-mono/LiberationMono-Regular.ttf", + "/usr/share/fonts/truetype/noto/NotoSansMono-Regular.ttf", + "/usr/share/fonts/google-noto/NotoSansMono-Regular.ttf", + "/usr/share/fonts/truetype/freefont/FreeMono.ttf" + }; +#endif + + const char* code_font_path = nullptr; + for(const char* path : code_font_paths) + { + if(std::filesystem::exists(path)) + { + code_font_path = path; + break; + } + } + + if(code_font_path) + { + m_code_font = io.Fonts->AddFontFromFileTTF(code_font_path, 0.0f); + } + else + { + ImFontConfig mono_fallback_config; + mono_fallback_config.SizePixels = BASE_FONT_SIZE; + m_code_font = io.Fonts->AddFontDefault(&mono_fallback_config); + } + ImFontConfig icon_config; icon_config.FontDataOwnedByAtlas = false; m_icon_font = io.Fonts->AddFontFromMemoryCompressedTTF( @@ -171,6 +219,8 @@ FontManager::GetFont(FontType font_type) return m_text_font; case FontType::kIcon: return m_icon_font; + case FontType::kCode: + return m_code_font; default: return m_text_font; } diff --git a/src/view/src/rocprofvis_font_manager.h b/src/view/src/rocprofvis_font_manager.h index 9e30b93ee..7869a056e 100644 --- a/src/view/src/rocprofvis_font_manager.h +++ b/src/view/src/rocprofvis_font_manager.h @@ -16,6 +16,7 @@ enum class FontType { kMainText, kIcon, + kCode, // Used to get the size of the enum, insert new fonts before this line __kLastFont, kDefault = kMainText @@ -58,6 +59,7 @@ class FontManager ImFont* m_text_font = nullptr; ImFont* m_icon_font = nullptr; + ImFont* m_code_font = nullptr; std::array m_sizes{}; std::vector m_available_sizes; }; diff --git a/src/view/src/rocprofvis_requests.h b/src/view/src/rocprofvis_requests.h index 792877f02..137f5ad16 100644 --- a/src/view/src/rocprofvis_requests.h +++ b/src/view/src/rocprofvis_requests.h @@ -45,6 +45,7 @@ enum class RequestType kFetchComputeTrace, kFetchMetrics, kFetchMetricPivotTable, + kFetchPcSampling, #endif }; @@ -266,6 +267,23 @@ class MetricsRequestParams : public RequestParamsBase {} }; +class PcSamplingRequestParams : public RequestParamsBase +{ +public: + uint32_t m_workload_id; + uint32_t m_kernel_id; + uint32_t m_source_file_id; + + PcSamplingRequestParams(const PcSamplingRequestParams&) = default; + PcSamplingRequestParams& operator=(const PcSamplingRequestParams&) = default; + + PcSamplingRequestParams(uint32_t workload_id, uint32_t kernel_id, uint32_t source_file_id) + : m_workload_id(workload_id) + , m_kernel_id(kernel_id) + , m_source_file_id(source_file_id) + {} +}; + class ComputeTableRequestParams : public RequestParamsBase { public: diff --git a/src/view/src/widgets/rocprofvis_split_containers.cpp b/src/view/src/widgets/rocprofvis_split_containers.cpp index 2d506a083..2a64eff15 100644 --- a/src/view/src/widgets/rocprofvis_split_containers.cpp +++ b/src/view/src/widgets/rocprofvis_split_containers.cpp @@ -192,7 +192,7 @@ void SplitContainerBase::SetMinSecondSize(float size) { m_second_min_size = size; -}; +} //------------------------------------------------------------------ HSplitContainer::HSplitContainer(LayoutItem::Ptr left, LayoutItem::Ptr right) @@ -252,18 +252,18 @@ HSplitContainer::GetFirstChildSize(float available_width) float left_col_width = 0.0f; if (m_first && m_first->m_visible) { - left_col_width = available_width * m_split_ratio; - float max_left_col_width = (m_second && m_second->m_visible) - ? (available_width - m_second_min_size) - : available_width; - if(m_first_min_size >= max_left_col_width) + if(!m_second || !m_second->m_visible) { - left_col_width = m_first_min_size; + left_col_width = available_width; } else { - left_col_width = std::clamp(left_col_width, m_first_min_size, - max_left_col_width); + left_col_width = available_width * m_split_ratio; + const float max_left_col_width = available_width - m_second_min_size; + if(m_first_min_size >= max_left_col_width) + left_col_width = m_first_min_size; + else + left_col_width = std::clamp(left_col_width, m_first_min_size, max_left_col_width); } } return ImVec2(left_col_width, 0); diff --git a/src/view/src/widgets/rocprofvis_split_containers.h b/src/view/src/widgets/rocprofvis_split_containers.h index ad8c94e80..db9200c32 100644 --- a/src/view/src/widgets/rocprofvis_split_containers.h +++ b/src/view/src/widgets/rocprofvis_split_containers.h @@ -45,6 +45,8 @@ class SplitContainerBase : public RocWidget virtual void Render() override; void SetSplit(float ratio) { m_split_ratio = ratio; }; + void ShowSplitter(bool show) { m_always_show_splitter = show; }; + float GetMinSize(); protected: @@ -78,6 +80,8 @@ class SplitContainerBase : public RocWidget std::string m_handle_name; float m_optimal_size = 0.0f; + + bool m_always_show_splitter = false; }; class HSplitContainer : public SplitContainerBase