diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a6f8bec..86098ed4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -135,6 +135,8 @@ list(APPEND VIEW_FILES src/view/src/compute/rocprofvis_compute_workload_view.cpp src/view/src/widgets/rocprofvis_compute_widget.cpp src/view/src/widgets/rocprofvis_query_builder.cpp + src/view/src/compute/rocprofvis_compute_kernel_metric_table.cpp + src/view/src/compute/rocprofvis_compute_tester.cpp ) endif(COMPUTE_UI_SUPPORT) diff --git a/src/controller/src/compute/rocprofvis_controller_trace_compute.cpp b/src/controller/src/compute/rocprofvis_controller_trace_compute.cpp index 8c9bebc8..fa3cc7b9 100644 --- a/src/controller/src/compute/rocprofvis_controller_trace_compute.cpp +++ b/src/controller/src/compute/rocprofvis_controller_trace_compute.cpp @@ -278,14 +278,16 @@ rocprofvis_result_t ComputeTrace::AsyncFetch(Arguments& args, Future& future, Me result = args.GetUInt64(kRPVControllerMetricArgsNumKernels, 0, &num_entries); if(result == kRocProfVisResultSuccess) { + auto query_args = std::make_shared(); + auto query_out = std::make_shared(); + uint64_t uint64_data = 0; - m_query_arguments.clear(); for(uint64_t i = 0; i < num_entries; i++) { result = args.GetUInt64(kRPVControllerMetricArgsKernelIdIndexed, i, &uint64_data); if(result == kRocProfVisResultSuccess) { - m_query_arguments.emplace_back(kRPVComputeParamKernelId, std::to_string(uint64_data)); + query_args->emplace_back(kRPVComputeParamKernelId, std::to_string(uint64_data)); } else { @@ -313,7 +315,7 @@ rocprofvis_result_t ComputeTrace::AsyncFetch(Arguments& args, Future& future, Me metric_id.SetEntryID((uint32_t)uint64_data); } } - m_query_arguments.emplace_back(kRPVComputeParamMetricId, metric_id.ToString()); + query_args->emplace_back(kRPVComputeParamMetricId, metric_id.ToString()); result = kRocProfVisResultSuccess; } else @@ -325,9 +327,9 @@ rocprofvis_result_t ComputeTrace::AsyncFetch(Arguments& args, Future& future, Me } if(result == kRocProfVisResultSuccess) { - future.Set(JobSystem::Get().IssueJob([this, &output](Future* future) -> rocprofvis_result_t { + future.Set(JobSystem::Get().IssueJob([this, &output, query_args, query_out](Future* future) -> rocprofvis_result_t { rocprofvis_result_t result = kRocProfVisResultUnknownError; - m_query_output = { + *query_out = { { { kRPVComputeColumnMetricId, std::nullopt }, { kRPVComputeColumnMetricName, std::nullopt }, @@ -338,7 +340,7 @@ rocprofvis_result_t ComputeTrace::AsyncFetch(Arguments& args, Future& future, Me {} }; rocprofvis_dm_database_t db = rocprofvis_dm_get_property_as_handle(m_dm_handle, kRPVDMDatabaseHandle, 0); - rocprofvis_dm_result_t dm_result = ExecuteQuery(db, m_dm_handle, nullptr, future, kRPVComputeFetchMetricValues, m_query_arguments, m_query_output, [this, &output](const QueryDataStore& data_store){ + rocprofvis_dm_result_t dm_result = ExecuteQuery(db, m_dm_handle, nullptr, future, kRPVComputeFetchMetricValues, *query_args, *query_out, [this, &output](const QueryDataStore& data_store){ uint64_t valid_results = 0; rocprofvis_property_t property; rocprofvis_controller_primitive_type_t type; diff --git a/src/controller/src/rocprofvis_controller.cpp b/src/controller/src/rocprofvis_controller.cpp index 3a769041..01f47ab0 100644 --- a/src/controller/src/rocprofvis_controller.cpp +++ b/src/controller/src/rocprofvis_controller.cpp @@ -361,10 +361,14 @@ rocprofvis_result_t rocprofvis_controller_table_fetch_async( rocprofvis_controller_array_t* output) { rocprofvis_result_t error = kRocProfVisResultInvalidArgument; - RocProfVis::Controller::SystemTraceRef system_trace(controller); -#ifdef COMPUTE_UI_SUPPORT - RocProfVis::Controller::ComputeTraceRef compute_trace(controller); -#endif + + // Determine actual controller type first to avoid ambiguous reference validation + rocprofvis_controller_object_type_t controller_type; + if(rocprofvis_controller_get_object_type(controller, &controller_type) != kRocProfVisResultSuccess) + { + return error; + } + RocProfVis::Controller::TableRef table_ref(table); RocProfVis::Controller::ArgumentsRef args_ref(args); RocProfVis::Controller::FutureRef future(result); @@ -372,14 +376,22 @@ rocprofvis_result_t rocprofvis_controller_table_fetch_async( if (table_ref.IsValid() && args_ref.IsValid() && future.IsValid() && array.IsValid()) { - if (system_trace.IsValid()) + if (controller_type == kRPVControllerObjectTypeControllerSystem) { - error = system_trace->AsyncFetch(*table_ref, *args_ref, *future, *array); + RocProfVis::Controller::SystemTraceRef system_trace(controller); + if(system_trace.IsValid()) + { + error = system_trace->AsyncFetch(*table_ref, *args_ref, *future, *array); + } } #ifdef COMPUTE_UI_SUPPORT - else if (compute_trace.IsValid()) + else if (controller_type == kRPVControllerObjectTypeControllerCompute) { - error = compute_trace->AsyncFetch(*table_ref, *args_ref, *future, *array); + RocProfVis::Controller::ComputeTraceRef compute_trace(controller); + if(compute_trace.IsValid()) + { + error = compute_trace->AsyncFetch(*table_ref, *args_ref, *future, *array); + } } #endif } diff --git a/src/model/src/database/rocprofvis_db_compute.cpp b/src/model/src/database/rocprofvis_db_compute.cpp index 174afa72..68df85ac 100644 --- a/src/model/src/database/rocprofvis_db_compute.cpp +++ b/src/model/src/database/rocprofvis_db_compute.cpp @@ -295,6 +295,9 @@ namespace DataModel { std::string metric_id = selector_str.substr(0, colon_pos); std::string value_name = selector_str.substr(colon_pos + 1); + // Convert value_name to lowercase to match SQL LOWER(value_name) comparison + std::transform(value_name.begin(), value_name.end(), value_name.begin(), + [](unsigned char c) { return std::tolower(c); }); metric_selectors.push_back({ metric_id, value_name }); } } diff --git a/src/view/src/compute/rocprofvis_compute_kernel_details.cpp b/src/view/src/compute/rocprofvis_compute_kernel_details.cpp index c130f61a..78ca4c31 100644 --- a/src/view/src/compute/rocprofvis_compute_kernel_details.cpp +++ b/src/view/src/compute/rocprofvis_compute_kernel_details.cpp @@ -6,6 +6,7 @@ #include "rocprofvis_compute_selection.h" #include "rocprofvis_data_provider.h" #include "rocprofvis_event_manager.h" +#include "rocprofvis_compute_kernel_metric_table.h" #include "imgui.h" @@ -20,13 +21,50 @@ ComputeKernelDetailsView::ComputeKernelDetailsView( , m_data_provider(data_provider) , m_memory_chart(data_provider, compute_selection) , m_roofline(nullptr) +, m_kernel_metric_table(nullptr) , m_compute_selection(compute_selection) +, m_client_id(IdGenerator::GetInstance().GenerateId()) , m_sol_table(data_provider, compute_selection, METRIC_CAT_SOL, METRIC_TABLE_SOL) +, m_workload_selection_changed_token(EventManager::InvalidSubscriptionToken) +, m_kernel_selection_changed_token(EventManager::InvalidSubscriptionToken) +, m_new_table_data_token(EventManager::InvalidSubscriptionToken) +, m_metrics_fetched_token(EventManager::InvalidSubscriptionToken) +{ + SubscribeToEvents(); + + m_roofline = std::make_unique(data_provider); + m_kernel_metric_table = std::make_unique(data_provider, compute_selection); + + m_widget_name = GenUniqueName("ComputeKernelDetailsView"); +} + +ComputeKernelDetailsView::~ComputeKernelDetailsView() +{ + EventManager::GetInstance()->Unsubscribe( + static_cast(RocEvents::kComputeWorkloadSelectionChanged), + m_workload_selection_changed_token); + EventManager::GetInstance()->Unsubscribe( + static_cast(RocEvents::kComputeKernelSelectionChanged), + m_kernel_selection_changed_token); + EventManager::GetInstance()->Unsubscribe( + static_cast(RocEvents::kComputeMetricsFetched), m_metrics_fetched_token); + EventManager::GetInstance()->Unsubscribe( + static_cast(RocEvents::kNewTableData), m_new_table_data_token); +} + +void ComputeKernelDetailsView::SubscribeToEvents() { auto workload_changed_handler = [this](std::shared_ptr e) { auto evt = std::dynamic_pointer_cast(e); if(evt && evt->GetSourceId() == m_data_provider.GetTraceFilePath()) { + // Fetch pivot table data + if(m_kernel_metric_table) + { + //clear existing model table data + m_data_provider.ComputeModel().GetKernelSelectionTable().Clear(); + m_kernel_metric_table->FetchData(evt->GetId()); + } m_sol_table.Clear(); } }; @@ -67,26 +105,33 @@ ComputeKernelDetailsView::ComputeKernelDetailsView( } } }; - m_metrics_fetched_token = EventManager::GetInstance()->Subscribe( static_cast(RocEvents::kComputeMetricsFetched), metrics_fetched_handler); - m_roofline = std::make_unique(data_provider); + // subscribe to fetch table data event + auto new_table_data_handler = [this](std::shared_ptr e) { + if(auto table_data_event = std::dynamic_pointer_cast(e) ) + { + if(m_data_provider.GetTraceFilePath() != table_data_event->GetSourceId()) + { + return; + } - m_widget_name = GenUniqueName("ComputeKernelDetailsView"); -} + if(table_data_event->GetResponseCode() != kRocProfVisResultSuccess) + { + return; + } -ComputeKernelDetailsView::~ComputeKernelDetailsView() -{ - EventManager::GetInstance()->Unsubscribe( - static_cast(RocEvents::kComputeWorkloadSelectionChanged), - m_workload_selection_changed_token); - EventManager::GetInstance()->Unsubscribe( - static_cast(RocEvents::kComputeKernelSelectionChanged), - m_kernel_selection_changed_token); - EventManager::GetInstance()->Unsubscribe( - static_cast(RocEvents::kComputeMetricsFetched), m_metrics_fetched_token); -} + if(table_data_event->GetRequestID() == DataProvider::METRIC_PIVOT_TABLE_REQUEST_ID) + { + m_kernel_metric_table->HandleNewData(); + } + } + }; + + m_new_table_data_token = EventManager::GetInstance()->Subscribe( + static_cast(RocEvents::kNewTableData), new_table_data_handler); +} void ComputeKernelDetailsView::Update() @@ -95,13 +140,24 @@ ComputeKernelDetailsView::Update() { m_roofline->Update(); } + if(m_kernel_metric_table) + { + m_kernel_metric_table->Update(); + } } void ComputeKernelDetailsView::Render() { ImGui::BeginChild("kernel_details"); + + if(m_kernel_metric_table) + { + m_kernel_metric_table->Render(); + } + ImGui::Text("Memory Chart"); + m_memory_chart.Render(); m_sol_table.Render(); if(m_roofline) diff --git a/src/view/src/compute/rocprofvis_compute_kernel_details.h b/src/view/src/compute/rocprofvis_compute_kernel_details.h index 732ceffe..adea59cb 100644 --- a/src/view/src/compute/rocprofvis_compute_kernel_details.h +++ b/src/view/src/compute/rocprofvis_compute_kernel_details.h @@ -15,6 +15,7 @@ namespace View class DataProvider; class ComputeSelection; class Roofline; +class KernelMetricTable; class ComputeKernelDetailsView : public RocWidget { @@ -27,16 +28,23 @@ class ComputeKernelDetailsView : public RocWidget void Update() override; private: + + void SubscribeToEvents(); + DataProvider& m_data_provider; ComputeMemoryChartView m_memory_chart; std::shared_ptr m_compute_selection; std::unique_ptr m_roofline; + std::unique_ptr m_kernel_metric_table; + + uint64_t m_client_id; MetricTableWidget m_sol_table; EventManager::SubscriptionToken m_workload_selection_changed_token; EventManager::SubscriptionToken m_kernel_selection_changed_token; EventManager::SubscriptionToken m_metrics_fetched_token; + EventManager::SubscriptionToken m_new_table_data_token; }; } // namespace View diff --git a/src/view/src/compute/rocprofvis_compute_kernel_metric_table.cpp b/src/view/src/compute/rocprofvis_compute_kernel_metric_table.cpp new file mode 100644 index 00000000..03b50fbb --- /dev/null +++ b/src/view/src/compute/rocprofvis_compute_kernel_metric_table.cpp @@ -0,0 +1,441 @@ +// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. +// SPDX-License-Identifier: MIT + +#include "rocprofvis_compute_kernel_metric_table.h" +#include "rocprofvis_compute_selection.h" +#include "rocprofvis_core_assert.h" +#include "rocprofvis_data_provider.h" +#include "rocprofvis_settings_manager.h" +#include "widgets/rocprofvis_gui_helpers.h" + +#include "imgui.h" +#include "spdlog/spdlog.h" + +namespace RocProfVis +{ +namespace View +{ + +// ID, Name, duration, invocation columns that are always present in the table +constexpr int PERMANENT_COLUMN_COUNT = 4; + +KernelMetricTable::KernelMetricTable(DataProvider& data_provider, + std::shared_ptr compute_selection) +: RocWidget() +, m_data_provider(data_provider) +, m_fetch_requested(false) +, m_workload_id(ComputeSelection::INVALID_SELECTION_ID) +, m_sort_column_index(-1) +, m_sort_order(kRPVControllerSortOrderDescending) +, m_selected_row(-1) +, m_compute_selection(compute_selection) +, m_selected_kernel_id_local(ComputeSelection::INVALID_SELECTION_ID) +{} + +void +KernelMetricTable::ClearData() +{ + m_metrics_params.clear(); + m_metrics_column_names.clear(); +} + +void +KernelMetricTable::FetchData(uint32_t workload_id) +{ + m_workload_id = workload_id; + if(m_workload_id == ComputeSelection::INVALID_SELECTION_ID) + { + spdlog::warn("Invalid workload ID, cannot fetch kernel metric data"); + return; + } + + m_query_builder.SetWorkload(m_data_provider.ComputeModel().GetWorkload(workload_id)); + m_fetch_requested = true; +} + +void +KernelMetricTable::HandleNewData() +{ + // update column names based on current metric params + ComputeKernelSelectionTable& table = + m_data_provider.ComputeModel().GetKernelSelectionTable(); + std::shared_ptr request_params = + table.GetTableInfo().table_params; + + m_metrics_column_names.clear(); + + ROCPROFVIS_ASSERT(m_metrics_params.size() == m_metrics_info.size()); + size_t metric_count = request_params->m_metric_selectors.size(); + for(size_t i = 0; i < metric_count; i++) + { + m_metrics_column_names.push_back(m_metrics_info[i].entry.name + " (" + + m_metrics_info[i].value_name + ")"); + } +} + +void +KernelMetricTable::Update() +{ + bool request_pending = + m_data_provider.IsRequestPending(DataProvider::METRIC_PIVOT_TABLE_REQUEST_ID); + + if(!request_pending && m_fetch_requested) + { + ComputeTableRequestParams params(m_workload_id, m_metrics_params); + + params.m_sort_column_index = m_sort_column_index; + params.m_sort_order = + static_cast(m_sort_order); + + spdlog::debug("Requesting sorted kernel selection table: column {}, order {}", + m_sort_column_index, + m_sort_order == kRPVControllerSortOrderAscending ? "ASC" : "DESC"); + m_data_provider.FetchMetricPivotTable(params); + + m_fetch_requested = false; + } + + // check if kernel selection has changed and update selection if needed + uint32_t selected_kernel_id = m_compute_selection->GetSelectedKernel(); + + if(m_selected_kernel_id_local != selected_kernel_id) + { + m_selected_kernel_id_local = selected_kernel_id; + if(m_selected_kernel_id_local == ComputeSelection::INVALID_SELECTION_ID) + { + m_selected_row = -1; + } + else + { + // Find the row with the selected kernel ID and update selection + ComputeKernelSelectionTable& table = + m_data_provider.ComputeModel().GetKernelSelectionTable(); + const std::vector>& data = table.GetTableData(); + for(size_t row = 0; row < data.size(); row++) + { + // TODO: add "Important Column" for indentifying id column instead of + // assuming index 0 + if(!data[row].empty() && + data[row][0] == std::to_string(selected_kernel_id)) + { + m_selected_row = static_cast(row); + break; + } + } + } + } +} + +void +KernelMetricTable::Render() +{ + int remove_index = -1; + + SettingsManager& settings = SettingsManager::GetInstance(); + float item_spacing = settings.GetDefaultStyle().ItemSpacing.x; + + ImGui::AlignTextToFramePadding(); + ImGui::TextUnformatted("Kernel Selection Table"); + + // if(m_workload_id == ComputeSelection::INVALID_SELECTION_ID) + // { + // ImGui::Separator(); + // ImGui::TextUnformatted("No workload selected"); + // return; + // } + m_query_builder.SetWorkload( + m_data_provider.ComputeModel().GetWorkload(m_workload_id)); + + ImGui::SameLine(0.0f, item_spacing); + + ImGui::BeginDisabled(m_workload_id == ComputeSelection::INVALID_SELECTION_ID); + if(ImGui::Button("Add Metric")) + { + m_query_builder.Show([this](const std::string& query) { + m_metrics_params.push_back(query); + const AvailableMetrics::Entry* entry = + m_query_builder.GetSelectedMetricInfo(); + m_metrics_info.push_back({ entry ? *entry : AvailableMetrics::Entry(), + m_query_builder.GetValueName() }); + m_fetch_requested = true; + }); + } + ImGui::EndDisabled(); + + ImGui::Separator(); + + ComputeKernelSelectionTable& table = + m_data_provider.ComputeModel().GetKernelSelectionTable(); + const std::vector& header = table.GetTableHeader(); + const std::vector>& data = table.GetTableData(); + + bool request_pending = + m_data_provider.IsRequestPending(DataProvider::METRIC_PIVOT_TABLE_REQUEST_ID); + + float line_height = ImGui::GetTextLineHeightWithSpacing(); + ImGuiStyle& style = ImGui::GetStyle(); + float row_padding_v = style.CellPadding.y * 2.0f; + line_height += row_padding_v; + + // Set a fixed height for the table container + if(ImGui::BeginChild("kernel_metric_table_cont", ImVec2(0, 10.0f * line_height), + ImGuiChildFlags_None, ImGuiWindowFlags_NoMove)) + { + if(!header.empty() && !data.empty() && m_workload_id != ComputeSelection::INVALID_SELECTION_ID) + { + ImGuiTableFlags table_flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | + ImGuiTableFlags_Borders | + ImGuiTableFlags_SizingStretchSame; + if(!request_pending) + { + table_flags = table_flags | ImGuiTableFlags_Sortable; + } + + int column_count = static_cast(header.size()); + ImVec2 outer_size = ImVec2(0.0f, ImGui::GetContentRegionAvail().y); + + if(ImGui::BeginTable("kernel_selection_table", column_count, table_flags, + outer_size)) + { + ImGui::TableSetupScrollFreeze(0, 1); // Freeze header row + for(int col = 0; col < column_count; col++) + { + if(col < PERMANENT_COLUMN_COUNT) + { + ImGuiTableColumnFlags col_flags = ImGuiTableColumnFlags_None; + if(!header[col].empty() && header[col][0] == '_') + { + col_flags = ImGuiTableColumnFlags_DefaultHide | + ImGuiTableColumnFlags_Disabled; + } + ImGui::TableSetupColumn(header[col].c_str(), col_flags); + } + else + { + int index = col - PERMANENT_COLUMN_COUNT; + // Since render reads directly from the data model, the + // m_metrics_column_names may not be synced for a few frames + if(index < static_cast(m_metrics_column_names.size())) + { + ImGui::TableSetupColumn( + m_metrics_column_names[index].c_str()); + } + else + { + ImGui::TableSetupColumn( + ("Metric " + std::to_string(index + 1)).c_str()); + } + } + } + + // Custom header row with hover detection and X button + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); + for(int col = 0; col < column_count; col++) + { + ImGui::TableSetColumnIndex(col); + + // Skip X for non-removable columns (like ID, Name) + if(col < PERMANENT_COLUMN_COUNT) + { + ImGui::TableHeader(ImGui::TableGetColumnName(col)); + continue; + } + + // Sortable header with X button + const char* name = ImGui::TableGetColumnName(col); + ImGui::TableHeader(name); + ImVec2 text_size = ImGui::CalcTextSize(name); + ImGui::SameLine(text_size.x, item_spacing); + + ImGui::PushID(col); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f)); + if(XButton(nullptr, "Remove Metric", &settings)) + { + remove_index = col - PERMANENT_COLUMN_COUNT; + } + ImGui::PopStyleVar(); + ImGui::PopID(); + } + + if(data.empty()) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextDisabled("None"); + } + + // Get sort specs + ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs(); + if(sort_specs && sort_specs->SpecsDirty) + { + int sort_column_index = -1; + rocprofvis_controller_sort_order_t sort_order = + kRPVControllerSortOrderDescending; + sort_column_index = sort_specs->Specs->ColumnIndex; + sort_order = + (sort_specs->Specs->SortDirection == ImGuiSortDirection_Ascending) + ? kRPVControllerSortOrderAscending + : kRPVControllerSortOrderDescending; + + sort_specs->SpecsDirty = false; + + if(m_sort_column_index != sort_column_index || + m_sort_order != sort_order) + { + m_sort_column_index = sort_column_index; + m_sort_order = sort_order; + m_fetch_requested = true; + } + } + + if(request_pending) + { + ImGui::BeginDisabled(); + } + + ImGuiListClipper clipper; + clipper.Begin(static_cast(data.size())); + while(clipper.Step()) + { + for(int row = clipper.DisplayStart; row < clipper.DisplayEnd; row++) + { + ImGui::TableNextRow(); + + bool is_selected = (m_selected_row == row); + bool selectable_placed = false; + + for(int col = 0; col < data[row].size(); col++) + { + const std::string& cell = data[row][col]; + ImGui::TableNextColumn(); + + // Check if this is the first visible column + ImGuiTableColumnFlags flags = ImGui::TableGetColumnFlags(col); + bool is_visible = (flags & ImGuiTableColumnFlags_IsVisible) != 0; + bool is_enabled = (flags & ImGuiTableColumnFlags_IsEnabled) != 0; + + if(!selectable_placed && is_visible && is_enabled) + { + if(ImGui::Selectable(cell.c_str(), is_selected, + ImGuiSelectableFlags_SpanAllColumns)) + { + if(is_selected) + { + m_selected_row = -1; // Deselect if already selected + m_compute_selection->SelectKernel( + ComputeSelection::INVALID_SELECTION_ID); + } + else + { + m_selected_row = row; + m_selected_kernel_id_local = + data[row][0].empty() + ? ComputeSelection::INVALID_SELECTION_ID + : std::stoul(data[row][0]); + + m_compute_selection->SelectKernel( + m_selected_kernel_id_local); + } + } + selectable_placed = true; + } + else + { + if(cell.empty()) + { + ImGui::TextDisabled("N/A"); + } + else + { + ImGui::TextUnformatted(cell.c_str()); + } + } + } + } + } + + if(request_pending) + { + ImGui::EndDisabled(); + } + + ImGui::EndTable(); + } + } + else + { + if(m_workload_id == ComputeSelection::INVALID_SELECTION_ID) + { + ImGui::TextDisabled("No workload selected"); + } + else + { + if(request_pending) + { + ImGui::TextDisabled("Loading data..."); + } + else + { + ImGui::TextDisabled("No data to display"); + } + } + } + + if(request_pending) + { + RenderLoadingIndicator(); + } + } + ImGui::EndChild(); + + if(remove_index >= 0 && remove_index < static_cast(m_metrics_params.size())) + { + ROCPROFVIS_ASSERT(m_metrics_params.size() == m_metrics_info.size()); + + m_metrics_params.erase(m_metrics_params.begin() + remove_index); + m_metrics_info.erase(m_metrics_info.begin() + remove_index); + + m_fetch_requested = true; + spdlog::debug("Removed metric column at index {}", remove_index); + } + + m_query_builder.Render(); +} + +void +KernelMetricTable::RenderLoadingIndicator() const +{ + ImGui::SetCursorPos(ImVec2(0, 0)); + // set transparent background for the overlay window + ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0, 0, 0, 0)); + ImGui::BeginChild("kernel_metric_table_loading", ImGui::GetWindowSize(), + ImGuiChildFlags_None); + + float dot_radius = 5.0f; + int num_dots = 3; + float dot_spacing = 5.0f; + float anim_speed = 5.0f; + + ImVec2 dot_size = MeasureLoadingIndicatorDots(dot_radius, num_dots, dot_spacing); + + ImVec2 window_pos = ImGui::GetWindowPos(); + ImVec2 view_rect = ImGui::GetWindowSize(); + ImVec2 pos = ImGui::GetCursorPos(); + ImVec2 center_pos = ImVec2(window_pos.x + (view_rect.x - dot_size.x) * 0.5f, + window_pos.y + (view_rect.y - dot_size.y) * 0.5f); + + ImGui::SetCursorScreenPos(center_pos); + + RenderLoadingIndicatorDots(dot_radius, num_dots, dot_spacing, + SettingsManager::GetInstance().GetColor(Colors::kTextMain), + anim_speed); + + // Reset cursor position after rendering spinner + ImGui::SetCursorPos(pos); + + ImGui::EndChild(); + ImGui::PopStyleColor(); +} + +} // namespace View +} // namespace RocProfVis diff --git a/src/view/src/compute/rocprofvis_compute_kernel_metric_table.h b/src/view/src/compute/rocprofvis_compute_kernel_metric_table.h new file mode 100644 index 00000000..5f769aa0 --- /dev/null +++ b/src/view/src/compute/rocprofvis_compute_kernel_metric_table.h @@ -0,0 +1,61 @@ +// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. +// SPDX-License-Identifier: MIT + +#pragma once +#include "widgets/rocprofvis_widget.h" +#include "widgets/rocprofvis_query_builder.h" +#include + +namespace RocProfVis +{ +namespace View +{ + +class DataProvider; +class ComputeSelection; + +class KernelMetricTable : public RocWidget +{ +public: + KernelMetricTable(DataProvider& data_provider, + std::shared_ptr compute_selection); + void Update() override; + void Render() override; + + void ClearData(); + void FetchData(uint32_t workload_id); + void HandleNewData(); + +private: + + void RenderLoadingIndicator() const; + + struct MetricInfo + { + AvailableMetrics::Entry entry; + std::string value_name; + }; + std::vector m_metrics_info; + std::vector m_metrics_params; + + std::vector m_metrics_column_names; + + DataProvider& m_data_provider; + QueryBuilder m_query_builder; + + int m_sort_column_index; + int m_sort_order; + + int m_selected_row; + + bool m_fetch_requested; + uint32_t m_workload_id; + + // used for selecting kernel + std::shared_ptr m_compute_selection; + uint32_t m_selected_kernel_id_local; + +}; + +} // namespace View +} // namespace RocProfVis \ No newline at end of file diff --git a/src/view/src/compute/rocprofvis_compute_tester.cpp b/src/view/src/compute/rocprofvis_compute_tester.cpp new file mode 100644 index 00000000..fe10a1d9 --- /dev/null +++ b/src/view/src/compute/rocprofvis_compute_tester.cpp @@ -0,0 +1,991 @@ +// Copyright Advanced Micro Devices, Inc. +// SPDX-License-Identifier: MIT + +#include "rocprofvis_compute_tester.h" +#include "rocprofvis_event_manager.h" +#include "implot/implot.h" +#include "spdlog/spdlog.h" + +namespace RocProfVis +{ +namespace View +{ + +ComputeTester::ComputeTester(DataProvider& data_provider, std::shared_ptr compute_selection) +: m_data_provider(data_provider) +, m_compute_selection(compute_selection) +, m_selections({ true, 0, {}, {}, SelectionState::FP32, {}, {}, {} }) +, m_display_names({ + { + { kRPVControllerRooflineCeilingComputeVALUI8, "VALU I8" }, + { kRPVControllerRooflineCeilingComputeMFMAI8, "MFMA I8" }, + { kRPVControllerRooflineCeilingComputeMFMAFP4, "MFMA FP4" }, + { kRPVControllerRooflineCeilingComputeMFMAFP6, "MFMA FP6" }, + { kRPVControllerRooflineCeilingComputeMFMAFP8, "MFMA FP8" }, + { kRPVControllerRooflineCeilingComputeMFMABF16, "MFMA BF16" }, + { kRPVControllerRooflineCeilingComputeVALUFP16, "VALU FP16" }, + { kRPVControllerRooflineCeilingComputeMFMAFP16, "MFMA FP16" }, + { kRPVControllerRooflineCeilingComputeVALUI32, "VALU I32" }, + { kRPVControllerRooflineCeilingComputeVALUFP32, "VALU FP32" }, + { kRPVControllerRooflineCeilingComputeMFMAFP32, "MFMA FP32" }, + { kRPVControllerRooflineCeilingComputeVALUI64, "VALU I64" }, + { kRPVControllerRooflineCeilingComputeVALUFP64, "VALU FP64" }, + { kRPVControllerRooflineCeilingComputeMFMAFP64, "MFMA FP64" }, + }, + { + { kRPVControllerRooflineCeilingTypeBandwidthHBM, "HBM" }, + { kRPVControllerRooflineCeilingTypeBandwidthL2, "L2" }, + { kRPVControllerRooflineCeilingTypeBandwidthL1, "L1" }, + { kRPVControllerRooflineCeilingTypeBandwidthLDS, "LDS" }, + }, + { + { kRPVControllerRooflineKernelIntensityTypeHBM, "HBM" }, + { kRPVControllerRooflineKernelIntensityTypeL2, "L2" }, + { kRPVControllerRooflineKernelIntensityTypeL1, "L1" }, + }, + }) +{} + +ComputeTester::~ComputeTester() {} + +void +ComputeTester::Update() +{} + +void +ComputeTester::Render() +{ + const std::unordered_map& workloads = + m_data_provider.ComputeModel().GetWorkloads(); + + uint32_t global_workload_id = m_compute_selection + ? m_compute_selection->GetSelectedWorkload() + : ComputeSelection::INVALID_SELECTION_ID; + const WorkloadInfo* selected_wl = workloads.count(global_workload_id) + ? &workloads.at(global_workload_id) + : nullptr; + m_query_builder.SetWorkload(selected_wl); + + if(ImGui::Button("Open Query Builder")) + { + m_query_builder.Show( + [this](const std::string& query) { + // Handle query confirmation if needed + spdlog::debug("Query confirmed: {}", query); + }); + } + if(!m_query_builder.GetQueryString().empty()) + { + ImGui::SameLine(); + ImGui::Text("Query: %s", m_query_builder.GetQueryString().c_str()); + } + m_query_builder.Render(); + ImGui::NewLine(); + + ImGui::SetNextItemWidth(ImGui::GetFrameHeight() * 15.0f); + if(ImGui::BeginCombo("Workloads", + workloads.count(m_selections.workload_id) > 0 + ? workloads.at(m_selections.workload_id).name.c_str() + : "-")) + { + if(ImGui::Selectable("-", m_selections.workload_id == 0)) + { + m_selections.workload_id = 0; + } + for(const std::pair& workload : workloads) + { + if(ImGui::Selectable(workload.second.name.c_str(), + m_selections.workload_id == workload.second.id)) + { + m_selections.workload_id = workload.second.id; + m_selections.kernel_ids.clear(); + m_selections.metric_ids.clear(); + } + } + ImGui::EndCombo(); + } + if(workloads.count(m_selections.workload_id) > 0) + { + ImGui::BeginChild("sv"); + ImGui::BeginChild("info", ImVec2(0, 0), + ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY); + const WorkloadInfo& workload = workloads.at(m_selections.workload_id); + if(workload.system_info.size() == 2 && + workload.system_info[0].size() == workload.system_info[1].size()) + { + ImGui::BeginChild("sys_info", + ImVec2(ImGui::GetContentRegionAvail().x / 2.0f, 0.0f), + ImGuiChildFlags_AutoResizeY); + ImGui::Text("System Information"); + if(ImGui::BeginTable("", static_cast(workload.system_info.size()), + ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders)) + { + for(size_t i = 0; i < workload.system_info[0].size(); i++) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text(workload.system_info[0][i].c_str()); + ImGui::TableNextColumn(); + ImGui::Text(workload.system_info[1][i].c_str()); + } + ImGui::EndTable(); + } + ImGui::EndChild(); + } + if(workload.profiling_config.size() == 2 && + workload.profiling_config[0].size() == workload.profiling_config[1].size()) + { + ImGui::SameLine(); + ImGui::BeginChild("config", ImVec2(0, 0), ImGuiChildFlags_AutoResizeY); + ImGui::Text("Profiling Configuration"); + if(ImGui::BeginTable("", static_cast(workload.profiling_config.size()), + ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders)) + { + for(size_t i = 0; i < workload.profiling_config[0].size(); i++) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text(workload.profiling_config[0][i].c_str()); + ImGui::TableNextColumn(); + ImGui::Text(workload.profiling_config[1][i].c_str()); + } + ImGui::EndTable(); + } + ImGui::EndChild(); + } + ImGui::EndChild(); + ImGui::NewLine(); + ImGui::BeginChild("metrics", ImVec2(0, 0), + ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY); + ImGui::Text("Available Metrics"); + for(const std::pair& category : + workload.available_metrics.tree) + { + ImGui::PushID(static_cast(category.first)); + if(ImGui::TreeNodeEx(std::string("[" + std::to_string(category.second.id) + + "] " + category.second.name) + .c_str())) + { + for(const std::pair& table : + category.second.tables) + { + ImGui::PushID(static_cast(table.first)); + std::string partial_metric_id = std::to_string(category.second.id) + + "." + std::to_string(table.second.id); + bool table_selected = + m_selections.metric_ids.count(category.first) > 0 && + m_selections.metric_ids.at(category.first).count(table.first) > + 0 && + m_selections.metric_ids.at(category.first).at(table.first).first; + bool table_selected_changed = ImGui::Selectable("", table_selected); + if(table_selected_changed) + { + if(table_selected) + { + if(m_selections.metric_ids.at(category.first).size() == 1) + { + m_selections.metric_ids.erase(category.first); + } + else + { + m_selections.metric_ids.at(category.first) + .erase(table.first); + } + } + else + { + m_selections.metric_ids[category.first][table.first] = { true, + {} }; + } + } + ImGui::SameLine(0.0f); + ImGui::BeginDisabled(table_selected); + if(ImGui::TreeNodeEx( + std::string("[" + partial_metric_id + "] " + table.second.name) + .c_str(), + ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet)) + { + if(ImGui::BeginTable("", 5, + ImGuiTableFlags_RowBg | + ImGuiTableFlags_Borders | + ImGuiTableFlags_SizingStretchSame)) + { + int col = 0; + for(const std::pair& + entry : table.second.entries) + { + if(col % 5 == 0) + { + ImGui::TableNextRow(); + } + ImGui::TableNextColumn(); + bool entry_selected = + m_selections.metric_ids.count(category.first) > 0 && + m_selections.metric_ids.at(category.first) + .count(table.first) > 0 && + m_selections.metric_ids.at(category.first) + .at(table.first) + .second.count(entry.first) > 0; + if(ImGui::Selectable( + std::string("[" + partial_metric_id + "." + + std::to_string(entry.second.id) + + "] " + entry.second.name) + .c_str(), + entry_selected)) + { + if(entry_selected) + { + if(m_selections.metric_ids.at(category.first) + .at(table.first) + .second.size() == 1) + { + if(m_selections.metric_ids.at(category.first) + .size() == 1) + { + m_selections.metric_ids.erase( + category.first); + } + else + { + m_selections.metric_ids.at(category.first) + .erase(table.first); + } + } + else + { + m_selections.metric_ids.at(category.first) + .at(table.first) + .second.erase(entry.first); + } + } + else + { + m_selections + .metric_ids[category.first][table.first] + .second.insert(entry.first); + } + } + if(ImGui::BeginItemTooltip()) + { + ImGui::PushTextWrapPos(500.0f); + ImGui::Text("Description: "); + ImGui::SameLine(); + ImGui::Text(entry.second.description.c_str()); + ImGui::Text("Unit: "); + ImGui::SameLine(); + ImGui::Text(entry.second.unit.c_str()); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } + col++; + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + ImGui::EndDisabled(); + ImGui::PopID(); + } + ImGui::TreePop(); + } + ImGui::PopID(); + } + ImGui::EndChild(); + ImGui::NewLine(); + ImGui::BeginChild("kernels", ImVec2(0, 0), + ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY); + ImGui::Text("Kernels"); + if(ImGui::BeginTable("", 8, + ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | + ImGuiTableFlags_SizingStretchSame)) + { + ImGui::TableSetupColumn("ID"); + ImGui::TableSetupColumn("Name"); + ImGui::TableSetupColumn("Invocation Count"); + ImGui::TableSetupColumn("Total Duration"); + ImGui::TableSetupColumn("Min Duration"); + ImGui::TableSetupColumn("Max Duration"); + ImGui::TableSetupColumn("Mean Duration"); + ImGui::TableSetupColumn("Median Duration"); + ImGui::TableHeadersRow(); + for(const std::pair& kernel : workload.kernels) + { + ImGui::PushID(static_cast(kernel.second.id)); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("%u", kernel.second.id); + ImGui::SameLine(); + bool kernel_selected = + m_selections.kernel_ids.count(kernel.second.id) > 0; + if(ImGui::Selectable("", kernel_selected, + ImGuiSelectableFlags_SpanAllColumns)) + { + if(kernel_selected) + { + m_selections.kernel_ids.erase(kernel.second.id); + } + else + { + m_selections.kernel_ids.insert(kernel.second.id); + } + } + ImGui::TableNextColumn(); + ImGui::Text(kernel.second.name.c_str()); + ImGui::TableNextColumn(); + ImGui::Text("%u", kernel.second.invocation_count); + ImGui::TableNextColumn(); + ImGui::Text("%llu", kernel.second.duration_total); + ImGui::TableNextColumn(); + ImGui::Text("%u", kernel.second.duration_min); + ImGui::TableNextColumn(); + ImGui::Text("%u", kernel.second.duration_max); + ImGui::TableNextColumn(); + ImGui::Text("%u", kernel.second.duration_mean); + ImGui::TableNextColumn(); + ImGui::Text("%u", kernel.second.duration_median); + ImGui::PopID(); + } + ImGui::EndTable(); + } + ImGui::EndChild(); + ImGui::NewLine(); + ImGui::BeginChild("fetcher", ImVec2(0, 0), + ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY); + ImGui::Text("Fetcher"); + if(ImGui::BeginTable( + "selected_metrics", 1, + ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | + ImGuiTableFlags_SizingStretchSame, + ImVec2((ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize("for").x) / + 2.0f, + 0.0f))) + { + ImGui::TableSetupColumn("Metric ID(s)"); + ImGui::TableHeadersRow(); + if(m_selections.metric_ids.empty()) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextDisabled("None"); + } + else + { + for(const std::pair< + const uint32_t, + std::unordered_map< + uint32_t, std::pair>>>& + category : m_selections.metric_ids) + { + for(const std::pair>>& + table : category.second) + { + if(table.second.second.empty()) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("%u.%u", category.first, table.first); + } + else + { + for(const uint32_t& entry : table.second.second) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("%u.%u.%u", category.first, table.first, + entry); + } + } + } + } + } + + ImGui::EndTable(); + } + ImGui::SameLine(); + ImGui::SetCursorPosY(ImGui::GetItemRectSize().y / 2.0f); + ImGui::Text(" for "); + ImGui::SameLine(); + if(ImGui::BeginTable("selected_kernels", 1, + ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | + ImGuiTableFlags_SizingStretchSame)) + { + ImGui::TableSetupColumn("Kernel ID(s)"); + ImGui::TableHeadersRow(); + if(m_selections.kernel_ids.empty()) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextDisabled("None"); + } + for(const uint32_t& id : m_selections.kernel_ids) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text(std::to_string(id).c_str()); + } + ImGui::EndTable(); + } + ImGui::NewLine(); + ImGui::BeginDisabled(m_selections.metric_ids.empty() || + m_selections.kernel_ids.empty()); + + if(ImGui::Button("Clear all clients")) + { + m_data_provider.ComputeModel().ClearAllMetricValues(); + } + ImGui::SameLine(); + uint64_t client_id = 0; + bool do_clear = false; + if(ImGui::Button("Clear client 1")) + { + client_id = 1; + do_clear = true; + } + ImGui::SameLine(); + if(ImGui::Button("Clear client 2")) + { + client_id = 2; + do_clear = true; + } + ImGui::SameLine(); + bool do_fetch = false; + if(ImGui::Button("Fetch client 1")) + { + do_fetch = true; + client_id = 1; + } + ImGui::SameLine(); + if(ImGui::Button("Fetch client 2")) + { + do_fetch = true; + client_id = 2; + } + + if(do_clear) + { + for(const uint32_t& kernel_id : m_selections.kernel_ids) + { + m_data_provider.ComputeModel().ClearMetricValues(client_id, kernel_id); + } + } + if(do_fetch) + { + std::vector kernel_ids; + kernel_ids.insert(kernel_ids.end(), m_selections.kernel_ids.begin(), + m_selections.kernel_ids.end()); + std::vector metric_ids; + for(const std::pair< + const uint32_t, + std::unordered_map>>>& + category : m_selections.metric_ids) + { + for(const std::pair>>& + table : category.second) + { + if(table.second.second.empty()) + { + metric_ids.emplace_back(MetricsRequestParams::MetricID{ + category.first, table.first, std::nullopt }); + } + else + { + for(const uint32_t& entry : table.second.second) + { + metric_ids.emplace_back(MetricsRequestParams::MetricID{ + category.first, table.first, entry }); + } + } + } + } + + m_data_provider.FetchMetrics( + MetricsRequestParams(workload.id, kernel_ids, metric_ids, client_id)); + } + ImGui::EndDisabled(); + ImGui::NewLine(); + + // loop through clients (mock client ids 1 and 2) + for(uint64_t c_id : { 1, 2 }) + { + ImGui::Separator(); + ImGui::Text("Client ID: %llu", c_id); + // Display fetched metrics for selected kernels + for(const uint32_t& kernel_id : m_selections.kernel_ids) + { + + ImGui::Text("Metrics for Kernel ID: %u", kernel_id); + const std::vector>* metrics = + m_data_provider.ComputeModel().GetMetricsData(c_id, kernel_id); + + if(metrics == nullptr) + { + ImGui::TextDisabled("No metrics fetched for this kernel."); + continue; + } + if(ImGui::BeginTable( + "results", 5, + ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | + ImGuiTableFlags_SizingStretchSame, + ImVec2(0.0f, metrics->empty() + ? ImGui::GetTextLineHeightWithSpacing() + : ImGui::GetTextLineHeightWithSpacing() * + (1.0f + static_cast(metrics->size()))))) + { + ImGui::TableSetupColumn("Metric ID"); + ImGui::TableSetupColumn("Metric Name"); + ImGui::TableSetupColumn("Kernel ID"); + ImGui::TableSetupColumn("Value Name"); + ImGui::TableSetupColumn("Value"); + ImGui::TableHeadersRow(); + if(metrics->empty()) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextDisabled("None"); + } + for(const std::shared_ptr& metric : *metrics) + { + if(metric && metric->entry && metric->kernel) + { + for(const std::pair& value : + metric->values) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("%u.%u.%u", metric->entry->category_id, + metric->entry->table_id, metric->entry->id); + ImGui::TableNextColumn(); + ImGui::Text(metric->entry->name.c_str()); + ImGui::TableNextColumn(); + ImGui::Text("%u", metric->kernel->id); + ImGui::TableNextColumn(); + ImGui::Text(value.first.c_str()); + ImGui::TableNextColumn(); + ImGui::Text("%f", value.second); + } + } + } + ImGui::EndTable(); + } + } + } + ImGui::EndChild(); + + ImGui::NewLine(); + ImGui::BeginChild("SOL", ImVec2(0, 0), + ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY); + ImGui::Text("Speed of light (SOL)"); + + TableKey table_key = { 2, 1 }; // SOL + //assume client id 1 and kernel id 1 for test + ComputeDataModel::MetricValuesByEntryId* sol_metrics = + m_data_provider.ComputeModel().GetMetricValuesByTable(1, 1, table_key.id); + if(!sol_metrics || sol_metrics->empty()) + { + ImGui::TextDisabled("No SOL metrics available for client 1."); + } + else + { + if(ImGui::BeginTable("sol_table", 5, + ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | + ImGuiTableFlags_SizingStretchSame, + ImVec2(0.0f, 0.0f))) { + ImGui::TableSetupColumn("Metric ID"); + ImGui::TableSetupColumn("Metric Name"); + ImGui::TableSetupColumn("Kernel ID"); + ImGui::TableSetupColumn("Value Name"); + ImGui::TableSetupColumn("Value"); + ImGui::TableHeadersRow(); + for(auto it = sol_metrics->begin(); it != sol_metrics->end(); ++it) + { + const std::shared_ptr& metric = it->second; + if(metric && metric->entry && metric->kernel) + { + for(const std::pair& value : + metric->values) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("%u.%u.%u", metric->entry->category_id, + metric->entry->table_id, metric->entry->id); + ImGui::TableNextColumn(); + ImGui::Text(metric->entry->name.c_str()); + ImGui::TableNextColumn(); + ImGui::Text("%u", metric->kernel->id); + ImGui::TableNextColumn(); + ImGui::Text(value.first.c_str()); + ImGui::TableNextColumn(); + ImGui::Text("%f", value.second); + } + } + } + + ImGui::EndTable(); + } + } + ImGui::EndChild(); + + ImGui::NewLine(); + ImGui::BeginChild("roofline", ImVec2(0, 0), + ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY); + int i = 0; + if(ImPlot::BeginPlot("Roofline", ImVec2(-1, 0), ImPlotFlags_Crosshairs)) + { + ImPlot::SetupAxisScale(ImAxis_X1, ImPlotScale_Log10); + ImPlot::SetupAxisScale(ImAxis_Y1, ImPlotScale_Log10); + + for(const std::pair& kernel : workload.kernels) + { + for(const std::pair< + const rocprofvis_controller_roofline_kernel_intensity_type_t, + KernelInfo::Roofline::Intensity>& intensity : + kernel.second.roofline.intensities) + { + if(m_selections.intensities.count(kernel.second.id) > 0 && + m_selections.intensities.at(kernel.second.id) + .count(intensity.second.type) > 0) + { + ImGui::PushID(i++); + ImPlot::PlotScatter("", &intensity.second.position.x, + &intensity.second.position.y, 1); + ImGui::PopID(); + } + } + } + for(const auto& compute_it : workload.roofline.ceiling_compute) + { + for(const auto& bandwidth_it : compute_it.second) + { + if(m_selections.ceilings_compute.count(compute_it.first) > 0 && + m_selections.ceilings_compute.at(compute_it.first) + .count(bandwidth_it.first) > 0) + { + ImGui::PushID(i++); + ImPlot::PlotLineG( + "", + [](int idx, void* user_data) -> ImPlotPoint { + const WorkloadInfo::Roofline::Line* line = + static_cast( + user_data); + ImPlotPoint point(-1.0, -1.0); + if(line) + { + if(idx == 0) + { + point.x = line->p1.x; + point.y = line->p1.y; + } + else + { + point.x = line->p2.x; + point.y = line->p2.y; + } + } + return point; + }, + (void*) &bandwidth_it.second.position, 2); + ImGui::PopID(); + } + } + } + for(const auto& bandwidth_it : workload.roofline.ceiling_bandwidth) + { + for(const auto& compute_it : bandwidth_it.second) + { + if(m_selections.ceilings_bandwidth.count(bandwidth_it.first) > 0 && + m_selections.ceilings_bandwidth.at(bandwidth_it.first) + .count(compute_it.first) > 0) + { + ImGui::PushID(i++); + ImPlot::PlotLineG( + "", + [](int idx, void* user_data) -> ImPlotPoint { + const WorkloadInfo::Roofline::Line* line = + static_cast( + user_data); + ImPlotPoint point(-1.0, -1.0); + if(line) + { + if(idx == 0) + { + point.x = line->p1.x; + point.y = line->p1.y; + } + else + { + point.x = line->p2.x; + point.y = line->p2.y; + } + } + return point; + }, + (void*) &compute_it.second.position, 2); + ImGui::PopID(); + } + } + } + ImPlot::EndPlot(); + } + int preset_idx = static_cast(m_selections.roofline_preset); + if(m_selections.init || + ImGui::Combo("Presets", &preset_idx, "FP32\0FP64\0Custom\0\0")) + { + m_selections.roofline_preset = + static_cast(preset_idx); + if(m_selections.roofline_preset == SelectionState::FP32) + { + m_selections.ceilings_compute = { + { kRPVControllerRooflineCeilingComputeMFMAFP32, + { kRPVControllerRooflineCeilingTypeBandwidthLDS } }, + { kRPVControllerRooflineCeilingComputeVALUFP32, + { kRPVControllerRooflineCeilingTypeBandwidthLDS } } + }; + m_selections.ceilings_bandwidth = { + { kRPVControllerRooflineCeilingTypeBandwidthHBM, + { kRPVControllerRooflineCeilingComputeMFMAFP32 } }, + { kRPVControllerRooflineCeilingTypeBandwidthL2, + { kRPVControllerRooflineCeilingComputeMFMAFP32 } }, + { kRPVControllerRooflineCeilingTypeBandwidthL1, + { kRPVControllerRooflineCeilingComputeMFMAFP32 } }, + { kRPVControllerRooflineCeilingTypeBandwidthLDS, + { kRPVControllerRooflineCeilingComputeMFMAFP32 } }, + }; + for(const std::pair& kernel : + workload.kernels) + { + for(const std::pair< + const rocprofvis_controller_roofline_kernel_intensity_type_t, + KernelInfo::Roofline::Intensity>& intensity : + kernel.second.roofline.intensities) + { + m_selections.intensities[kernel.second.id].insert( + intensity.second.type); + } + } + } + else if(m_selections.roofline_preset == SelectionState::FP64) + { + m_selections.ceilings_compute = { + { kRPVControllerRooflineCeilingComputeMFMAFP64, + { kRPVControllerRooflineCeilingTypeBandwidthLDS } }, + { kRPVControllerRooflineCeilingComputeVALUFP64, + { kRPVControllerRooflineCeilingTypeBandwidthLDS } } + }; + m_selections.ceilings_bandwidth = { + { kRPVControllerRooflineCeilingTypeBandwidthHBM, + { kRPVControllerRooflineCeilingComputeMFMAFP64 } }, + { kRPVControllerRooflineCeilingTypeBandwidthL2, + { kRPVControllerRooflineCeilingComputeMFMAFP64 } }, + { kRPVControllerRooflineCeilingTypeBandwidthL1, + { kRPVControllerRooflineCeilingComputeMFMAFP64 } }, + { kRPVControllerRooflineCeilingTypeBandwidthLDS, + { kRPVControllerRooflineCeilingComputeMFMAFP64 } }, + }; + for(const std::pair& kernel : + workload.kernels) + { + for(const std::pair< + const rocprofvis_controller_roofline_kernel_intensity_type_t, + KernelInfo::Roofline::Intensity>& intensity : + kernel.second.roofline.intensities) + { + m_selections.intensities[kernel.second.id].insert( + intensity.second.type); + } + } + } + } + if(m_selections.roofline_preset == SelectionState::Custom && + ImGui::BeginTable("customizer", 2, + ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | + ImGuiTableFlags_SizingStretchSame)) + { + ImGui::TableSetupColumn("Type"); + ImGui::TableSetupColumn("Element"); + ImGui::TableHeadersRow(); + for(const std::pair& kernel : workload.kernels) + { + for(const std::pair< + const rocprofvis_controller_roofline_kernel_intensity_type_t, + KernelInfo::Roofline::Intensity>& intensity : + kernel.second.roofline.intensities) + { + ImGui::PushID(i++); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Kernel Intensity"); + ImGui::SameLine(); + bool show = m_selections.intensities.count(kernel.second.id) > 0 && + m_selections.intensities.at(kernel.second.id) + .count(intensity.second.type) > 0; + if(ImGui::Selectable("", show, ImGuiSelectableFlags_SpanAllColumns)) + { + if(show) + { + m_selections.intensities.at(kernel.second.id) + .erase(intensity.second.type); + } + else + { + m_selections.intensities[kernel.second.id].insert( + intensity.second.type); + } + } + ImGui::TableNextColumn(); + ImGui::Text("ID:%u - %s", kernel.second.id, + m_display_names.intensity.at(intensity.second.type)); + ImGui::PopID(); + } + } + for(const auto& compute_it : workload.roofline.ceiling_compute) + { + for(const auto& bandwidth_it : compute_it.second) + { + ImGui::PushID(i++); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Compute Ceiling"); + ImGui::SameLine(); + bool show = + m_selections.ceilings_compute.count(compute_it.first) > 0 && + m_selections.ceilings_compute.at(compute_it.first) + .count(bandwidth_it.first) > 0; + if(ImGui::Selectable("", show, ImGuiSelectableFlags_SpanAllColumns)) + { + if(show) + { + m_selections.ceilings_compute.at(compute_it.first) + .erase(bandwidth_it.first); + } + else + { + m_selections.ceilings_compute[compute_it.first].insert( + bandwidth_it.first); + } + } + ImGui::TableNextColumn(); + ImGui::Text("%s-%s", + m_display_names.ceiling_compute.at(compute_it.first), + m_display_names.ceiling_bandwidth.at(bandwidth_it.first)); + ImGui::PopID(); + } + } + for(const auto& bandwidth_it : workload.roofline.ceiling_bandwidth) + { + for(const auto& compute_it : bandwidth_it.second) + { + ImGui::PushID(i++); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Bandwidth Ceiling"); + ImGui::SameLine(); + bool show = + m_selections.ceilings_bandwidth.count(bandwidth_it.first) > 0 && + m_selections.ceilings_bandwidth.at(bandwidth_it.first) + .count(compute_it.first) > 0; + if(ImGui::Selectable("", show, ImGuiSelectableFlags_SpanAllColumns)) + { + if(show) + { + m_selections.ceilings_bandwidth.at(bandwidth_it.first) + .erase(compute_it.first); + } + else + { + m_selections.ceilings_bandwidth[bandwidth_it.first].insert( + compute_it.first); + } + } + ImGui::TableNextColumn(); + ImGui::Text("%s-%s", + m_display_names.ceiling_bandwidth.at(bandwidth_it.first), + m_display_names.ceiling_compute.at(compute_it.first)); + ImGui::PopID(); + } + } + ImGui::EndTable(); + } + ImGui::EndChild(); + ImGui::NewLine(); + ImGui::BeginChild("value_names_lookup", ImVec2(0, 0), + ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY); + ImGui::Text("Value Names Lookup"); + ImGui::InputText("Metric ID (e.g. 3.1.2)", m_value_names_input, + sizeof(m_value_names_input)); + + const WorkloadInfo& wl = workloads.at(m_selections.workload_id); + ImGui::Text("Workload: %s (metrics: %zu, categories: %zu)", + wl.name.c_str(), + wl.available_metrics.list.size(), + wl.available_metrics.tree.size()); + + std::string input(m_value_names_input); + auto dot1 = input.find('.'); + auto dot2 = (dot1 != std::string::npos) ? input.find('.', dot1 + 1) + : std::string::npos; + if(dot1 != std::string::npos && dot2 != std::string::npos && + dot2 + 1 < input.size()) + { + uint32_t cat_id = static_cast(std::stoul(input.substr(0, dot1))); + uint32_t tbl_id = static_cast( + std::stoul(input.substr(dot1 + 1, dot2 - dot1 - 1))); + uint32_t entry_id = static_cast( + std::stoul(input.substr(dot2 + 1))); + + ImGui::Text("Looking up: cat=%u, table=%u, entry=%u", cat_id, tbl_id, entry_id); + + if(wl.available_metrics.tree.count(cat_id)) + { + const auto& cat = wl.available_metrics.tree.at(cat_id); + if(cat.tables.count(tbl_id)) + { + const auto& tbl = cat.tables.at(tbl_id); + if(tbl.entries.count(entry_id)) + { + const AvailableMetrics::Entry& entry = tbl.entries.at(entry_id); + ImGui::Text("Metric: [%u.%u.%u] %s", + entry.category_id, entry.table_id, entry.id, + entry.name.c_str()); + } + else + { + ImGui::TextColored(ImVec4(1, 0.4f, 0.4f, 1), + "Entry %u not found in table %u (table has %zu entries)", + entry_id, tbl_id, tbl.entries.size()); + } + if(tbl.value_names.empty()) + { + ImGui::TextDisabled("No value names found for table %u", tbl_id); + } + else + { + ImGui::Text("Value Names (%zu):", tbl.value_names.size()); + for(const std::string& vn : tbl.value_names) + { + ImGui::BulletText("%s", vn.c_str()); + } + } + } + else + { + ImGui::TextColored(ImVec4(1, 0.4f, 0.4f, 1), + "Table %u not found in category %u", tbl_id, cat_id); + } + } + else + { + ImGui::TextColored(ImVec4(1, 0.4f, 0.4f, 1), + "Category %u not found", cat_id); + } + } + ImGui::EndChild(); + ImGui::EndChild(); + m_selections.init = false; + } +} + +} // namespace View +} // namespace RocProfVis diff --git a/src/view/src/compute/rocprofvis_compute_tester.h b/src/view/src/compute/rocprofvis_compute_tester.h new file mode 100644 index 00000000..e72f612c --- /dev/null +++ b/src/view/src/compute/rocprofvis_compute_tester.h @@ -0,0 +1,80 @@ +// Copyright Advanced Micro Devices, Inc. +// SPDX-License-Identifier: MIT + +#pragma once +#include "rocprofvis_data_provider.h" +#include "rocprofvis_compute_selection.h" +#include "widgets/rocprofvis_query_builder.h" +#include "widgets/rocprofvis_widget.h" +#include +#include + +namespace RocProfVis +{ +namespace View +{ + +class ComputeTester : public RocWidget +{ +public: + ComputeTester(DataProvider& data_provider, std::shared_ptr compute_selection); + ~ComputeTester(); + + void Update() override; + void Render() override; + +private: + + struct SelectionState + { + enum RooflinePreset + { + FP32, + FP64, + Custom + }; + bool init; + uint32_t workload_id; + std::unordered_set kernel_ids; + std::unordered_map< + uint32_t, + std::unordered_map>>> + metric_ids; + RooflinePreset roofline_preset; + std::unordered_map< + rocprofvis_controller_roofline_ceiling_compute_type_t, + std::unordered_set> + ceilings_compute; + std::unordered_map< + rocprofvis_controller_roofline_ceiling_bandwidth_type_t, + std::unordered_set> + ceilings_bandwidth; + std::unordered_map< + uint32_t, + std::unordered_set> + intensities; + }; + struct DisplayStrings + { + std::unordered_map + ceiling_compute; + std::unordered_map + ceiling_bandwidth; + std::unordered_map + intensity; + }; + + DataProvider& m_data_provider; + std::shared_ptr m_compute_selection; + SelectionState m_selections; + DisplayStrings m_display_names; + QueryBuilder m_query_builder; + + char m_value_names_input[64] = "3.1.2"; +}; + +} // 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 98f2e07e..e3f7fdc0 100644 --- a/src/view/src/compute/rocprofvis_compute_view.cpp +++ b/src/view/src/compute/rocprofvis_compute_view.cpp @@ -2,16 +2,18 @@ // SPDX-License-Identifier: MIT #include "rocprofvis_compute_view.h" -#include "rocprofvis_compute_table_view.h" +#include "model/compute/rocprofvis_compute_data_model.h" #include "rocprofvis_compute_kernel_details.h" +#include "rocprofvis_compute_roofline.h" #include "rocprofvis_compute_summary.h" -#include "implot/implot.h" +#include "rocprofvis_compute_table_view.h" +#include "rocprofvis_compute_tester.h" +#include "rocprofvis_compute_workload_view.h" #include "rocprofvis_event_manager.h" -#include "rocprofvis_compute_roofline.h" #include "rocprofvis_settings_manager.h" -#include "model/compute/rocprofvis_compute_data_model.h" #include "widgets/rocprofvis_notification_manager.h" +#include "implot/implot.h" #include "spdlog/spdlog.h" namespace RocProfVis @@ -46,7 +48,19 @@ ComputeView::ComputeView() } }); + m_data_provider.SetTableDataReadyCallback( + [](const std::string& trace_path, uint64_t request_id, uint64_t response_code) { + if(response_code != kRocProfVisResultSuccess) + { + NotificationManager::GetInstance().Show( + "Failed to fetch table data for trace: " + trace_path, + NotificationLevel::Error); + } + // trigger new table data event to update the UI + EventManager::GetInstance()->AddEvent( + std::make_shared(trace_path, request_id, response_code)); + }); } ComputeView::~ComputeView() {} @@ -220,1098 +234,6 @@ ComputeView::RenderWorkloadSelection() } } -ComputeTester::ComputeTester(DataProvider& data_provider, std::shared_ptr compute_selection) -: m_data_provider(data_provider) -, m_compute_selection(compute_selection) -, m_selections({ true, 0, {}, {}, SelectionState::FP32, {}, {}, {} }) -, m_display_names({ - { - { kRPVControllerRooflineCeilingComputeVALUI8, "VALU I8" }, - { kRPVControllerRooflineCeilingComputeMFMAI8, "MFMA I8" }, - { kRPVControllerRooflineCeilingComputeMFMAFP4, "MFMA FP4" }, - { kRPVControllerRooflineCeilingComputeMFMAFP6, "MFMA FP6" }, - { kRPVControllerRooflineCeilingComputeMFMAFP8, "MFMA FP8" }, - { kRPVControllerRooflineCeilingComputeMFMABF16, "MFMA BF16" }, - { kRPVControllerRooflineCeilingComputeVALUFP16, "VALU FP16" }, - { kRPVControllerRooflineCeilingComputeMFMAFP16, "MFMA FP16" }, - { kRPVControllerRooflineCeilingComputeVALUI32, "VALU I32" }, - { kRPVControllerRooflineCeilingComputeVALUFP32, "VALU FP32" }, - { kRPVControllerRooflineCeilingComputeMFMAFP32, "MFMA FP32" }, - { kRPVControllerRooflineCeilingComputeVALUI64, "VALU I64" }, - { kRPVControllerRooflineCeilingComputeVALUFP64, "VALU FP64" }, - { kRPVControllerRooflineCeilingComputeMFMAFP64, "MFMA FP64" }, - }, - { - { kRPVControllerRooflineCeilingTypeBandwidthHBM, "HBM" }, - { kRPVControllerRooflineCeilingTypeBandwidthL2, "L2" }, - { kRPVControllerRooflineCeilingTypeBandwidthL1, "L1" }, - { kRPVControllerRooflineCeilingTypeBandwidthLDS, "LDS" }, - }, - { - { kRPVControllerRooflineKernelIntensityTypeHBM, "HBM" }, - { kRPVControllerRooflineKernelIntensityTypeL2, "L2" }, - { kRPVControllerRooflineKernelIntensityTypeL1, "L1" }, - }, - }) -{} - -ComputeTester::~ComputeTester() {} - -void -ComputeTester::Update() -{} - -void -ComputeTester::Render() -{ - const std::unordered_map& workloads = - m_data_provider.ComputeModel().GetWorkloads(); - - uint32_t global_workload_id = m_compute_selection - ? m_compute_selection->GetSelectedWorkload() - : ComputeSelection::INVALID_SELECTION_ID; - const WorkloadInfo* selected_wl = workloads.count(global_workload_id) - ? &workloads.at(global_workload_id) - : nullptr; - m_query_builder.SetWorkload(selected_wl); - - if(ImGui::Button("Open Query Builder")) - { - m_query_builder.Open(); - } - if(!m_query_builder.GetQueryString().empty()) - { - ImGui::SameLine(); - ImGui::Text("Query: %s", m_query_builder.GetQueryString().c_str()); - } - m_query_builder.Render(); - ImGui::NewLine(); - - ImGui::SetNextItemWidth(ImGui::GetFrameHeight() * 15.0f); - if(ImGui::BeginCombo("Workloads", - workloads.count(m_selections.workload_id) > 0 - ? workloads.at(m_selections.workload_id).name.c_str() - : "-")) - { - if(ImGui::Selectable("-", m_selections.workload_id == 0)) - { - m_selections.workload_id = 0; - } - for(const std::pair& workload : workloads) - { - if(ImGui::Selectable(workload.second.name.c_str(), - m_selections.workload_id == workload.second.id)) - { - m_selections.workload_id = workload.second.id; - m_selections.kernel_ids.clear(); - m_selections.metric_ids.clear(); - } - } - ImGui::EndCombo(); - } - if(workloads.count(m_selections.workload_id) > 0) - { - ImGui::BeginChild("sv"); - ImGui::BeginChild("info", ImVec2(0, 0), - ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY); - const WorkloadInfo& workload = workloads.at(m_selections.workload_id); - if(workload.system_info.size() == 2 && - workload.system_info[0].size() == workload.system_info[1].size()) - { - ImGui::BeginChild("sys_info", - ImVec2(ImGui::GetContentRegionAvail().x / 2.0f, 0.0f), - ImGuiChildFlags_AutoResizeY); - ImGui::Text("System Information"); - if(ImGui::BeginTable("", static_cast(workload.system_info.size()), - ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders)) - { - for(size_t i = 0; i < workload.system_info[0].size(); i++) - { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text(workload.system_info[0][i].c_str()); - ImGui::TableNextColumn(); - ImGui::Text(workload.system_info[1][i].c_str()); - } - ImGui::EndTable(); - } - ImGui::EndChild(); - } - if(workload.profiling_config.size() == 2 && - workload.profiling_config[0].size() == workload.profiling_config[1].size()) - { - ImGui::SameLine(); - ImGui::BeginChild("config", ImVec2(0, 0), ImGuiChildFlags_AutoResizeY); - ImGui::Text("Profiling Configuration"); - if(ImGui::BeginTable("", static_cast(workload.profiling_config.size()), - ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders)) - { - for(size_t i = 0; i < workload.profiling_config[0].size(); i++) - { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text(workload.profiling_config[0][i].c_str()); - ImGui::TableNextColumn(); - ImGui::Text(workload.profiling_config[1][i].c_str()); - } - ImGui::EndTable(); - } - ImGui::EndChild(); - } - ImGui::EndChild(); - ImGui::NewLine(); - ImGui::BeginChild("metrics", ImVec2(0, 0), - ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY); - ImGui::Text("Available Metrics"); - for(const std::pair& category : - workload.available_metrics.tree) - { - ImGui::PushID(static_cast(category.first)); - if(ImGui::TreeNodeEx(std::string("[" + std::to_string(category.second.id) + - "] " + category.second.name) - .c_str())) - { - for(const std::pair& table : - category.second.tables) - { - ImGui::PushID(static_cast(table.first)); - std::string partial_metric_id = std::to_string(category.second.id) + - "." + std::to_string(table.second.id); - bool table_selected = - m_selections.metric_ids.count(category.first) > 0 && - m_selections.metric_ids.at(category.first).count(table.first) > - 0 && - m_selections.metric_ids.at(category.first).at(table.first).first; - bool table_selected_changed = ImGui::Selectable("", table_selected); - if(table_selected_changed) - { - if(table_selected) - { - if(m_selections.metric_ids.at(category.first).size() == 1) - { - m_selections.metric_ids.erase(category.first); - } - else - { - m_selections.metric_ids.at(category.first) - .erase(table.first); - } - } - else - { - m_selections.metric_ids[category.first][table.first] = { true, - {} }; - } - } - ImGui::SameLine(0.0f); - ImGui::BeginDisabled(table_selected); - if(ImGui::TreeNodeEx( - std::string("[" + partial_metric_id + "] " + table.second.name) - .c_str(), - ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet)) - { - if(ImGui::BeginTable("", 5, - ImGuiTableFlags_RowBg | - ImGuiTableFlags_Borders | - ImGuiTableFlags_SizingStretchSame)) - { - int col = 0; - for(const std::pair& - entry : table.second.entries) - { - if(col % 5 == 0) - { - ImGui::TableNextRow(); - } - ImGui::TableNextColumn(); - bool entry_selected = - m_selections.metric_ids.count(category.first) > 0 && - m_selections.metric_ids.at(category.first) - .count(table.first) > 0 && - m_selections.metric_ids.at(category.first) - .at(table.first) - .second.count(entry.first) > 0; - if(ImGui::Selectable( - std::string("[" + partial_metric_id + "." + - std::to_string(entry.second.id) + - "] " + entry.second.name) - .c_str(), - entry_selected)) - { - if(entry_selected) - { - if(m_selections.metric_ids.at(category.first) - .at(table.first) - .second.size() == 1) - { - if(m_selections.metric_ids.at(category.first) - .size() == 1) - { - m_selections.metric_ids.erase( - category.first); - } - else - { - m_selections.metric_ids.at(category.first) - .erase(table.first); - } - } - else - { - m_selections.metric_ids.at(category.first) - .at(table.first) - .second.erase(entry.first); - } - } - else - { - m_selections - .metric_ids[category.first][table.first] - .second.insert(entry.first); - } - } - if(ImGui::BeginItemTooltip()) - { - ImGui::PushTextWrapPos(500.0f); - ImGui::Text("Description: "); - ImGui::SameLine(); - ImGui::Text(entry.second.description.c_str()); - ImGui::Text("Unit: "); - ImGui::SameLine(); - ImGui::Text(entry.second.unit.c_str()); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); - } - col++; - } - ImGui::EndTable(); - } - ImGui::TreePop(); - } - ImGui::EndDisabled(); - ImGui::PopID(); - } - ImGui::TreePop(); - } - ImGui::PopID(); - } - ImGui::EndChild(); - ImGui::NewLine(); - ImGui::BeginChild("kernels", ImVec2(0, 0), - ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY); - ImGui::Text("Kernels"); - if(ImGui::BeginTable("", 8, - ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | - ImGuiTableFlags_SizingStretchSame)) - { - ImGui::TableSetupColumn("ID"); - ImGui::TableSetupColumn("Name"); - ImGui::TableSetupColumn("Invocation Count"); - ImGui::TableSetupColumn("Total Duration"); - ImGui::TableSetupColumn("Min Duration"); - ImGui::TableSetupColumn("Max Duration"); - ImGui::TableSetupColumn("Mean Duration"); - ImGui::TableSetupColumn("Median Duration"); - ImGui::TableHeadersRow(); - for(const std::pair& kernel : workload.kernels) - { - ImGui::PushID(static_cast(kernel.second.id)); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("%u", kernel.second.id); - ImGui::SameLine(); - bool kernel_selected = - m_selections.kernel_ids.count(kernel.second.id) > 0; - if(ImGui::Selectable("", kernel_selected, - ImGuiSelectableFlags_SpanAllColumns)) - { - if(kernel_selected) - { - m_selections.kernel_ids.erase(kernel.second.id); - } - else - { - m_selections.kernel_ids.insert(kernel.second.id); - } - } - ImGui::TableNextColumn(); - ImGui::Text(kernel.second.name.c_str()); - ImGui::TableNextColumn(); - ImGui::Text("%u", kernel.second.invocation_count); - ImGui::TableNextColumn(); - ImGui::Text("%llu", kernel.second.duration_total); - ImGui::TableNextColumn(); - ImGui::Text("%u", kernel.second.duration_min); - ImGui::TableNextColumn(); - ImGui::Text("%u", kernel.second.duration_max); - ImGui::TableNextColumn(); - ImGui::Text("%u", kernel.second.duration_mean); - ImGui::TableNextColumn(); - ImGui::Text("%u", kernel.second.duration_median); - ImGui::PopID(); - } - ImGui::EndTable(); - } - ImGui::EndChild(); - ImGui::NewLine(); - ImGui::BeginChild("fetcher", ImVec2(0, 0), - ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY); - ImGui::Text("Fetcher"); - if(ImGui::BeginTable( - "selected_metrics", 1, - ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | - ImGuiTableFlags_SizingStretchSame, - ImVec2((ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize("for").x) / - 2.0f, - 0.0f))) - { - ImGui::TableSetupColumn("Metric ID(s)"); - ImGui::TableHeadersRow(); - if(m_selections.metric_ids.empty()) - { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::TextDisabled("None"); - } - else - { - for(const std::pair< - const uint32_t, - std::unordered_map< - uint32_t, std::pair>>>& - category : m_selections.metric_ids) - { - for(const std::pair>>& - table : category.second) - { - if(table.second.second.empty()) - { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("%u.%u", category.first, table.first); - } - else - { - for(const uint32_t& entry : table.second.second) - { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("%u.%u.%u", category.first, table.first, - entry); - } - } - } - } - } - - ImGui::EndTable(); - } - ImGui::SameLine(); - ImGui::SetCursorPosY(ImGui::GetItemRectSize().y / 2.0f); - ImGui::Text(" for "); - ImGui::SameLine(); - if(ImGui::BeginTable("selected_kernels", 1, - ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | - ImGuiTableFlags_SizingStretchSame)) - { - ImGui::TableSetupColumn("Kernel ID(s)"); - ImGui::TableHeadersRow(); - if(m_selections.kernel_ids.empty()) - { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::TextDisabled("None"); - } - for(const uint32_t& id : m_selections.kernel_ids) - { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text(std::to_string(id).c_str()); - } - ImGui::EndTable(); - } - ImGui::NewLine(); - ImGui::BeginDisabled(m_selections.metric_ids.empty() || - m_selections.kernel_ids.empty()); - - if(ImGui::Button("Clear all clients")) - { - m_data_provider.ComputeModel().ClearAllMetricValues(); - } - ImGui::SameLine(); - uint64_t client_id = 0; - bool do_clear = false; - if(ImGui::Button("Clear client 1")) - { - client_id = 1; - do_clear = true; - } - ImGui::SameLine(); - if(ImGui::Button("Clear client 2")) - { - client_id = 2; - do_clear = true; - } - ImGui::SameLine(); - bool do_fetch = false; - if(ImGui::Button("Fetch client 1")) - { - do_fetch = true; - client_id = 1; - } - ImGui::SameLine(); - if(ImGui::Button("Fetch client 2")) - { - do_fetch = true; - client_id = 2; - } - - if(do_clear) - { - for(const uint32_t& kernel_id : m_selections.kernel_ids) - { - m_data_provider.ComputeModel().ClearMetricValues(client_id, kernel_id); - } - } - if(do_fetch) - { - std::vector kernel_ids; - kernel_ids.insert(kernel_ids.end(), m_selections.kernel_ids.begin(), - m_selections.kernel_ids.end()); - std::vector metric_ids; - for(const std::pair< - const uint32_t, - std::unordered_map>>>& - category : m_selections.metric_ids) - { - for(const std::pair>>& - table : category.second) - { - if(table.second.second.empty()) - { - metric_ids.emplace_back(MetricsRequestParams::MetricID{ - category.first, table.first, std::nullopt }); - } - else - { - for(const uint32_t& entry : table.second.second) - { - metric_ids.emplace_back(MetricsRequestParams::MetricID{ - category.first, table.first, entry }); - } - } - } - } - - m_data_provider.FetchMetrics( - MetricsRequestParams(workload.id, kernel_ids, metric_ids, client_id)); - } - ImGui::EndDisabled(); - ImGui::NewLine(); - - // loop through clients (mock client ids 1 and 2) - for(uint64_t c_id : { 1, 2 }) - { - ImGui::Separator(); - ImGui::Text("Client ID: %llu", c_id); - // Display fetched metrics for selected kernels - for(const uint32_t& kernel_id : m_selections.kernel_ids) - { - - ImGui::Text("Metrics for Kernel ID: %u", kernel_id); - const std::vector>* metrics = - m_data_provider.ComputeModel().GetMetricsData(c_id, kernel_id); - - if(metrics == nullptr) - { - ImGui::TextDisabled("No metrics fetched for this kernel."); - continue; - } - if(ImGui::BeginTable( - "results", 5, - ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | - ImGuiTableFlags_SizingStretchSame, - ImVec2(0.0f, metrics->empty() - ? ImGui::GetTextLineHeightWithSpacing() - : ImGui::GetTextLineHeightWithSpacing() * - (1.0f + static_cast(metrics->size()))))) - { - ImGui::TableSetupColumn("Metric ID"); - ImGui::TableSetupColumn("Metric Name"); - ImGui::TableSetupColumn("Kernel ID"); - ImGui::TableSetupColumn("Value Name"); - ImGui::TableSetupColumn("Value"); - ImGui::TableHeadersRow(); - if(metrics->empty()) - { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::TextDisabled("None"); - } - for(const std::shared_ptr& metric : *metrics) - { - if(metric && metric->entry && metric->kernel) - { - for(const std::pair& value : - metric->values) - { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("%u.%u.%u", metric->entry->category_id, - metric->entry->table_id, metric->entry->id); - ImGui::TableNextColumn(); - ImGui::Text(metric->entry->name.c_str()); - ImGui::TableNextColumn(); - ImGui::Text("%u", metric->kernel->id); - ImGui::TableNextColumn(); - ImGui::Text(value.first.c_str()); - ImGui::TableNextColumn(); - ImGui::Text("%f", value.second); - } - } - } - ImGui::EndTable(); - } - } - } - ImGui::EndChild(); - - ImGui::NewLine(); - ImGui::BeginChild("SOL", ImVec2(0, 0), - ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY); - ImGui::Text("Speed of light (SOL)"); - - TableKey table_key = { 2, 1 }; // SOL - //assume client id 1 and kernel id 1 for test - ComputeDataModel::MetricValuesByEntryId* sol_metrics = - m_data_provider.ComputeModel().GetMetricValuesByTable(1, 1, table_key.id); - if(!sol_metrics || sol_metrics->empty()) - { - ImGui::TextDisabled("No SOL metrics available for client 1."); - } - else - { - if(ImGui::BeginTable("sol_table", 5, - ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | - ImGuiTableFlags_SizingStretchSame, - ImVec2(0.0f, 0.0f))) { - ImGui::TableSetupColumn("Metric ID"); - ImGui::TableSetupColumn("Metric Name"); - ImGui::TableSetupColumn("Kernel ID"); - ImGui::TableSetupColumn("Value Name"); - ImGui::TableSetupColumn("Value"); - ImGui::TableHeadersRow(); - for(auto it = sol_metrics->begin(); it != sol_metrics->end(); ++it) - { - const std::shared_ptr& metric = it->second; - if(metric && metric->entry && metric->kernel) - { - for(const std::pair& value : - metric->values) - { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("%u.%u.%u", metric->entry->category_id, - metric->entry->table_id, metric->entry->id); - ImGui::TableNextColumn(); - ImGui::Text(metric->entry->name.c_str()); - ImGui::TableNextColumn(); - ImGui::Text("%u", metric->kernel->id); - ImGui::TableNextColumn(); - ImGui::Text(value.first.c_str()); - ImGui::TableNextColumn(); - ImGui::Text("%f", value.second); - } - } - } - - ImGui::EndTable(); - } - } - ImGui::EndChild(); - - ImGui::NewLine(); - ImGui::BeginChild("roofline", ImVec2(0, 0), - ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY); - int i = 0; - if(ImPlot::BeginPlot("Roofline", ImVec2(-1, 0), ImPlotFlags_Crosshairs)) - { - ImPlot::SetupAxisScale(ImAxis_X1, ImPlotScale_Log10); - ImPlot::SetupAxisScale(ImAxis_Y1, ImPlotScale_Log10); - - for(const std::pair& kernel : workload.kernels) - { - for(const std::pair< - const rocprofvis_controller_roofline_kernel_intensity_type_t, - KernelInfo::Roofline::Intensity>& intensity : - kernel.second.roofline.intensities) - { - if(m_selections.intensities.count(kernel.second.id) > 0 && - m_selections.intensities.at(kernel.second.id) - .count(intensity.second.type) > 0) - { - ImGui::PushID(i++); - ImPlot::PlotScatter("", &intensity.second.position.x, - &intensity.second.position.y, 1); - ImGui::PopID(); - } - } - } - for(const auto& compute_it : workload.roofline.ceiling_compute) - { - for(const auto& bandwidth_it : compute_it.second) - { - if(m_selections.ceilings_compute.count(compute_it.first) > 0 && - m_selections.ceilings_compute.at(compute_it.first) - .count(bandwidth_it.first) > 0) - { - ImGui::PushID(i++); - ImPlot::PlotLineG( - "", - [](int idx, void* user_data) -> ImPlotPoint { - const WorkloadInfo::Roofline::Line* line = - static_cast( - user_data); - ImPlotPoint point(-1.0, -1.0); - if(line) - { - if(idx == 0) - { - point.x = line->p1.x; - point.y = line->p1.y; - } - else - { - point.x = line->p2.x; - point.y = line->p2.y; - } - } - return point; - }, - (void*) &bandwidth_it.second.position, 2); - ImGui::PopID(); - } - } - } - for(const auto& bandwidth_it : workload.roofline.ceiling_bandwidth) - { - for(const auto& compute_it : bandwidth_it.second) - { - if(m_selections.ceilings_bandwidth.count(bandwidth_it.first) > 0 && - m_selections.ceilings_bandwidth.at(bandwidth_it.first) - .count(compute_it.first) > 0) - { - ImGui::PushID(i++); - ImPlot::PlotLineG( - "", - [](int idx, void* user_data) -> ImPlotPoint { - const WorkloadInfo::Roofline::Line* line = - static_cast( - user_data); - ImPlotPoint point(-1.0, -1.0); - if(line) - { - if(idx == 0) - { - point.x = line->p1.x; - point.y = line->p1.y; - } - else - { - point.x = line->p2.x; - point.y = line->p2.y; - } - } - return point; - }, - (void*) &compute_it.second.position, 2); - ImGui::PopID(); - } - } - } - ImPlot::EndPlot(); - } - int preset_idx = static_cast(m_selections.roofline_preset); - if(m_selections.init || - ImGui::Combo("Presets", &preset_idx, "FP32\0FP64\0Custom\0\0")) - { - m_selections.roofline_preset = - static_cast(preset_idx); - if(m_selections.roofline_preset == SelectionState::FP32) - { - m_selections.ceilings_compute = { - { kRPVControllerRooflineCeilingComputeMFMAFP32, - { kRPVControllerRooflineCeilingTypeBandwidthLDS } }, - { kRPVControllerRooflineCeilingComputeVALUFP32, - { kRPVControllerRooflineCeilingTypeBandwidthLDS } } - }; - m_selections.ceilings_bandwidth = { - { kRPVControllerRooflineCeilingTypeBandwidthHBM, - { kRPVControllerRooflineCeilingComputeMFMAFP32 } }, - { kRPVControllerRooflineCeilingTypeBandwidthL2, - { kRPVControllerRooflineCeilingComputeMFMAFP32 } }, - { kRPVControllerRooflineCeilingTypeBandwidthL1, - { kRPVControllerRooflineCeilingComputeMFMAFP32 } }, - { kRPVControllerRooflineCeilingTypeBandwidthLDS, - { kRPVControllerRooflineCeilingComputeMFMAFP32 } }, - }; - for(const std::pair& kernel : - workload.kernels) - { - for(const std::pair< - const rocprofvis_controller_roofline_kernel_intensity_type_t, - KernelInfo::Roofline::Intensity>& intensity : - kernel.second.roofline.intensities) - { - m_selections.intensities[kernel.second.id].insert( - intensity.second.type); - } - } - } - else if(m_selections.roofline_preset == SelectionState::FP64) - { - m_selections.ceilings_compute = { - { kRPVControllerRooflineCeilingComputeMFMAFP64, - { kRPVControllerRooflineCeilingTypeBandwidthLDS } }, - { kRPVControllerRooflineCeilingComputeVALUFP64, - { kRPVControllerRooflineCeilingTypeBandwidthLDS } } - }; - m_selections.ceilings_bandwidth = { - { kRPVControllerRooflineCeilingTypeBandwidthHBM, - { kRPVControllerRooflineCeilingComputeMFMAFP64 } }, - { kRPVControllerRooflineCeilingTypeBandwidthL2, - { kRPVControllerRooflineCeilingComputeMFMAFP64 } }, - { kRPVControllerRooflineCeilingTypeBandwidthL1, - { kRPVControllerRooflineCeilingComputeMFMAFP64 } }, - { kRPVControllerRooflineCeilingTypeBandwidthLDS, - { kRPVControllerRooflineCeilingComputeMFMAFP64 } }, - }; - for(const std::pair& kernel : - workload.kernels) - { - for(const std::pair< - const rocprofvis_controller_roofline_kernel_intensity_type_t, - KernelInfo::Roofline::Intensity>& intensity : - kernel.second.roofline.intensities) - { - m_selections.intensities[kernel.second.id].insert( - intensity.second.type); - } - } - } - } - if(m_selections.roofline_preset == SelectionState::Custom && - ImGui::BeginTable("customizer", 2, - ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | - ImGuiTableFlags_SizingStretchSame)) - { - ImGui::TableSetupColumn("Type"); - ImGui::TableSetupColumn("Element"); - ImGui::TableHeadersRow(); - for(const std::pair& kernel : workload.kernels) - { - for(const std::pair< - const rocprofvis_controller_roofline_kernel_intensity_type_t, - KernelInfo::Roofline::Intensity>& intensity : - kernel.second.roofline.intensities) - { - ImGui::PushID(i++); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Kernel Intensity"); - ImGui::SameLine(); - bool show = m_selections.intensities.count(kernel.second.id) > 0 && - m_selections.intensities.at(kernel.second.id) - .count(intensity.second.type) > 0; - if(ImGui::Selectable("", show, ImGuiSelectableFlags_SpanAllColumns)) - { - if(show) - { - m_selections.intensities.at(kernel.second.id) - .erase(intensity.second.type); - } - else - { - m_selections.intensities[kernel.second.id].insert( - intensity.second.type); - } - } - ImGui::TableNextColumn(); - ImGui::Text("ID:%u - %s", kernel.second.id, - m_display_names.intensity.at(intensity.second.type)); - ImGui::PopID(); - } - } - for(const auto& compute_it : workload.roofline.ceiling_compute) - { - for(const auto& bandwidth_it : compute_it.second) - { - ImGui::PushID(i++); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Compute Ceiling"); - ImGui::SameLine(); - bool show = - m_selections.ceilings_compute.count(compute_it.first) > 0 && - m_selections.ceilings_compute.at(compute_it.first) - .count(bandwidth_it.first) > 0; - if(ImGui::Selectable("", show, ImGuiSelectableFlags_SpanAllColumns)) - { - if(show) - { - m_selections.ceilings_compute.at(compute_it.first) - .erase(bandwidth_it.first); - } - else - { - m_selections.ceilings_compute[compute_it.first].insert( - bandwidth_it.first); - } - } - ImGui::TableNextColumn(); - ImGui::Text("%s-%s", - m_display_names.ceiling_compute.at(compute_it.first), - m_display_names.ceiling_bandwidth.at(bandwidth_it.first)); - ImGui::PopID(); - } - } - for(const auto& bandwidth_it : workload.roofline.ceiling_bandwidth) - { - for(const auto& compute_it : bandwidth_it.second) - { - ImGui::PushID(i++); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Bandwidth Ceiling"); - ImGui::SameLine(); - bool show = - m_selections.ceilings_bandwidth.count(bandwidth_it.first) > 0 && - m_selections.ceilings_bandwidth.at(bandwidth_it.first) - .count(compute_it.first) > 0; - if(ImGui::Selectable("", show, ImGuiSelectableFlags_SpanAllColumns)) - { - if(show) - { - m_selections.ceilings_bandwidth.at(bandwidth_it.first) - .erase(compute_it.first); - } - else - { - m_selections.ceilings_bandwidth[bandwidth_it.first].insert( - compute_it.first); - } - } - ImGui::TableNextColumn(); - ImGui::Text("%s-%s", - m_display_names.ceiling_bandwidth.at(bandwidth_it.first), - m_display_names.ceiling_compute.at(compute_it.first)); - ImGui::PopID(); - } - } - ImGui::EndTable(); - } - ImGui::EndChild(); - ImGui::NewLine(); - ImGui::BeginChild("value_names_lookup", ImVec2(0, 0), - ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY); - ImGui::Text("Value Names Lookup"); - ImGui::InputText("Metric ID (e.g. 3.1.2)", m_value_names_input, - sizeof(m_value_names_input)); - - const WorkloadInfo& wl = workloads.at(m_selections.workload_id); - ImGui::Text("Workload: %s (metrics: %zu, categories: %zu)", - wl.name.c_str(), - wl.available_metrics.list.size(), - wl.available_metrics.tree.size()); - - std::string input(m_value_names_input); - auto dot1 = input.find('.'); - auto dot2 = (dot1 != std::string::npos) ? input.find('.', dot1 + 1) - : std::string::npos; - if(dot1 != std::string::npos && dot2 != std::string::npos && - dot2 + 1 < input.size()) - { - uint32_t cat_id = static_cast(std::stoul(input.substr(0, dot1))); - uint32_t tbl_id = static_cast( - std::stoul(input.substr(dot1 + 1, dot2 - dot1 - 1))); - uint32_t entry_id = static_cast( - std::stoul(input.substr(dot2 + 1))); - - ImGui::Text("Looking up: cat=%u, table=%u, entry=%u", cat_id, tbl_id, entry_id); - - if(wl.available_metrics.tree.count(cat_id)) - { - const auto& cat = wl.available_metrics.tree.at(cat_id); - if(cat.tables.count(tbl_id)) - { - const auto& tbl = cat.tables.at(tbl_id); - if(tbl.entries.count(entry_id)) - { - const AvailableMetrics::Entry& entry = tbl.entries.at(entry_id); - ImGui::Text("Metric: [%u.%u.%u] %s", - entry.category_id, entry.table_id, entry.id, - entry.name.c_str()); - } - else - { - ImGui::TextColored(ImVec4(1, 0.4f, 0.4f, 1), - "Entry %u not found in table %u (table has %zu entries)", - entry_id, tbl_id, tbl.entries.size()); - } - if(tbl.value_names.empty()) - { - ImGui::TextDisabled("No value names found for table %u", tbl_id); - } - else - { - ImGui::Text("Value Names (%zu):", tbl.value_names.size()); - for(const std::string& vn : tbl.value_names) - { - ImGui::BulletText("%s", vn.c_str()); - } - } - } - else - { - ImGui::TextColored(ImVec4(1, 0.4f, 0.4f, 1), - "Table %u not found in category %u", tbl_id, cat_id); - } - } - else - { - ImGui::TextColored(ImVec4(1, 0.4f, 0.4f, 1), - "Category %u not found", cat_id); - } - } - ImGui::EndChild(); - ImGui::EndChild(); - m_selections.init = false; - } - - RenderKernelSelectionTable(); -} - -void -ComputeTester::RenderKernelSelectionTable() -{ - static std::vector metrics = { - "2.1.4:avg", "2.1.3:avg", "2.1.3:peak" - }; - - static char metric_id_buffer[256] = "2.1.4:avg"; - static bool fetch_requested = true; // force fetch on first render - - static bool sort_requested = false; - static int sort_column_index = -1; - static int sort_order = kRPVControllerSortOrderDescending; - - static const int built_in_columns_cnt = 2; // ID and Name columns that are always present in the table - - int remove_index = -1; - - if(ImGui::Button("Fetch Kernel Metric Pivot Test")) - { - fetch_requested = true; - } - - ImGui::InputText("Metric ID:", metric_id_buffer, sizeof(metric_id_buffer)); - - if(ImGui::Button("Add Metric")) - { - metrics.push_back(std::string(metric_id_buffer)); - fetch_requested = true; - } - - ImGui::Separator(); - - ComputeKernelSelectionTable& table = - m_data_provider.ComputeModel().GetKernelSelectionTable(); - const std::vector& header = table.GetTableHeader(); - const std::vector>& data = table.GetTableData(); - - if(!header.empty() && !data.empty()) - { - if(ImGui::BeginTable("kernel_selection_table", header.size(), - ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | - ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Sortable, - ImVec2(0.0f, data.empty() - ? ImGui::GetTextLineHeightWithSpacing() - : ImGui::GetTextLineHeightWithSpacing() * - (1.0f + data.size())))) - { - - for(const std::string& col_name : header) - { - ImGui::TableSetupColumn(col_name.c_str()); - } - ImGui::TableHeadersRow(); - if(data.empty()) - { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::TextDisabled("None"); - } - - // Get sort specs - ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs(); - if(sort_specs && sort_specs->SpecsDirty) - { - sort_requested = true; - sort_column_index = sort_specs->Specs->ColumnIndex; - sort_order = - (sort_specs->Specs->SortDirection == ImGuiSortDirection_Ascending) - ? kRPVControllerSortOrderAscending - : kRPVControllerSortOrderDescending; - - sort_specs->SpecsDirty = false; - } - - for(const std::vector& row : data) - { - int index = 0; - ImGui::TableNextRow(); - for(const std::string& cell : row) - { - ImGui::TableNextColumn(); - ImGui::Text(cell.c_str()); - - if(ImGui::IsItemClicked(ImGuiMouseButton_Right)) - { - remove_index = index - built_in_columns_cnt; - sort_requested = true; - spdlog::debug("Clicked cell at row {}, column {}: {} {}", - index / header.size(), index % header.size(), cell, remove_index); - } - index++; - } - } - ImGui::EndTable(); - } - } - - if(remove_index >= 0 && remove_index < static_cast(metrics.size())) - { - metrics.erase(metrics.begin() + remove_index); - } - - if(sort_requested || fetch_requested) - { - ComputeTableRequestParams params(1, metrics); - - params.m_sort_column_index = sort_column_index; - params.m_sort_order = static_cast(sort_order); - - spdlog::debug("Requesting sorted kernel selection table: column {}, order {}", - sort_column_index, sort_order == kRPVControllerSortOrderAscending ? "ASC" : "DESC"); - m_data_provider.FetchMetricPivotTable(params); - - fetch_requested = false; - sort_requested = false; - } -} } // namespace View } // namespace RocProfVis diff --git a/src/view/src/compute/rocprofvis_compute_view.h b/src/view/src/compute/rocprofvis_compute_view.h index a2d782ff..4de922dd 100644 --- a/src/view/src/compute/rocprofvis_compute_view.h +++ b/src/view/src/compute/rocprofvis_compute_view.h @@ -7,7 +7,6 @@ #include "widgets/rocprofvis_query_builder.h" #include "widgets/rocprofvis_tab_container.h" #include "rocprofvis_compute_selection.h" -#include "rocprofvis_compute_workload_view.h" namespace RocProfVis { @@ -15,7 +14,6 @@ namespace View { class SettingsManager; -class ComputeTester; class Roofline; class ComputeView : public RootView @@ -49,68 +47,5 @@ class ComputeView : public RootView std::shared_ptr m_tool_bar; }; -class ComputeTester : public RocWidget -{ -public: - ComputeTester(DataProvider& data_provider, std::shared_ptr compute_selection); - ~ComputeTester(); - - void Update(); - void Render(); - -private: - void RenderKernelSelectionTable(); - - struct SelectionState - { - enum RooflinePreset - { - FP32, - FP64, - Custom - }; - bool init; - uint32_t workload_id; - std::unordered_set kernel_ids; - std::unordered_map< - uint32_t, - std::unordered_map>>> - metric_ids; - RooflinePreset roofline_preset; - std::unordered_map< - rocprofvis_controller_roofline_ceiling_compute_type_t, - std::unordered_set> - ceilings_compute; - std::unordered_map< - rocprofvis_controller_roofline_ceiling_bandwidth_type_t, - std::unordered_set> - ceilings_bandwidth; - std::unordered_map< - uint32_t, - std::unordered_set> - intensities; - }; - struct DisplayStrings - { - std::unordered_map - ceiling_compute; - std::unordered_map - ceiling_bandwidth; - std::unordered_map - intensity; - }; - - DataProvider& m_data_provider; - std::shared_ptr m_compute_selection; - SelectionState m_selections; - DisplayStrings m_display_names; - QueryBuilder m_query_builder; - - char m_value_names_input[64] = "3.1.2"; -}; - } // namespace View } // namespace RocProfVis 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 40994424..669ccf9c 100644 --- a/src/view/src/model/compute/rocprofvis_compute_data_model.cpp +++ b/src/view/src/model/compute/rocprofvis_compute_data_model.cpp @@ -135,6 +135,35 @@ ComputeDataModel::AddMetricValue(uint64_t store_id, uint32_t workload_id, return valid; } +const AvailableMetrics::Entry* +ComputeDataModel::GetMetricInfo(uint32_t workload_id, uint32_t category_id, + uint32_t table_id, uint32_t entry_id) const +{ + if(m_workloads.count(workload_id)) + { + const WorkloadInfo& workload = m_workloads.at(workload_id); + return GetMetricInfo(workload, category_id, table_id, entry_id); + } + return nullptr; +} + +const AvailableMetrics::Entry* +ComputeDataModel::GetMetricInfo(const WorkloadInfo& workload, uint32_t category_id, uint32_t table_id, + uint32_t entry_id) +{ + if(workload.available_metrics.tree.count(category_id)) + { + const AvailableMetrics::Category& category = + workload.available_metrics.tree.at(category_id); + if(category.tables.count(table_id) && + category.tables.at(table_id).entries.count(entry_id)) + { + return &category.tables.at(table_id).entries.at(entry_id); + } + } + return nullptr; +} + void ComputeDataModel::Clear() { 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 88dceb47..9f5e00db 100644 --- a/src/view/src/model/compute/rocprofvis_compute_data_model.h +++ b/src/view/src/model/compute/rocprofvis_compute_data_model.h @@ -55,6 +55,15 @@ class ComputeDataModel std::shared_ptr GetMetricValue(uint64_t store_id, uint32_t kernel_id, uint32_t category_id, uint32_t table_id, uint32_t entry_id) const; std::shared_ptr GetMetricValue(uint64_t store_id, uint32_t kernel_id, uint64_t metric_key) const; + const AvailableMetrics::Entry* GetMetricInfo(uint32_t workload_id, + uint32_t category_id, uint32_t table_id, + uint32_t entry_id) const; + + static const AvailableMetrics::Entry* GetMetricInfo(const WorkloadInfo& workload, + uint32_t category_id, + uint32_t table_id, + uint32_t entry_id); + MetricValuesByEntryId* GetMetricValuesByTable(uint64_t store_id, uint32_t kernel_id, uint32_t category_id, uint32_t table_id); diff --git a/src/view/src/rocprofvis_data_provider.cpp b/src/view/src/rocprofvis_data_provider.cpp index 0f1278bd..8d0c1139 100644 --- a/src/view/src/rocprofvis_data_provider.cpp +++ b/src/view/src/rocprofvis_data_provider.cpp @@ -20,34 +20,32 @@ namespace View { const uint64_t DataProvider::EVENT_TABLE_REQUEST_ID = - MakeRequestId(RequestType::kFetchTrackEventTable); + RequestIdBuilder::MakeRequestId(RequestType::kFetchTrackEventTable); const uint64_t DataProvider::SAMPLE_TABLE_REQUEST_ID = - MakeRequestId(RequestType::kFetchTrackSampleTable); + RequestIdBuilder::MakeRequestId(RequestType::kFetchTrackSampleTable); const uint64_t DataProvider::EVENT_SEARCH_REQUEST_ID = - MakeRequestId(RequestType::kFetchEventSearchTable); + RequestIdBuilder::MakeRequestId(RequestType::kFetchEventSearchTable); const uint64_t DataProvider::EVENT_EXTENDED_DATA_REQUEST_ID = - MakeRequestId(RequestType::kFetchEventExtendedData); + RequestIdBuilder::MakeRequestId(RequestType::kFetchEventExtendedData); const uint64_t DataProvider::EVENT_FLOW_DATA_REQUEST_ID = - MakeRequestId(RequestType::kFetchEventFlowDetails); + RequestIdBuilder::MakeRequestId(RequestType::kFetchEventFlowDetails); const uint64_t DataProvider::EVENT_CALL_STACK_DATA_REQUEST_ID = - MakeRequestId(RequestType::kFetchEventCallStack); + RequestIdBuilder::MakeRequestId(RequestType::kFetchEventCallStack); const uint64_t DataProvider::SAVE_TRIMMED_TRACE_REQUEST_ID = - MakeRequestId(RequestType::kSaveTrimmedTrace); + RequestIdBuilder::MakeRequestId(RequestType::kSaveTrimmedTrace); const uint64_t DataProvider::TABLE_EXPORT_REQUEST_ID = - MakeRequestId(RequestType::kTableExport); + RequestIdBuilder::MakeRequestId(RequestType::kTableExport); const uint64_t DataProvider::FETCH_SYSTEM_TRACE_REQUEST_ID = - MakeRequestId(RequestType::kFetchSystemTrace); + RequestIdBuilder::MakeRequestId(RequestType::kFetchSystemTrace); const uint64_t DataProvider::SUMMARY_REQUEST_ID = - MakeRequestId(RequestType::kFetchSummary); + RequestIdBuilder::MakeRequestId(RequestType::kFetchSummary); const uint64_t DataProvider::SUMMARY_KERNEL_INSTANCE_TABLE_REQUEST_ID = - MakeRequestId(RequestType::kFetchSummaryKernelInstanceTable); + RequestIdBuilder::MakeRequestId(RequestType::kFetchSummaryKernelInstanceTable); #ifdef COMPUTE_UI_SUPPORT const uint64_t DataProvider::FETCH_COMPUTE_TRACE_REQUEST_ID = - MakeRequestId(RequestType::kFetchComputeTrace); -const uint64_t DataProvider::METRICS_REQUEST_ID = - MakeRequestId(RequestType::kFetchMetrics); + RequestIdBuilder::MakeRequestId(RequestType::kFetchComputeTrace); const uint64_t DataProvider::METRIC_PIVOT_TABLE_REQUEST_ID = - MakeRequestId(RequestType::kFetchMetricPivotTable); + RequestIdBuilder::MakeRequestId(RequestType::kFetchMetricPivotTable); #endif DataProvider::DataProvider() @@ -180,7 +178,7 @@ DataProvider::SetTrackMetadataChangedCallback( void DataProvider::SetTableDataReadyCallback( - const std::function& callback) + const std::function& callback) { m_table_data_ready_callback = callback; } @@ -1162,8 +1160,8 @@ DataProvider::FetchWholeTrack(uint32_t track_id, double start_ts, double end_ts, return false; } - uint64_t request_id = - MakeTrackDataRequestId(track_id, chunk_index, group_id, RequestType::kFetchTrack); + uint64_t request_id = RequestIdBuilder::MakeTrackDataRequestId( + track_id, chunk_index, group_id, RequestType::kFetchTrack); const TrackInfo* metadata = m_model.GetTimeline().GetTrack(track_id); if(metadata) @@ -1251,9 +1249,9 @@ DataProvider::FetchTrack(const TrackRequestParams& request_params) return { false, 0 }; } - uint64_t request_id = - MakeTrackDataRequestId(request_params.m_track_id, request_params.m_chunk_index, - request_params.m_data_group_id, RequestType::kFetchGraph); + uint64_t request_id = RequestIdBuilder::MakeTrackDataRequestId( + request_params.m_track_id, request_params.m_chunk_index, + request_params.m_data_group_id, RequestType::kFetchGraph); if(m_model.GetTimeline().GetTrack(request_params.m_track_id)) { @@ -2993,7 +2991,7 @@ DataProvider::ProcessTableRequest(RequestInfo& req) if(m_table_data_ready_callback) { - m_table_data_ready_callback(m_model.GetTraceFilePath(), req.request_id); + m_table_data_ready_callback(m_model.GetTraceFilePath(), req.request_id, req.response_code); } } @@ -3597,7 +3595,8 @@ DataProvider::FetchMetrics(const MetricsRequestParams& metrics_params) static_cast(m_state)); return false; } - auto it = m_requests.find(METRICS_REQUEST_ID); + uint64_t request_id = RequestIdBuilder::MakeClientRequestId(RequestType::kFetchMetrics, metrics_params.m_client_id); + auto it = m_requests.find(request_id); if(it == m_requests.end()) { rocprofvis_controller_future_t* future = rocprofvis_controller_future_alloc(); @@ -3648,8 +3647,8 @@ DataProvider::FetchMetrics(const MetricsRequestParams& metrics_params) if(result == kRocProfVisResultSuccess) { m_requests.emplace( - METRICS_REQUEST_ID, - RequestInfo{ METRICS_REQUEST_ID, future, nullptr, output, args, + request_id, + RequestInfo{ request_id, future, nullptr, output, args, RequestState::kLoading, RequestType::kFetchMetrics, std::make_shared(metrics_params) }); return true; @@ -4249,8 +4248,6 @@ DataProvider::ProcessMetricPivotTable(RequestInfo& req) ComputeTableInfo& kernel_pivot_table = m_compute_model.GetKernelSelectionTable().GetTableInfoMutable(); - kernel_pivot_table.table_header.clear(); - for(uint64_t col = 0; col < num_columns; col++) { // Get column name @@ -4312,6 +4309,11 @@ DataProvider::ProcessMetricPivotTable(RequestInfo& req) req.response_code); } + if(m_table_data_ready_callback) + { + m_table_data_ready_callback(m_model.GetTraceFilePath(), req.request_id, req.response_code); + } + // Free array rocprofvis_controller_array_free(array); req.request_array = nullptr; diff --git a/src/view/src/rocprofvis_data_provider.h b/src/view/src/rocprofvis_data_provider.h index db9d4ee9..b3e92cfd 100644 --- a/src/view/src/rocprofvis_data_provider.h +++ b/src/view/src/rocprofvis_data_provider.h @@ -36,27 +36,6 @@ enum class ProviderState class DataProvider { public: - static constexpr uint8_t TRACK_CHUNK_OFFSET_BITS = sizeof(uint32_t) * 8; - static constexpr uint8_t TRACK_GROUP_OFFSET_BITS = - sizeof(uint16_t) * 8 + TRACK_CHUNK_OFFSET_BITS; - static constexpr uint8_t REQUEST_TYPE_OFFSET_BITS = - sizeof(uint8_t) * 8 + TRACK_GROUP_OFFSET_BITS; - - static uint64_t MakeTrackDataRequestId(uint32_t track_id, uint16_t chunk_index, - uint8_t group_id, RequestType request_type) - { - return (static_cast(request_type) << REQUEST_TYPE_OFFSET_BITS) | - (static_cast(group_id) << TRACK_GROUP_OFFSET_BITS) | - (static_cast(chunk_index) << TRACK_CHUNK_OFFSET_BITS) | - (static_cast(track_id)); - } - - static uint64_t MakeRequestId(RequestType request_type) - { - return (static_cast(request_type) << REQUEST_TYPE_OFFSET_BITS) | - static_cast(0); - } - static const uint64_t EVENT_TABLE_REQUEST_ID; static const uint64_t SAMPLE_TABLE_REQUEST_ID; static const uint64_t EVENT_SEARCH_REQUEST_ID; @@ -70,7 +49,6 @@ class DataProvider static const uint64_t SUMMARY_KERNEL_INSTANCE_TABLE_REQUEST_ID; #ifdef COMPUTE_UI_SUPPORT static const uint64_t FETCH_COMPUTE_TRACE_REQUEST_ID; - static const uint64_t METRICS_REQUEST_ID; static const uint64_t METRIC_PIVOT_TABLE_REQUEST_ID; #endif @@ -209,7 +187,7 @@ class DataProvider void SetTrackMetadataChangedCallback( const std::function& callback); void SetTableDataReadyCallback( - const std::function& callback); + const std::function& callback); void SetTrackDataReadyCallback( const std::function& callback); @@ -306,7 +284,7 @@ class DataProvider // Called when track metadata has changed std::function m_track_metadata_changed_callback; // Called when table data has changed - std::function m_table_data_ready_callback; + std::function m_table_data_ready_callback; // Called when new track data is ready std::function m_track_data_ready_callback; diff --git a/src/view/src/rocprofvis_events.cpp b/src/view/src/rocprofvis_events.cpp index b3132738..140ba972 100644 --- a/src/view/src/rocprofvis_events.cpp +++ b/src/view/src/rocprofvis_events.cpp @@ -114,9 +114,10 @@ TrackDataEvent::GetResponseCode() const return m_response_code; } -TableDataEvent::TableDataEvent(const std::string& source_id, uint64_t request_id) +TableDataEvent::TableDataEvent(const std::string& source_id, uint64_t request_id, uint64_t response_code) : RocEvent(static_cast(RocEvents::kNewTableData), source_id) , m_request_id(request_id) +, m_response_code(response_code) { m_event_type = RocEventType::kTableDataEvent; } @@ -127,6 +128,12 @@ TableDataEvent::GetRequestID() const return m_request_id; } +uint64_t +TableDataEvent::GetResponseCode() const +{ + return m_response_code; +} + #ifdef COMPUTE_UI_SUPPORT ComputeTableSearchEvent::ComputeTableSearchEvent(int event_id, std::string& term) : RocEvent(event_id) diff --git a/src/view/src/rocprofvis_events.h b/src/view/src/rocprofvis_events.h index 833046ef..cc4bf675 100644 --- a/src/view/src/rocprofvis_events.h +++ b/src/view/src/rocprofvis_events.h @@ -164,11 +164,13 @@ class TrackDataEvent : public RocEvent class TableDataEvent : public RocEvent { public: - TableDataEvent(const std::string& source_id, uint64_t request_id); + TableDataEvent(const std::string& source_id, uint64_t request_id, uint64_t response_code); uint64_t GetRequestID() const; + uint64_t GetResponseCode() const; private: uint64_t m_request_id; + uint64_t m_response_code; }; class StickyNoteEvent : public RocEvent diff --git a/src/view/src/rocprofvis_events_view.cpp b/src/view/src/rocprofvis_events_view.cpp index 51f5471b..7d0f400d 100644 --- a/src/view/src/rocprofvis_events_view.cpp +++ b/src/view/src/rocprofvis_events_view.cpp @@ -437,20 +437,7 @@ EventsView::RenderArgumentData(const EventInfo* event_data) bool EventsView::XButton() { - bool clicked = false; - ImGui::PushStyleColor(ImGuiCol_Button, m_settings.GetColor(Colors::kTransparent)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, - m_settings.GetColor(Colors::kTransparent)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, - m_settings.GetColor(Colors::kTransparent)); - ImGui::PushStyleVarX(ImGuiStyleVar_FramePadding, 0); - ImGui::PushFont(m_settings.GetFontManager().GetIconFont(FontType::kDefault)); - clicked = ImGui::SmallButton(ICON_X_CIRCLED); - ImGui::PopFont(); - ImGui::PopStyleVar(); - ImGui::PopStyleColor(3); - if(ImGui::IsItemHovered()) - SetTooltipStyled("Unselect Event"); + bool clicked = RocProfVis::View::XButton(nullptr, "Unselect Event", &m_settings); return clicked; } diff --git a/src/view/src/rocprofvis_multi_track_table.cpp b/src/view/src/rocprofvis_multi_track_table.cpp index 7eb75cb5..86712ea7 100644 --- a/src/view/src/rocprofvis_multi_track_table.cpp +++ b/src/view/src/rocprofvis_multi_track_table.cpp @@ -388,22 +388,7 @@ MultiTrackTable::RowSelected(const ImGuiMouseButton mouse_button) bool MultiTrackTable::XButton(const char* id) const { - bool clicked = false; - ImGui::PushStyleColor(ImGuiCol_Button, m_settings.GetColor(Colors::kTransparent)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, - m_settings.GetColor(Colors::kTransparent)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, - m_settings.GetColor(Colors::kTransparent)); - ImGui::PushStyleVarX(ImGuiStyleVar_FramePadding, 0); - ImGui::PushFont(m_settings.GetFontManager().GetIconFont(FontType::kDefault)); - ImGui::PushID(id); - clicked = ImGui::SmallButton(ICON_X_CIRCLED); - ImGui::PopID(); - ImGui::PopFont(); - ImGui::PopStyleVar(); - ImGui::PopStyleColor(3); - if(ImGui::IsItemHovered()) - SetTooltipStyled("Clear"); + bool clicked = RocProfVis::View::XButton(id, "Clear", &m_settings); return clicked; } diff --git a/src/view/src/rocprofvis_requests.h b/src/view/src/rocprofvis_requests.h index 9baccfbe..1b6dfbfe 100644 --- a/src/view/src/rocprofvis_requests.h +++ b/src/view/src/rocprofvis_requests.h @@ -12,32 +12,13 @@ #include "rocprofvis_controller_enums.h" #include "rocprofvis_controller_types.h" #include "rocprofvis_c_interface_types.h" +#include "rocprofvis_core_assert.h" namespace RocProfVis { namespace View { -// Singleton class for creating unique IDs -class IdGenerator -{ -public: - static IdGenerator& GetInstance() - { - static IdGenerator instance; - return instance; - } - - uint64_t GenerateId() - { - return ++m_current_id; - } - -private: - IdGenerator() : m_current_id(0) {} - uint64_t m_current_id; -}; - enum class RequestType { kFetchTrack, @@ -68,6 +49,69 @@ enum class RequestState kError }; + +// Helper class for constructing request IDs with packed fields +class RequestIdBuilder +{ +public: + static constexpr uint8_t TRACK_CHUNK_OFFSET_BITS = sizeof(uint32_t) * 8; + static constexpr uint8_t TRACK_GROUP_OFFSET_BITS = + sizeof(uint16_t) * 8 + TRACK_CHUNK_OFFSET_BITS; + static constexpr uint8_t REQUEST_TYPE_OFFSET_BITS = + sizeof(uint8_t) * 8 + TRACK_GROUP_OFFSET_BITS; + + static uint64_t MakeTrackDataRequestId(uint32_t track_id, uint16_t chunk_index, + uint8_t group_id, RequestType request_type) + { + return (static_cast(request_type) << REQUEST_TYPE_OFFSET_BITS) | + (static_cast(group_id) << TRACK_GROUP_OFFSET_BITS) | + (static_cast(chunk_index) << TRACK_CHUNK_OFFSET_BITS) | + (static_cast(track_id)); + } + + static uint64_t MakeRequestId(RequestType request_type) + { + return (static_cast(request_type) << REQUEST_TYPE_OFFSET_BITS) | + static_cast(0); + } + + static uint64_t MakeClientRequestId(RequestType request_type, uint64_t client_id) + { + ROCPROFVIS_ASSERT(client_id < (1ULL << REQUEST_TYPE_OFFSET_BITS)); + return (static_cast(request_type) << REQUEST_TYPE_OFFSET_BITS) | + (static_cast(client_id) & ((1ULL << REQUEST_TYPE_OFFSET_BITS) - 1)); + } +}; + +// Singleton class for creating unique IDs +class IdGenerator +{ +public: + static IdGenerator& GetInstance() + { + static IdGenerator instance; + return instance; + } + + uint64_t GenerateId() + { + uint64_t id = m_current_id; + m_current_id++; + if(m_current_id > (1ULL << RequestIdBuilder::REQUEST_TYPE_OFFSET_BITS) - 1) + { + // Wrap around if we exceed the maximum client ID that can be encoded in the + // request ID + m_current_id = 0; + } + return id; + } + +private: + IdGenerator() : m_current_id(0) {} + uint64_t m_current_id; +}; + + class RequestParamsBase { public: diff --git a/src/view/src/rocprofvis_trace_view.cpp b/src/view/src/rocprofvis_trace_view.cpp index da6aea3d..ab916832 100644 --- a/src/view/src/rocprofvis_trace_view.cpp +++ b/src/view/src/rocprofvis_trace_view.cpp @@ -91,9 +91,9 @@ TraceView::TraceView() }); m_data_provider.SetTableDataReadyCallback( - [](const std::string& trace_path, uint64_t request_id) { + [](const std::string& trace_path, uint64_t request_id, uint64_t response_code) { EventManager::GetInstance()->AddEvent( - std::make_shared(trace_path, request_id)); + std::make_shared(trace_path, request_id, response_code)); }); m_data_provider.SetTraceLoadedCallback( diff --git a/src/view/src/widgets/rocprofvis_gui_helpers.cpp b/src/view/src/widgets/rocprofvis_gui_helpers.cpp index 4382de41..2aeff40e 100644 --- a/src/view/src/widgets/rocprofvis_gui_helpers.cpp +++ b/src/view/src/widgets/rocprofvis_gui_helpers.cpp @@ -295,6 +295,43 @@ CenterNextTextItem(const char* text) ImGui::SetCursorPos(pos); } +bool +XButton(const char* id, const char * tool_tip_label, SettingsManager* settings) +{ + bool clicked = false; + + if(!settings) + { + settings = &SettingsManager::GetInstance(); + } + + ImGui::PushStyleColor(ImGuiCol_Button, settings->GetColor(Colors::kTransparent)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, + settings->GetColor(Colors::kTransparent)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, + settings->GetColor(Colors::kTransparent)); + ImGui::PushStyleVarX(ImGuiStyleVar_FramePadding, 0); + ImGui::PushFont(settings->GetFontManager().GetIconFont(FontType::kDefault)); + if(id && strlen(id) > 0) + { + ImGui::PushID(id); + } + + clicked = ImGui::SmallButton(ICON_X_CIRCLED); + + if(id && strlen(id) > 0) + { + ImGui::PopID(); + } + + ImGui::PopFont(); + ImGui::PopStyleVar(); + ImGui::PopStyleColor(3); + if(tool_tip_label && ImGui::IsItemHovered()) + SetTooltipStyled(tool_tip_label); + return clicked; +} + #ifdef ROCPROFVIS_ENABLE_INTERNAL_BANNER void diff --git a/src/view/src/widgets/rocprofvis_gui_helpers.h b/src/view/src/widgets/rocprofvis_gui_helpers.h index c1d81345..05185e68 100644 --- a/src/view/src/widgets/rocprofvis_gui_helpers.h +++ b/src/view/src/widgets/rocprofvis_gui_helpers.h @@ -10,6 +10,8 @@ namespace RocProfVis namespace View { +class SettingsManager; + constexpr float PI = 3.14159265358979323846f; // Define PI constant void @@ -58,6 +60,10 @@ ElidedText(const char* text, float available_width, float tooltip_width = 0.0f, void CenterNextTextItem(const char* text); +bool +XButton(const char* id = nullptr, const char* tool_tip_label = nullptr, + SettingsManager* settings = nullptr); + #ifdef ROCPROFVIS_ENABLE_INTERNAL_BANNER void DrawInternalBuildBanner(const char* text = "Internal Build"); diff --git a/src/view/src/widgets/rocprofvis_query_builder.cpp b/src/view/src/widgets/rocprofvis_query_builder.cpp index 8e55d6b9..b6f22eb6 100644 --- a/src/view/src/widgets/rocprofvis_query_builder.cpp +++ b/src/view/src/widgets/rocprofvis_query_builder.cpp @@ -4,6 +4,7 @@ #include "rocprofvis_query_builder.h" #include "imgui.h" #include "rocprofvis_settings_manager.h" +#include "model/compute/rocprofvis_compute_data_model.h" namespace RocProfVis { @@ -29,8 +30,11 @@ QueryBuilder::SetWorkload(const WorkloadInfo* workload) } void -QueryBuilder::Open() +QueryBuilder::Show(std::function on_confirm_callback, + std::function on_cancel_callback) { + m_on_confirm = on_confirm_callback; + m_on_cancel = on_cancel_callback; m_should_open = true; } @@ -104,11 +108,18 @@ QueryBuilder::Render() (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.x) * 0.5f; bool query_complete = !m_value_name.empty(); if(!query_complete) ImGui::BeginDisabled(); - if(ImGui::Button("Add", ImVec2(button_width, 0))) ImGui::CloseCurrentPopup(); + if(ImGui::Button("Add", ImVec2(button_width, 0))) + { + if(m_on_confirm) + m_on_confirm(GetQueryString()); + ImGui::CloseCurrentPopup(); + } if(!query_complete) ImGui::EndDisabled(); ImGui::SameLine(); if(ImGui::Button("Cancel", ImVec2(button_width, 0))) { + if(m_on_cancel) + m_on_cancel(); ClearFrom(LEVEL_CATEGORY); ImGui::CloseCurrentPopup(); } @@ -119,8 +130,7 @@ QueryBuilder::Render() void QueryBuilder::RenderTags() { - SettingsManager& settings = SettingsManager::GetInstance(); - int clear = -1; + int clear = -1; ImGui::BeginChild("##tags", ImVec2(-1, ImGui::GetFrameHeightWithSpacing()), ImGuiChildFlags_FrameStyle, ImGuiWindowFlags_HorizontalScrollbar); @@ -131,16 +141,8 @@ QueryBuilder::RenderTags() if(clear >= 0 || i > 0) ImGui::SameLine(); ImGui::PushID(i); - ImGui::PushStyleColor(ImGuiCol_Button, settings.GetColor(Colors::kAccentRed)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, - settings.GetColor(Colors::kAccentRedHover)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, - settings.GetColor(Colors::kAccentRedActive)); - std::string tag = m_selections[i]->label + " X"; if(ImGui::SmallButton(tag.c_str())) clear = i; - - ImGui::PopStyleColor(3); ImGui::PopID(); } @@ -260,9 +262,35 @@ QueryBuilder::GetQueryString() const if(m_selections[LEVEL_ENTRY]) result += "." + std::to_string(m_selections[LEVEL_ENTRY]->id); if(!m_value_name.empty()) - result += ": " + m_value_name; + result += ":" + m_value_name; return result; } +std::string +QueryBuilder::GetMetricName() const +{ + if(m_selections[LEVEL_ENTRY]) return m_selections[LEVEL_ENTRY]->label; + return ""; +} + +std::string +QueryBuilder::GetValueName() const +{ + return m_value_name; +} + +const AvailableMetrics::Entry* +QueryBuilder::GetSelectedMetricInfo() const +{ + if(m_workload && m_selections[LEVEL_ENTRY] && m_selections[LEVEL_TABLE] && + m_selections[LEVEL_CATEGORY]) + { + return ComputeDataModel::GetMetricInfo( + *m_workload, m_selections[LEVEL_CATEGORY]->id, m_selections[LEVEL_TABLE]->id, + m_selections[LEVEL_ENTRY]->id); + } + return nullptr; +} + } // namespace View } // namespace RocProfVis diff --git a/src/view/src/widgets/rocprofvis_query_builder.h b/src/view/src/widgets/rocprofvis_query_builder.h index 0b80d3d5..6503cc56 100644 --- a/src/view/src/widgets/rocprofvis_query_builder.h +++ b/src/view/src/widgets/rocprofvis_query_builder.h @@ -8,6 +8,7 @@ #include #include #include +#include namespace RocProfVis @@ -21,11 +22,16 @@ class QueryBuilder : public RocWidget QueryBuilder(); void Render() override; - void Open(); + void Show(std::function on_confirm_callback, + std::function on_cancel_callback = nullptr); void SetWorkload(const WorkloadInfo* workload); std::string GetQueryString() const; + std::string GetMetricName() const; + std::string GetValueName() const; + + const AvailableMetrics::Entry* GetSelectedMetricInfo() const; private: static constexpr int LEVEL_CATEGORY = 0; @@ -54,6 +60,8 @@ class QueryBuilder : public RocWidget bool m_scroll_to_end = false; std::string m_value_name; std::vector> m_selections; + std::function m_on_confirm; + std::function m_on_cancel; }; } // namespace View