From 7f758d447a4f273ce395a2e4c03a68fee0f53a0b Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Thu, 16 Nov 2023 11:53:27 +0100 Subject: [PATCH] DPL GUI: add GUI to list devices preventing quitting --- Framework/Core/include/Framework/DebugGUI.h | 4 +- Framework/Core/src/runDataProcessing.cxx | 6 +- .../GUISupport/src/FrameworkGUIDebugger.cxx | 110 ++++++++++++------ .../GUISupport/src/FrameworkGUIDebugger.h | 4 +- Framework/GUISupport/src/Plugin.cxx | 5 +- 5 files changed, 87 insertions(+), 42 deletions(-) diff --git a/Framework/Core/include/Framework/DebugGUI.h b/Framework/Core/include/Framework/DebugGUI.h index c7a611d50a1d4..109fd36e27511 100644 --- a/Framework/Core/include/Framework/DebugGUI.h +++ b/Framework/Core/include/Framework/DebugGUI.h @@ -26,6 +26,7 @@ namespace o2::framework { struct ServiceRegistry; +struct GuiCallbackContext; /// Plugin interface for DPL GUIs. struct DebugGUI { virtual std::function getGUIDebugger(std::vector const& infos, @@ -35,7 +36,8 @@ struct DebugGUI { std::vector const& metricsInfos, o2::framework::DriverInfo const& driverInfo, std::vector& controls, - o2::framework::DriverControl& driverControl) = 0; + o2::framework::DriverControl& driverControl, + GuiCallbackContext& context) = 0; virtual void updateMousePos(float x, float y) = 0; virtual void updateMouseButton(bool isClicked) = 0; virtual void updateMouseWheel(int direction) = 0; diff --git a/Framework/Core/src/runDataProcessing.cxx b/Framework/Core/src/runDataProcessing.cxx index dbd626c32e568..f31629d90416b 100644 --- a/Framework/Core/src/runDataProcessing.cxx +++ b/Framework/Core/src/runDataProcessing.cxx @@ -1302,7 +1302,8 @@ int runStateMachine(DataProcessorSpecs const& workflow, DebugGUI* debugGUI = nullptr; void* window = nullptr; - decltype(debugGUI->getGUIDebugger(infos, runningWorkflow.devices, allStates, dataProcessorInfos, metricsInfos, driverInfo, controls, driverControl)) debugGUICallback; + GuiCallbackContext guiContext; + decltype(debugGUI->getGUIDebugger(infos, runningWorkflow.devices, allStates, dataProcessorInfos, metricsInfos, driverInfo, controls, driverControl, guiContext)) debugGUICallback; // An empty frameworkId means this is the driver, so we initialise the GUI auto initDebugGUI = []() -> DebugGUI* { @@ -1389,7 +1390,6 @@ int runStateMachine(DataProcessorSpecs const& workflow, ServiceRegistryRef ref{serviceRegistry}; ref.registerService(ServiceRegistryHelpers::handleForService(devicesManager)); - GuiCallbackContext guiContext; guiContext.plugin = debugGUI; guiContext.frameLast = uv_hrtime(); guiContext.frameLatency = &driverInfo.frameLatency; @@ -1882,7 +1882,7 @@ int runStateMachine(DataProcessorSpecs const& workflow, uv_timer_stop(gui_timer); } - auto callback = debugGUI->getGUIDebugger(infos, runningWorkflow.devices, allStates, dataProcessorInfos, metricsInfos, driverInfo, controls, driverControl); + auto callback = debugGUI->getGUIDebugger(infos, runningWorkflow.devices, allStates, dataProcessorInfos, metricsInfos, driverInfo, controls, driverControl, guiContext); guiContext.callback = [&serviceRegistry, &driverServices, &debugGUI, &infos, &runningWorkflow, &dataProcessorInfos, &metricsInfos, &driverInfo, &controls, &driverControl, callback]() { callback(); for (auto& service : driverServices) { diff --git a/Framework/GUISupport/src/FrameworkGUIDebugger.cxx b/Framework/GUISupport/src/FrameworkGUIDebugger.cxx index 35e0bc563a22e..375afef1007f9 100644 --- a/Framework/GUISupport/src/FrameworkGUIDebugger.cxx +++ b/Framework/GUISupport/src/FrameworkGUIDebugger.cxx @@ -16,6 +16,7 @@ #include "DebugGUI/imgui_extras.h" #include "Framework/DriverControl.h" #include "Framework/DriverInfo.h" +#include "Framework/GuiCallbackContext.h" #include "Framework/DeviceMetricsHelper.h" #include "Framework/DeviceMetricsInfo.h" #include "FrameworkGUIDeviceInspector.h" @@ -506,7 +507,7 @@ void displayDeviceMetrics(const char* label, case MetricsDisplayStyle::Lines: { auto xAxisFlags = ImPlotAxisFlags_None; auto yAxisFlags = ImPlotAxisFlags_LockMin; - //ImPlot::FitNextPlotAxes(true, true, true, true); + // ImPlot::FitNextPlotAxes(true, true, true, true); if (ImPlot::BeginPlot("##Some plot", {-1, -1}, axisFlags)) { ImPlot::SetupAxes("time", "value", xAxisFlags, yAxisFlags); ImPlot::SetupAxisFormat(ImAxis_Y1, formatSI, nullptr); @@ -1008,6 +1009,71 @@ void popWindowColorDueToStatus() ImGui::PopStyleVar(1); } +int debugPID(int pid) +{ + std::string pidStr = std::to_string(pid); + setenv("O2DEBUGGEDPID", pidStr.c_str(), 1); +#ifdef __APPLE__ + std::string defaultAppleDebugCommand = + "osascript -e 'tell application \"Terminal\"'" + " -e 'activate'" + " -e 'do script \"lldb -p \" & (system attribute \"O2DEBUGGEDPID\") & \"; exit\"'" + " -e 'end tell'"; + setenv("O2DPLDEBUG", defaultAppleDebugCommand.c_str(), 0); +#else + setenv("O2DPLDEBUG", "xterm -hold -e gdb attach $O2DEBUGGEDPID &", 0); +#endif + return system(getenv("O2DPLDEBUG")); +} + +int profilePID(int pid) +{ + std::string pidStr = std::to_string(pid); + setenv("O2PROFILEDPID", pidStr.c_str(), 1); +#ifdef __APPLE__ + auto defaultAppleProfileCommand = fmt::format( + "osascript -e 'tell application \"Terminal\"'" + " -e 'activate'" + " -e 'do script \"xcrun xctrace record --output dpl-profile-{0}.trace" + " --instrument os_signpost --time-limit 30s --template Time\\\\ Profiler --attach {0} " + " && open dpl-profile-{0}.trace && exit\"'" + " -e 'end tell'", + pid); + std::cout << defaultAppleProfileCommand << std::endl; + setenv("O2DPLPROFILE", defaultAppleProfileCommand.c_str(), 0); +#else + setenv("O2DPLPROFILE", "xterm -hold -e perf record -a -g -p $O2PROFILEDPID > perf-$O2PROFILEDPID.data &", 0); +#endif + return system(getenv("O2DPLPROFILE")); +} + +/// Show a window with the list of devices which have not yet exited +/// and provide a few controls to interact with them. +void displayShutdownDialog(std::vector const& specs, std::vector const& infos) +{ + for (size_t i = 0; i < infos.size(); ++i) { + auto& info = infos[i]; + if (info.active == false) { + continue; + } + auto& spec = specs[i]; + ImGui::Text("Unable to quit due to the following devices:"); + ImGui::Text("%s (%d).", spec.name.c_str(), info.pid); + ImGui::SameLine(); + if (ImGui::Button("Force quit")) { + kill(info.pid, SIGKILL); + } + ImGui::SameLine(); + if (ImGui::Button("Debug")) { + debugPID(info.pid); + } + ImGui::SameLine(); + if (ImGui::Button("Profile")) { + profilePID(info.pid); + } + } +} + /// Display information window about the driver /// and its state. void displayDriverInfo(DriverInfo const& driverInfo, DriverControl& driverControl) @@ -1035,42 +1101,12 @@ void displayDriverInfo(DriverInfo const& driverInfo, DriverControl& driverContro } ImGui::SameLine(); if (ImGui::Button("Debug driver")) { - std::string pidStr = std::to_string(pid); - setenv("O2DEBUGGEDPID", pidStr.c_str(), 1); -#ifdef __APPLE__ - std::string defaultAppleDebugCommand = - "osascript -e 'tell application \"Terminal\"'" - " -e 'activate'" - " -e 'do script \"lldb -p \" & (system attribute \"O2DEBUGGEDPID\") & \"; exit\"'" - " -e 'end tell'"; - setenv("O2DPLDEBUG", defaultAppleDebugCommand.c_str(), 0); -#else - setenv("O2DPLDEBUG", "xterm -hold -e gdb attach $O2DEBUGGEDPID &", 0); -#endif - int retVal = system(getenv("O2DPLDEBUG")); - (void)retVal; + debugPID(pid); } ImGui::SameLine(); if (ImGui::Button("Profile")) { - std::string pidStr = std::to_string(pid); - setenv("O2PROFILEDPID", pidStr.c_str(), 1); -#ifdef __APPLE__ - auto defaultAppleProfileCommand = fmt::format( - "osascript -e 'tell application \"Terminal\"'" - " -e 'activate'" - " -e 'do script \"xcrun xctrace record --output dpl-profile-{0}.trace" - " --instrument os_signpost --time-limit 30s --template Time\\\\ Profiler --attach {0} " - " && open dpl-profile-{0}.trace && exit\"'" - " -e 'end tell'", - pid); - std::cout << defaultAppleProfileCommand << std::endl; - setenv("O2DPLPROFILE", defaultAppleProfileCommand.c_str(), 0); -#else - setenv("O2DPLPROFILE", "xterm -hold -e perf record -a -g -p $O2PROFILEDPID > perf-$O2PROFILEDPID.data &", 0); -#endif - int retVal = system(getenv("O2DPLPROFILE")); - (void)retVal; + profilePID(pid); } // FIXME: this should really be a combo box @@ -1110,7 +1146,8 @@ std::function getGUIDebugger(std::vector const& infos, std::vector const& metricsInfos, DriverInfo const& driverInfo, std::vector& controls, - DriverControl& driverControl) + DriverControl& driverControl, + GuiCallbackContext& gui) { static gui::WorkspaceGUIState globalGUIState; gui::WorkspaceGUIState& guiState = globalGUIState; @@ -1141,7 +1178,7 @@ std::function getGUIDebugger(std::vector const& infos, std::vector driverNodesInfos; driverNodesInfos.push_back(TopologyNodeInfo{"driver"}); - return [&infos, &devices, &allStates, &metadata, &controls, &metricsInfos, &driverInfo, &driverControl, deviceNodesInfos, driverNodesInfos]() { + return [&infos, &devices, &allStates, &metadata, &controls, &metricsInfos, &driverInfo, &driverControl, &gui, deviceNodesInfos, driverNodesInfos]() { ImGuiStyle& style = ImGui::GetStyle(); style.FrameRounding = 0.; style.WindowRounding = 0.; @@ -1158,6 +1195,9 @@ std::function getGUIDebugger(std::vector const& infos, metricsStore.specs[DRIVER_METRICS] = gsl::span(driverNodesInfos); displayMetrics(guiState, driverInfo, infos, metadata, controls, metricsStore); displayDriverInfo(driverInfo, driverControl); + if (*(gui.guiQuitRequested) && !*(gui.allChildrenGone)) { + displayShutdownDialog(devices, infos); + } int windowPosStepping = (ImGui::GetIO().DisplaySize.y - 500) / guiState.devices.size(); diff --git a/Framework/GUISupport/src/FrameworkGUIDebugger.h b/Framework/GUISupport/src/FrameworkGUIDebugger.h index 5de5e350ddf8d..98bb50b07fd44 100644 --- a/Framework/GUISupport/src/FrameworkGUIDebugger.h +++ b/Framework/GUISupport/src/FrameworkGUIDebugger.h @@ -26,6 +26,7 @@ namespace o2::framework class DriverInfo; class DriverControl; +class GuiCallbackContext; namespace gui { @@ -37,7 +38,8 @@ std::function getGUIDebugger(std::vector const& infos, std::vector const& metricsInfos, DriverInfo const& driverInfo, std::vector& controls, - DriverControl& driverControl); + DriverControl& driverControl, + GuiCallbackContext& context); void updateMousePos(float x, float y); void updateMouseButton(bool clicked); diff --git a/Framework/GUISupport/src/Plugin.cxx b/Framework/GUISupport/src/Plugin.cxx index 7a356f6e55d9b..022b74174f632 100644 --- a/Framework/GUISupport/src/Plugin.cxx +++ b/Framework/GUISupport/src/Plugin.cxx @@ -36,9 +36,10 @@ struct ImGUIDebugGUI : o2::framework::DebugGUI { std::vector const& metricsInfos, DriverInfo const& driverInfo, std::vector& controls, - DriverControl& driverControl) override + DriverControl& driverControl, + GuiCallbackContext& context) override { - return o2::framework::gui::getGUIDebugger(infos, devices, allStates, metadata, metricsInfos, driverInfo, controls, driverControl); + return o2::framework::gui::getGUIDebugger(infos, devices, allStates, metadata, metricsInfos, driverInfo, controls, driverControl, context); } void updateMousePos(float x, float y) override