mirror of
https://github.com/FairRootGroup/FairMQ.git
synced 2025-10-13 08:41:16 +00:00
feat(top): Add new fairmq-top tool
This commit is contained in:
parent
bc91799e56
commit
cb2eca9c4a
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -4,3 +4,4 @@ install
|
|||
.vscode
|
||||
/compile_commands.json
|
||||
.cache
|
||||
imgui.ini
|
||||
|
|
|
@ -47,6 +47,8 @@ fairmq_build_option(USE_EXTERNAL_GTEST "Do not use bundled GTest. Not recommend
|
|||
DEFAULT OFF)
|
||||
fairmq_build_option(FAIRMQ_DEBUG_MODE "Compile in debug mode (may decrease performance)."
|
||||
DEFAULT OFF)
|
||||
fairmq_build_option(BUILD_SDK_TOP_TOOL "Build the fairmq-top tool."
|
||||
DEFAULT OFF REQUIRES "BUILD_SDK")
|
||||
################################################################################
|
||||
|
||||
|
||||
|
@ -116,6 +118,9 @@ endif()
|
|||
if(BUILD_TIDY_TOOL)
|
||||
list(APPEND PROJECT_PACKAGE_COMPONENTS tidy_tool)
|
||||
endif()
|
||||
if(BUILD_SDK_TOP_TOOL)
|
||||
list(APPEND PROJECT_PACKAGE_COMPONENTS sdk_top_tool)
|
||||
endif()
|
||||
################################################################################
|
||||
|
||||
|
||||
|
|
|
@ -77,9 +77,16 @@ if(BUILD_TIDY_TOOL)
|
|||
find_package2(PRIVATE LLVM REQUIRED)
|
||||
find_package2(PRIVATE Clang REQUIRED)
|
||||
set(Clang_VERSION ${LLVM_VERSION})
|
||||
endif()
|
||||
|
||||
if(BUILD_TIDY_TOOL OR BUILD_SDK_TOP_TOOL)
|
||||
find_package2(PRIVATE CLI11 REQUIRED)
|
||||
endif()
|
||||
|
||||
if(BUILD_SDK_TOP_TOOL)
|
||||
find_package2(PRIVATE imtui REQUIRED)
|
||||
endif()
|
||||
|
||||
find_package2_implicit_dependencies() # Always call last after latest find_package2
|
||||
|
||||
if(PROJECT_PACKAGE_DEPENDENCIES)
|
||||
|
|
|
@ -106,7 +106,9 @@ if(ENABLE_SANITIZER_MEMORY AND CMAKE_CXX_COMPILER_ID MATCHES ".*Clang")
|
|||
endif()
|
||||
|
||||
list(JOIN _sanitizers "," _sanitizers)
|
||||
if(_sanitizers)
|
||||
set(_sanitizers "-fsanitize=${_sanitizers}")
|
||||
endif()
|
||||
|
||||
# Configure build types
|
||||
set(CMAKE_CONFIGURATION_TYPES "Debug" "Release" "RelWithDebInfo")
|
||||
|
|
|
@ -70,11 +70,17 @@ macro(fairmq_summary_components)
|
|||
endif()
|
||||
message(STATUS " ${BWhite}sdk_commands${CR} ${sdk_commands_summary}")
|
||||
if(BUILD_TIDY_TOOL)
|
||||
set(sdk_tidy_summary "${BGreen}YES${CR} (disable with ${BMagenta}-DBUILD_TIDY_TOOL=OFF${CR})")
|
||||
set(tidy_summary "${BGreen}YES${CR} (disable with ${BMagenta}-DBUILD_TIDY_TOOL=OFF${CR})")
|
||||
else()
|
||||
set(sdk_tidy_summary "${BRed} NO${CR} (default, enable with ${BMagenta}-DBUILD_TIDY_TOOL=ON${CR})")
|
||||
set(tidy_summary "${BRed} NO${CR} (default, enable with ${BMagenta}-DBUILD_TIDY_TOOL=ON${CR})")
|
||||
endif()
|
||||
message(STATUS " ${BWhite}tidy_tool${CR} ${sdk_tidy_summary}")
|
||||
message(STATUS " ${BWhite}tidy_tool${CR} ${tidy_summary}")
|
||||
if(BUILD_SDK_TOP_TOOL)
|
||||
set(sdk_top_summary "${BGreen}YES${CR} EXPERIMENTAL (disable with ${BMagenta}-DBUILD_SDK_TOP_TOOL=OFF${CR})")
|
||||
else()
|
||||
set(sdk_top_summary "${BRed} NO${CR} EXPERIMENTAL (default, enable with ${BMagenta}-DBUILD_SDK_TOP_TOOL=ON${CR})")
|
||||
endif()
|
||||
message(STATUS " ${BWhite}sdk_top_tool${CR} ${sdk_top_summary}")
|
||||
endmacro()
|
||||
|
||||
macro(fairmq_summary_static_analysis)
|
||||
|
|
58
cmake/Findimtui.cmake
Normal file
58
cmake/Findimtui.cmake
Normal file
|
@ -0,0 +1,58 @@
|
|||
################################################################################
|
||||
# Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
set(pkg imtui)
|
||||
find_path(${pkg}_INCLUDE_DIR
|
||||
NAMES ${pkg}.h
|
||||
PATH_SUFFIXES include/${pkg}
|
||||
DOC "imtui include directory"
|
||||
)
|
||||
get_filename_component(${pkg}_INCLUDE_DIR "${${pkg}_INCLUDE_DIR}/.." ABSOLUTE)
|
||||
|
||||
find_library(${pkg}_LIBRARY
|
||||
NAMES lib${pkg}.so
|
||||
PATH_SUFFIXES lib lib64
|
||||
DOC "Path to libimtui.a"
|
||||
)
|
||||
|
||||
find_library(${pkg}_ncurses_LIBRARY
|
||||
NAMES lib${pkg}-ncurses.so
|
||||
PATH_SUFFIXES lib lib64
|
||||
DOC "Path to libimtui-ncurses.a"
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(${pkg} REQUIRED_VARS
|
||||
${pkg}_INCLUDE_DIR
|
||||
${pkg}_LIBRARY
|
||||
${pkg}_ncurses_LIBRARY
|
||||
)
|
||||
|
||||
get_filename_component(${pkg}_PREFIX "${${pkg}_INCLUDE_DIR}/.." ABSOLUTE)
|
||||
|
||||
if(${pkg}_FOUND AND NOT TARGET ${pkg}::${pkg}-ncurses)
|
||||
add_library(${pkg}::${pkg}-ncurses SHARED IMPORTED)
|
||||
set_target_properties(${pkg}::${pkg}-ncurses PROPERTIES
|
||||
IMPORTED_LOCATION ${${pkg}_ncurses_LIBRARY}
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${${pkg}_INCLUDE_DIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(${pkg}_FOUND AND NOT TARGET ${pkg}::${pkg})
|
||||
add_library(${pkg}::${pkg} SHARED IMPORTED)
|
||||
set_target_properties(${pkg}::${pkg} PROPERTIES
|
||||
IMPORTED_LOCATION ${${pkg}_LIBRARY}
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${${pkg}_INCLUDE_DIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(
|
||||
${pkg}_INCLUDE_DIR
|
||||
${pkg}_LIBRARY
|
||||
${pkg}_ncurses_LIBRARY
|
||||
)
|
|
@ -1,5 +1,5 @@
|
|||
################################################################################
|
||||
# Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# Copyright (C) 2019-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
|
@ -84,18 +84,35 @@ endif()
|
|||
###############
|
||||
# executables #
|
||||
###############
|
||||
add_executable(fairmq-dds-command-ui ${CMAKE_CURRENT_SOURCE_DIR}/runDDSCommandUI.cxx)
|
||||
target_link_libraries(fairmq-dds-command-ui
|
||||
FairMQ
|
||||
Commands
|
||||
SDK
|
||||
StateMachine
|
||||
set(target fairmq-dds-command-ui)
|
||||
add_executable(${target} ${CMAKE_CURRENT_SOURCE_DIR}/runDDSCommandUI.cxx)
|
||||
target_link_libraries(${target} PRIVATE FairMQ Commands SDK StateMachine)
|
||||
target_compile_features(${target} PRIVATE cxx_std_17)
|
||||
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
|
||||
fairmq_target_tidy(TARGET ${target})
|
||||
endif()
|
||||
|
||||
if(BUILD_SDK_TOP_TOOL)
|
||||
set(fairmq_top "fairmq-top")
|
||||
add_executable(${fairmq_top}
|
||||
top/runTool.cxx
|
||||
top/Tool.h
|
||||
)
|
||||
target_link_libraries(${fairmq_top} PRIVATE
|
||||
SDK asio::asio CLI11::CLI11 imtui::imtui imtui::imtui-ncurses)
|
||||
target_compile_features(${fairmq_top} PRIVATE cxx_std_17)
|
||||
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
|
||||
fairmq_target_tidy(TARGET ${fairmq_top})
|
||||
endif()
|
||||
else()
|
||||
set(fairmq_top)
|
||||
endif()
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
SDK
|
||||
fairmq-dds-command-ui
|
||||
${fairmq_top}
|
||||
|
||||
EXPORT ${PROJECT_EXPORT_SET}
|
||||
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
|
|
19
fairmq/sdk/top/README.md
Normal file
19
fairmq/sdk/top/README.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
### `fairmq-top`
|
||||
|
||||
`htop`-like TUI to monitor/control a running FairMQ topology.
|
||||
|
||||
EXPERIMENTAL - Currently mainly used as internal development tool.
|
||||
|
||||
Enable building by passing `-DBUILD_FAIRMQ=ON -DBUILD_SDK_COMMANDS=ON -DBUILD_SDK=ON -DBUILD_DDS_PLUGIN=ON -DBUILD_SDK_TOP_TOOL=ON`.
|
||||
|
||||
---
|
||||
|
||||
How to build [imtui](https://github.com/ggerganov/imtui) (requires ncurses devel package installed):
|
||||
|
||||
```
|
||||
git clone https://github.com/ggerganov/imtui
|
||||
cmake -S imtui -B <builddir> -DIMTUI_INSTALL_IMGUI_HEADERS=ON -DIMTUI_SUPPORT_NCURSES=ON -DCMAKE_INSTALL_PREFIX=<installdir>
|
||||
cmake --build <builddir> --target install
|
||||
```
|
||||
|
||||
and then pass `-Dimtui_ROOT=<installdir>` to the FairMQ configure above.
|
200
fairmq/sdk/top/Tool.h
Normal file
200
fairmq/sdk/top/Tool.h
Normal file
|
@ -0,0 +1,200 @@
|
|||
/********************************************************************************
|
||||
* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIR_MQ_SDK_TOP_TOOL_H
|
||||
#define FAIR_MQ_SDK_TOP_TOOL_H
|
||||
|
||||
#include <asio/io_context.hpp>
|
||||
#include <asio/post.hpp>
|
||||
#include <asio/signal_set.hpp>
|
||||
#include <asio/steady_timer.hpp>
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
#include <fairmq/Tools.h>
|
||||
#include <fairmq/Version.h>
|
||||
#include <fairmq/sdk/DDSAgent.h>
|
||||
#include <fairmq/sdk/DDSEnvironment.h>
|
||||
#include <fairmq/sdk/DDSSession.h>
|
||||
#include <fairmq/sdk/DDSTask.h>
|
||||
#include <fairmq/sdk/DDSTopology.h>
|
||||
#include <fairmq/sdk/Topology.h>
|
||||
#include <imgui/imgui.h>
|
||||
#include <imtui/imtui-impl-ncurses.h>
|
||||
#include <imtui/imtui.h>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <system_error>
|
||||
|
||||
namespace fair::mq::sdk::top {
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
struct Tool
|
||||
{
|
||||
static constexpr auto DefaultFrameDrawInterval = 200ms; // 5Hz
|
||||
static constexpr auto DefaultInputPollInterval = 10ms; // 100Hz
|
||||
static constexpr auto DefaultDataPollInterval = 333ms; // 3Hz
|
||||
|
||||
Tool(DDSSession::Id session_id)
|
||||
: fScreen(Tool::MakeScreen())
|
||||
, fSignals(fIoCtx, SIGINT, SIGTERM, SIGSEGV)
|
||||
, fFrameDrawInterval(DefaultFrameDrawInterval)
|
||||
, fFrameDrawTimer(fIoCtx)
|
||||
, fInputPollInterval(DefaultInputPollInterval)
|
||||
, fInputPollTimer(fIoCtx)
|
||||
, fDdsSessionId(std::move(session_id))
|
||||
, fDataPollInterval(DefaultInputPollInterval)
|
||||
, fDataPollTimer(fIoCtx)
|
||||
{
|
||||
fSignals.async_wait([&](std::error_code const&, int) {
|
||||
fIoCtx.stop();
|
||||
Tool::ShutdownImTui();
|
||||
});
|
||||
}
|
||||
Tool(Tool const&) = delete;
|
||||
Tool& operator=(Tool const&) = delete;
|
||||
Tool(Tool&&) = delete;
|
||||
Tool& operator=(Tool&&) = delete;
|
||||
~Tool() { Tool::ShutdownImTui(); }
|
||||
|
||||
auto DrawFrame() -> void
|
||||
{
|
||||
fFrameDrawTimer.expires_from_now(fFrameDrawInterval); // this will drift a bit (depending
|
||||
// on outstanding work in fIoCtx)
|
||||
ImTui_ImplNcurses_NewFrame();
|
||||
ImTui_ImplText_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
ImGui::SetNextWindowPos({0.0f, 0.0f});
|
||||
ImGui::SetNextWindowSize(ImGui::GetContentRegionAvail());
|
||||
ImGui::Begin(
|
||||
tools::ToString("fairmq-top v", FAIRMQ_VERSION, " session: ", fDdsSessionId, " active topo: ", fDdsTopo->GetName()).c_str(),
|
||||
nullptr,
|
||||
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove);
|
||||
ImGui::TextUnformatted(tools::ToString(this).c_str());
|
||||
// auto tasks(fDdsTopo->GetTasks());
|
||||
// for (auto const& task : tasks) {
|
||||
// ImGui::TextUnformatted(tools::ToString(task.GetId(), task.GetCollectionId()).c_str());
|
||||
// }
|
||||
// auto const agents(fDdsSession->RequestAgentInfo());
|
||||
// for (auto const& agent : agents) {
|
||||
// ImGui::TextUnformatted(tools::ToString(agent).c_str());
|
||||
// }
|
||||
// for (auto const& dev : fFmqTopoState) {
|
||||
// ImGui::TextUnformatted(
|
||||
// tools::ToString(dev.state, " ", fDdsTasks.at(dev.taskId)).c_str());
|
||||
// }
|
||||
ImGui::End();
|
||||
|
||||
ImGui::Render();
|
||||
ImTui_ImplText_RenderDrawData(ImGui::GetDrawData(), &fScreen);
|
||||
ImTui_ImplNcurses_DrawScreen();
|
||||
fFrameDrawTimer.async_wait([&](std::error_code const& e) {
|
||||
if (!e) {
|
||||
this->DrawFrame();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
auto PollInput() -> void
|
||||
{
|
||||
fInputPollTimer.expires_from_now(fInputPollInterval); // this will drift a bit (depending
|
||||
// on outstanding work in fIoCtx)
|
||||
|
||||
if (ImGui::IsKeyPressed('q', false)) {
|
||||
asio::post([&]() { fIoCtx.stop(); });
|
||||
}
|
||||
|
||||
fInputPollTimer.async_wait([&](std::error_code const& e) {
|
||||
if (!e) {
|
||||
this->PollInput();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
auto PollData() -> void
|
||||
{
|
||||
fDataPollTimer.expires_from_now(fDataPollInterval); // this will drift a bit (depending
|
||||
// on outstanding work in fIoCtx)
|
||||
|
||||
fFmqTopoState = fFmqTopo->GetCurrentState();
|
||||
|
||||
fDataPollTimer.async_wait([&](std::error_code const& e) {
|
||||
if (!e) {
|
||||
this->PollData();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
auto LoadSession(DDSTopology::Path const& topo) -> void
|
||||
{
|
||||
if (fDdsSessionId.empty()) {
|
||||
fDdsSession = std::make_unique<DDSSession>(getMostRecentRunningDDSSession(fDdsEnv));
|
||||
fDdsSessionId = fDdsSession->GetId();
|
||||
} else {
|
||||
fDdsSession = std::make_unique<DDSSession>(fDdsSessionId);
|
||||
}
|
||||
fDdsTopo = std::make_unique<DDSTopology>(topo, fDdsEnv);
|
||||
fFmqTopo = std::make_unique<Topology>(fIoCtx.get_executor(), *fDdsTopo, *fDdsSession);
|
||||
|
||||
this->PollData();
|
||||
}
|
||||
|
||||
auto Run(DDSTopology::Path const& topo) -> int
|
||||
{
|
||||
asio::post([&]() { this->PollInput(); });
|
||||
asio::post([&]() { this->LoadSession(topo); });
|
||||
asio::post([&]() { this->DrawFrame(); });
|
||||
try {
|
||||
fIoCtx.run();
|
||||
} catch (...) {
|
||||
Tool::ShutdownImTui();
|
||||
throw;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
asio::io_context fIoCtx;
|
||||
ImTui::TScreen& fScreen;
|
||||
asio::signal_set fSignals;
|
||||
std::chrono::milliseconds fFrameDrawInterval;
|
||||
asio::steady_timer fFrameDrawTimer;
|
||||
std::chrono::milliseconds fInputPollInterval;
|
||||
asio::steady_timer fInputPollTimer;
|
||||
DDSSession::Id fDdsSessionId;
|
||||
|
||||
// TODO refactor ff members into separate class
|
||||
DDSEnvironment fDdsEnv;
|
||||
std::unique_ptr<DDSSession> fDdsSession;
|
||||
std::unique_ptr<DDSTopology> fDdsTopo;
|
||||
std::unique_ptr<Topology> fFmqTopo;
|
||||
std::chrono::milliseconds fDataPollInterval;
|
||||
asio::steady_timer fDataPollTimer;
|
||||
TopologyState fFmqTopoState;
|
||||
std::map<DDSTask::Id, DDSCollection::Id> fDdsTasks;
|
||||
|
||||
static auto MakeScreen() -> ImTui::TScreen&
|
||||
{
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
auto& screen(*ImTui_ImplNcurses_Init(true));
|
||||
ImTui_ImplText_Init();
|
||||
return screen;
|
||||
}
|
||||
|
||||
static auto ShutdownImTui() -> void
|
||||
{
|
||||
ImTui_ImplText_Shutdown();
|
||||
ImTui_ImplNcurses_Shutdown();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace fair::mq::sdk::top
|
||||
|
||||
#endif /* FAIR_MQ_SDK_TOP_TOOL_H */
|
200
fairmq/sdk/top/TopTable.h
Normal file
200
fairmq/sdk/top/TopTable.h
Normal file
|
@ -0,0 +1,200 @@
|
|||
/********************************************************************************
|
||||
* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIR_MQ_SDK_TOP_TOOL_H
|
||||
#define FAIR_MQ_SDK_TOP_TOOL_H
|
||||
|
||||
#include <asio/io_context.hpp>
|
||||
#include <asio/post.hpp>
|
||||
#include <asio/signal_set.hpp>
|
||||
#include <asio/steady_timer.hpp>
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
#include <fairmq/Tools.h>
|
||||
#include <fairmq/Version.h>
|
||||
#include <fairmq/sdk/DDSAgent.h>
|
||||
#include <fairmq/sdk/DDSEnvironment.h>
|
||||
#include <fairmq/sdk/DDSSession.h>
|
||||
#include <fairmq/sdk/DDSTask.h>
|
||||
#include <fairmq/sdk/DDSTopology.h>
|
||||
#include <fairmq/sdk/Topology.h>
|
||||
#include <imgui/imgui.h>
|
||||
#include <imtui/imtui-impl-ncurses.h>
|
||||
#include <imtui/imtui.h>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <system_error>
|
||||
|
||||
namespace fair::mq::sdk::top {
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
struct Tool
|
||||
{
|
||||
static constexpr auto DefaultFrameDrawInterval = 200ms; // 5Hz
|
||||
static constexpr auto DefaultInputPollInterval = 10ms; // 100Hz
|
||||
static constexpr auto DefaultDataPollInterval = 333ms; // 3Hz
|
||||
|
||||
Tool(DDSSession::Id session_id)
|
||||
: fScreen(Tool::MakeScreen())
|
||||
, fSignals(fIoCtx, SIGINT, SIGTERM, SIGSEGV)
|
||||
, fFrameDrawInterval(DefaultFrameDrawInterval)
|
||||
, fFrameDrawTimer(fIoCtx)
|
||||
, fInputPollInterval(DefaultInputPollInterval)
|
||||
, fInputPollTimer(fIoCtx)
|
||||
, fDdsSessionId(std::move(session_id))
|
||||
, fDataPollInterval(DefaultInputPollInterval)
|
||||
, fDataPollTimer(fIoCtx)
|
||||
{
|
||||
fSignals.async_wait([&](std::error_code const&, int) {
|
||||
fIoCtx.stop();
|
||||
Tool::ShutdownImTui();
|
||||
});
|
||||
}
|
||||
Tool(Tool const&) = delete;
|
||||
Tool& operator=(Tool const&) = delete;
|
||||
Tool(Tool&&) = delete;
|
||||
Tool& operator=(Tool&&) = delete;
|
||||
~Tool() { Tool::ShutdownImTui(); }
|
||||
|
||||
auto DrawFrame() -> void
|
||||
{
|
||||
fFrameDrawTimer.expires_from_now(fFrameDrawInterval); // this will drift a bit (depending
|
||||
// on outstanding work in fIoCtx)
|
||||
ImTui_ImplNcurses_NewFrame();
|
||||
ImTui_ImplText_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
ImGui::SetNextWindowPos({0.0f, 0.0f});
|
||||
ImGui::SetNextWindowSize(ImGui::GetContentRegionAvail());
|
||||
ImGui::Begin(
|
||||
tools::ToString("fairmq-top v", FAIRMQ_VERSION, " session: ", fDdsSessionId, " active topo: ", fDdsTopo->GetName()).c_str(),
|
||||
nullptr,
|
||||
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove);
|
||||
ImGui::TextUnformatted(tools::ToString(this).c_str());
|
||||
// auto tasks(fDdsTopo->GetTasks());
|
||||
// for (auto const& task : tasks) {
|
||||
// ImGui::TextUnformatted(tools::ToString(task.GetId(), task.GetCollectionId()).c_str());
|
||||
// }
|
||||
// auto const agents(fDdsSession->RequestAgentInfo());
|
||||
// for (auto const& agent : agents) {
|
||||
// ImGui::TextUnformatted(tools::ToString(agent).c_str());
|
||||
// }
|
||||
// for (auto const& dev : fFmqTopoState) {
|
||||
// ImGui::TextUnformatted(
|
||||
// tools::ToString(dev.state, " ", fDdsTasks.at(dev.taskId)).c_str());
|
||||
// }
|
||||
ImGui::End();
|
||||
|
||||
ImGui::Render();
|
||||
ImTui_ImplText_RenderDrawData(ImGui::GetDrawData(), &fScreen);
|
||||
ImTui_ImplNcurses_DrawScreen();
|
||||
fFrameDrawTimer.async_wait([&](std::error_code const& e) {
|
||||
if (!e) {
|
||||
this->DrawFrame();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
auto PollInput() -> void
|
||||
{
|
||||
fInputPollTimer.expires_from_now(fInputPollInterval); // this will drift a bit (depending
|
||||
// on outstanding work in fIoCtx)
|
||||
|
||||
if (ImGui::IsKeyPressed('q', false)) {
|
||||
asio::post([&]() { fIoCtx.stop(); });
|
||||
}
|
||||
|
||||
fInputPollTimer.async_wait([&](std::error_code const& e) {
|
||||
if (!e) {
|
||||
this->PollInput();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
auto PollData() -> void
|
||||
{
|
||||
fDataPollTimer.expires_from_now(fDataPollInterval); // this will drift a bit (depending
|
||||
// on outstanding work in fIoCtx)
|
||||
|
||||
fFmqTopoState = fFmqTopo->GetCurrentState();
|
||||
|
||||
fDataPollTimer.async_wait([&](std::error_code const& e) {
|
||||
if (!e) {
|
||||
this->PollData();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
auto LoadSession(DDSTopology::Path const& topo) -> void
|
||||
{
|
||||
if (fDdsSessionId.empty()) {
|
||||
fDdsSession = std::make_unique<DDSSession>(getMostRecentRunningDDSSession(fDdsEnv));
|
||||
fDdsSessionId = fDdsSession->GetId();
|
||||
} else {
|
||||
fDdsSession = std::make_unique<DDSSession>(fDdsSessionId);
|
||||
}
|
||||
fDdsTopo = std::make_unique<DDSTopology>(topo, fDdsEnv);
|
||||
fFmqTopo = std::make_unique<Topology>(fIoCtx.get_executor(), *fDdsTopo, *fDdsSession);
|
||||
|
||||
this->PollData();
|
||||
}
|
||||
|
||||
auto Run(DDSTopology::Path const& topo) -> int
|
||||
{
|
||||
asio::post([&]() { this->PollInput(); });
|
||||
asio::post([&]() { this->LoadSession(topo); });
|
||||
asio::post([&]() { this->DrawFrame(); });
|
||||
try {
|
||||
fIoCtx.run();
|
||||
} catch (...) {
|
||||
Tool::ShutdownImTui();
|
||||
throw;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
asio::io_context fIoCtx;
|
||||
ImTui::TScreen& fScreen;
|
||||
asio::signal_set fSignals;
|
||||
std::chrono::milliseconds fFrameDrawInterval;
|
||||
asio::steady_timer fFrameDrawTimer;
|
||||
std::chrono::milliseconds fInputPollInterval;
|
||||
asio::steady_timer fInputPollTimer;
|
||||
DDSSession::Id fDdsSessionId;
|
||||
|
||||
// TODO refactor ff members into separate class
|
||||
DDSEnvironment fDdsEnv;
|
||||
std::unique_ptr<DDSSession> fDdsSession;
|
||||
std::unique_ptr<DDSTopology> fDdsTopo;
|
||||
std::unique_ptr<Topology> fFmqTopo;
|
||||
std::chrono::milliseconds fDataPollInterval;
|
||||
asio::steady_timer fDataPollTimer;
|
||||
TopologyState fFmqTopoState;
|
||||
std::map<DDSTask::Id, DDSCollection::Id> fDdsTasks;
|
||||
|
||||
static auto MakeScreen() -> ImTui::TScreen&
|
||||
{
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
auto& screen(*ImTui_ImplNcurses_Init(true));
|
||||
ImTui_ImplText_Init();
|
||||
return screen;
|
||||
}
|
||||
|
||||
static auto ShutdownImTui() -> void
|
||||
{
|
||||
ImTui_ImplText_Shutdown();
|
||||
ImTui_ImplNcurses_Shutdown();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace fair::mq::sdk::top
|
||||
|
||||
#endif /* FAIR_MQ_SDK_TOP_TOOL_H */
|
39
fairmq/sdk/top/runTool.cxx
Normal file
39
fairmq/sdk/top/runTool.cxx
Normal file
|
@ -0,0 +1,39 @@
|
|||
/********************************************************************************
|
||||
* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include <CLI/App.hpp>
|
||||
#include <CLI/Config.hpp>
|
||||
#include <CLI/Formatter.hpp>
|
||||
#include <fairmq/Version.h>
|
||||
#include <fairmq/sdk/top/Tool.h>
|
||||
|
||||
auto main(int argc, char** argv) -> int
|
||||
{
|
||||
CLI::App app("htop-like TUI to monitor/control a running FairMQ topology\n", "fairmq-top");
|
||||
|
||||
auto session(app.add_option("-s,--session", "DDS session id")
|
||||
->default_val(fair::mq::sdk::DDSSession::Id())
|
||||
->envname("DDS_SESSION_ID"));
|
||||
auto topo(app.add_option("-t,--topology", "DDS topology file")->check(CLI::ExistingFile));
|
||||
auto version(app.add_flag("-v,--version", "Print version")->excludes(session)->excludes(topo));
|
||||
|
||||
try {
|
||||
app.parse(argc, argv);
|
||||
} catch (CLI::ParseError const& e) {
|
||||
return app.exit(e);
|
||||
}
|
||||
|
||||
if (version->as<bool>()) {
|
||||
std::cout << FAIRMQ_GIT_VERSION << '\n';
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
fair::mq::sdk::top::Tool tool(session->as<fair::mq::sdk::DDSSession::Id>());
|
||||
|
||||
return tool.Run(topo->as<fair::mq::sdk::DDSTopology::Path>());
|
||||
}
|
Loading…
Reference in New Issue
Block a user