mirror of
https://github.com/CHN-beta/nixos.git
synced 2024-10-23 03:18:45 +08:00
localPackages.sbatch-tui: 基本完成
This commit is contained in:
parent
64532717da
commit
b5a4aee761
@ -197,9 +197,9 @@
|
||||
packages = [ pkgs.clang-tools_17 ];
|
||||
CMAKE_EXPORT_COMPILE_COMMANDS = "1";
|
||||
};
|
||||
sbatch-cli = pkgs.mkShell
|
||||
sbatch-tui = pkgs.mkShell
|
||||
{
|
||||
packages = with pkgs; [ sbatch-cli ];
|
||||
inputsFrom = with pkgs.localPackages; [ sbatch-tui ];
|
||||
buildInputs = [ pkgs.clang-tools_17 ];
|
||||
CMAKE_EXPORT_COMPILE_COMMANDS = "1";
|
||||
};
|
||||
|
@ -78,7 +78,7 @@ inputs: rec
|
||||
sqlite-orm = inputs.pkgs.callPackage ./sqlite-orm { src = inputs.topInputs.sqlite-orm; };
|
||||
mkPnpmPackage = inputs.pkgs.callPackage ./mkPnpmPackage.nix {};
|
||||
nodejs-with-pnpm9 = inputs.pkgs.callPackage ./nodejs-with-pnpm9.nix {};
|
||||
sbatch-cli = inputs.pkgs.callPackage ./sbatch-cli {};
|
||||
sbatch-tui = inputs.pkgs.callPackage ./sbatch-tui {};
|
||||
|
||||
fromYaml = content: builtins.fromJSON (builtins.readFile
|
||||
(inputs.pkgs.runCommand "toJSON" {}
|
||||
|
@ -1 +0,0 @@
|
||||
use flake .#sbatch-cli
|
@ -1,7 +0,0 @@
|
||||
{ stdenv, cmake, pkg-config }: stdenv.mkDerivation
|
||||
{
|
||||
name = "sbatch-cli";
|
||||
src = ./.;
|
||||
buildInputs = [];
|
||||
nativeBuildInputs = [ cmake pkg-config ];
|
||||
}
|
1
local/pkgs/sbatch-tui/.envrc
Normal file
1
local/pkgs/sbatch-tui/.envrc
Normal file
@ -0,0 +1 @@
|
||||
use flake .#sbatch-tui
|
@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(sbatch-cli VERSION 0.0.0 LANGUAGES CXX)
|
||||
project(sbatch-tui VERSION 0.0.0 LANGUAGES CXX)
|
||||
enable_testing()
|
||||
include(GNUInstallDirs)
|
||||
|
||||
@ -9,13 +9,18 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
|
||||
endif()
|
||||
|
||||
set(HPCSTAT_VERSION "unknown" CACHE STRING "Version of the hpcstat")
|
||||
find_package(fmt REQUIRED)
|
||||
find_package(ftxui REQUIRED)
|
||||
find_package(Boost REQUIRED COMPONENTS filesystem)
|
||||
find_package(range-v3 REQUIRED)
|
||||
|
||||
add_executable(sbatch-cli src/main.cpp)
|
||||
target_compile_features(sbatch-cli PUBLIC cxx_std_23)
|
||||
# target_link_libraries(sbatch-cli PRIVATE)
|
||||
add_executable(sbatch-tui src/main.cpp src/device.cpp)
|
||||
target_compile_features(sbatch-tui PUBLIC cxx_std_23)
|
||||
target_include_directories(sbatch-tui PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
target_link_libraries(sbatch-tui PRIVATE fmt::fmt ftxui::screen ftxui::dom ftxui::component Boost::filesystem
|
||||
range-v3::range-v3)
|
||||
|
||||
install(TARGETS sbatch-cli RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install(TARGETS sbatch-tui RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
get_property(ImportedTargets DIRECTORY "${CMAKE_SOURCE_DIR}" PROPERTY IMPORTED_TARGETS)
|
||||
message("Imported targets: ${ImportedTargets}")
|
7
local/pkgs/sbatch-tui/default.nix
Normal file
7
local/pkgs/sbatch-tui/default.nix
Normal file
@ -0,0 +1,7 @@
|
||||
{ stdenv, cmake, pkg-config, fmt, ftxui, boost, range-v3 }: stdenv.mkDerivation
|
||||
{
|
||||
name = "sbatch-tui";
|
||||
src = ./.;
|
||||
buildInputs = [ fmt ftxui boost range-v3 ];
|
||||
nativeBuildInputs = [ cmake pkg-config ];
|
||||
}
|
10
local/pkgs/sbatch-tui/include/sbatch-tui/device.hpp
Normal file
10
local/pkgs/sbatch-tui/include/sbatch-tui/device.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
# pragma once
|
||||
# include <string>
|
||||
# include <vector>
|
||||
|
||||
struct Device_t
|
||||
{
|
||||
unsigned CpuMpiThreads, CpuOpenMPThreads;
|
||||
std::vector<std::string> GpuIds;
|
||||
};
|
||||
extern Device_t Device;
|
8
local/pkgs/sbatch-tui/src/device.cpp
Normal file
8
local/pkgs/sbatch-tui/src/device.cpp
Normal file
@ -0,0 +1,8 @@
|
||||
# include <sbatch-tui/device.hpp>
|
||||
|
||||
Device_t Device
|
||||
{
|
||||
.CpuMpiThreads = 1,
|
||||
.CpuOpenMPThreads = 1,
|
||||
.GpuIds = { "4060" }
|
||||
};
|
8
local/pkgs/sbatch-tui/src/device.cpp.template
Normal file
8
local/pkgs/sbatch-tui/src/device.cpp.template
Normal file
@ -0,0 +1,8 @@
|
||||
# include <sbatch-tui/device.hpp>
|
||||
|
||||
decltype(Device) Device
|
||||
{
|
||||
.CpuMpiThreads = @CpuMpiThreads@,
|
||||
.CpuOpenMPThreads = @CpuOpenMPThreads@,
|
||||
.GpuIds = { @GpuIds@ }
|
||||
};
|
157
local/pkgs/sbatch-tui/src/main.cpp
Normal file
157
local/pkgs/sbatch-tui/src/main.cpp
Normal file
@ -0,0 +1,157 @@
|
||||
# include <map>
|
||||
# include <filesystem>
|
||||
# include <ftxui/component/component.hpp>
|
||||
# include <ftxui/component/component_options.hpp>
|
||||
# include <ftxui/component/screen_interactive.hpp>
|
||||
# include <boost/process.hpp>
|
||||
# include <boost/algorithm/string.hpp>
|
||||
# include <fmt/format.h>
|
||||
# include <range/v3/view.hpp>
|
||||
# include <sbatch-tui/device.hpp>
|
||||
|
||||
using namespace fmt::literals;
|
||||
using namespace std::literals;
|
||||
|
||||
int main()
|
||||
{
|
||||
// 需要绑定到界面上的变量
|
||||
struct
|
||||
{
|
||||
int vasp_version_selected = 0;
|
||||
std::vector<std::string> vasp_version_entries = { "std", "gam", "ncl" };
|
||||
int device_selected = 0;
|
||||
std::vector<std::string> device_entries = []
|
||||
{
|
||||
std::vector<std::string> devices(Device.GpuIds.size() + 2);
|
||||
for (std::size_t i = 0; i < Device.GpuIds.size(); ++i)
|
||||
devices[i + 1] = Device.GpuIds[i];
|
||||
devices[0] = "any single GPU";
|
||||
devices.back() = "CPU";
|
||||
return devices;
|
||||
}();
|
||||
std::string user_command;
|
||||
std::string submit_command;
|
||||
} state;
|
||||
|
||||
// 为组件增加标题栏
|
||||
auto component_with_title = [](std::string title, ftxui::Component component)
|
||||
{
|
||||
return ftxui::Renderer(component, [title, component]
|
||||
{
|
||||
return ftxui::vbox
|
||||
({
|
||||
ftxui::text(title) | ftxui::bgcolor(ftxui::Color::Blue),
|
||||
component->Render(),
|
||||
ftxui::separator()
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 构建界面, 需要至少 25 行 47 列
|
||||
auto screen = ftxui::ScreenInteractive::Fullscreen();
|
||||
auto request_interface = [&state, &screen, &component_with_title]
|
||||
{
|
||||
auto vasp_version = component_with_title
|
||||
(
|
||||
"Select VASP version:",
|
||||
ftxui::Menu(&state.vasp_version_entries, &state.vasp_version_selected)
|
||||
)
|
||||
| ftxui::size(ftxui::WIDTH, ftxui::EQUAL, 30);
|
||||
auto device = component_with_title
|
||||
(
|
||||
"Select device:",
|
||||
ftxui::Menu(&state.device_entries, &state.device_selected)
|
||||
)
|
||||
| ftxui::size(ftxui::WIDTH, ftxui::EQUAL, 30);
|
||||
auto continue_button = ftxui::Button("Continue",
|
||||
[&]{ state.user_command = "continue"; screen.ExitLoopClosure()(); });
|
||||
auto quit_button = ftxui::Button("Quit",
|
||||
[&]{ state.user_command = "quit"; screen.ExitLoopClosure()(); });
|
||||
return ftxui::Container::Vertical
|
||||
({
|
||||
vasp_version, device,
|
||||
ftxui::Container::Horizontal({continue_button, quit_button})
|
||||
}) | ftxui::borderHeavy
|
||||
| ftxui::size(ftxui::WIDTH, ftxui::EQUAL, 30)
|
||||
| ftxui::size(ftxui::HEIGHT, ftxui::EQUAL, 18);
|
||||
}();
|
||||
auto confirm_interface = [&state, &screen, &component_with_title]
|
||||
{
|
||||
ftxui::InputOption input_option;
|
||||
input_option.multiline = true;
|
||||
return ftxui::Container::Vertical
|
||||
({
|
||||
component_with_title
|
||||
(
|
||||
"Double check & modify submit command:",
|
||||
ftxui::Input(&state.submit_command, "", input_option)
|
||||
)
|
||||
| ftxui::size(ftxui::HEIGHT, ftxui::EQUAL, 7),
|
||||
ftxui::Container::Horizontal
|
||||
({
|
||||
ftxui::Button("Submit",
|
||||
[&]{state.user_command = "submit"; screen.ExitLoopClosure()();}),
|
||||
ftxui::Button("Quit",
|
||||
[&]{state.user_command = "quit"; screen.ExitLoopClosure()();}),
|
||||
ftxui::Button("Back",
|
||||
[&]{state.user_command = "back"; screen.ExitLoopClosure()();})
|
||||
})
|
||||
}) | ftxui::borderHeavy
|
||||
| ftxui::size(ftxui::WIDTH, ftxui::EQUAL, 30)
|
||||
| ftxui::size(ftxui::HEIGHT, ftxui::EQUAL, 18);
|
||||
}();
|
||||
|
||||
// 实际投递任务
|
||||
auto submit = [](std::string submit_command)
|
||||
{
|
||||
// replace \n with space
|
||||
boost::replace_all(submit_command, "\n", " ");
|
||||
auto process = boost::process::child
|
||||
(
|
||||
boost::process::search_path("sh"), "-c", submit_command,
|
||||
boost::process::std_in.close(),
|
||||
boost::process::std_out > stdout,
|
||||
boost::process::std_err > stderr
|
||||
);
|
||||
process.wait();
|
||||
};
|
||||
|
||||
// 进入事件循环
|
||||
while (true)
|
||||
{
|
||||
screen.Loop(request_interface);
|
||||
if (state.user_command == "quit")
|
||||
return EXIT_FAILURE;
|
||||
else if (state.user_command != "continue")
|
||||
throw std::runtime_error("user_command is not recognized");
|
||||
else if (state.device_selected < 0 || state.device_selected >= state.device_entries.size())
|
||||
throw std::runtime_error("device_selected is out of range");
|
||||
else if (state.device_selected == 0) state.submit_command = fmt::format
|
||||
(
|
||||
"sbatch --ntasks=1\n--gpus=1\n--job-name='{}'\n--output=output.txt\nvasp-nvidia-{}",
|
||||
std::filesystem::current_path().filename().string(), state.vasp_version_entries[state.vasp_version_selected]
|
||||
);
|
||||
else if (state.device_selected == state.device_entries.size() - 1) state.submit_command = fmt::format
|
||||
(
|
||||
"sbatch --ntasks={}\n--cpus-per-task={}\n--hint=nomultithread\n--job-name='{}'\n--output=output.txt"
|
||||
"\nvasp-intel-{}",
|
||||
Device.CpuMpiThreads, Device.CpuOpenMPThreads, std::filesystem::current_path().filename().string(),
|
||||
state.vasp_version_entries[state.vasp_version_selected]
|
||||
);
|
||||
else state.submit_command = fmt::format
|
||||
(
|
||||
"sbatch --ntasks=1\n--gpus={}:1\n--job-name='{}'\n--output=output.txt\nvasp-nvidia-{}",
|
||||
state.device_entries[state.device_selected], std::filesystem::current_path().filename().string(),
|
||||
state.vasp_version_entries[state.vasp_version_selected]
|
||||
);
|
||||
screen.Loop(confirm_interface);
|
||||
if (state.user_command == "quit")
|
||||
return EXIT_FAILURE;
|
||||
else if (state.user_command == "back")
|
||||
continue;
|
||||
else if (state.user_command != "submit")
|
||||
throw std::runtime_error("user_command is not recognized");
|
||||
submit(state.submit_command);
|
||||
break;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user