Smart parellalization

This commit is contained in:
2026-06-28 09:37:09 -04:00
parent 1813b3f5cf
commit ac98871cfc
9 changed files with 275 additions and 73 deletions

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
build/ build/
.idea .idea
*.dot

View File

@@ -4,6 +4,9 @@ project(build_script)
set(CMAKE_CXX_STANDARD 26) set(CMAKE_CXX_STANDARD 26)
set(CMAKE_POLICY_VERSION_MINIMUM 3.5) set(CMAKE_POLICY_VERSION_MINIMUM 3.5)
# Taskflow has a deprecated declaration issue in its small_vector.hpp file
add_compile_options(-Wno-deprecated-declarations)
file(GLOB REQUIRED_CMAKE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/cmake/*.required.cmake") file(GLOB REQUIRED_CMAKE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/cmake/*.required.cmake")
foreach (cmake_file ${REQUIRED_CMAKE_FILES}) foreach (cmake_file ${REQUIRED_CMAKE_FILES})
include(${cmake_file}) include(${cmake_file})
@@ -23,13 +26,16 @@ add_executable(${PROJECT_NAME} ${SRC_FILES} ${HEADER_FILES})
target_include_directories(${PROJECT_NAME} PUBLIC target_include_directories(${PROJECT_NAME} PUBLIC
"${structops_SOURCE_DIR}/include" "${structops_SOURCE_DIR}/include"
"${spdlog_SOURCE_DIR}/include" "${spdlog_SOURCE_DIR}/include"
"${taskflow_SOURCE_DIR}"
) )
target_link_libraries(${PROJECT_NAME} PUBLIC target_link_libraries(${PROJECT_NAME} PUBLIC
structopt structopt
spdlog spdlog
Taskflow
) )
# Structopt includes an outdated version of magic_enum that breaks some default defines # Structopt includes an outdated version of magic_enum that breaks some default defines
# This is needed to bypass it. Im not happy about it, but it is what it is # This is needed to bypass it. Im not happy about it, but it is what it is
target_link_options(build_script PRIVATE -Wl,--allow-multiple-definition) target_link_options(build_script PRIVATE -Wl,--allow-multiple-definition)

5
cmake/taskflow.cmake Normal file
View File

@@ -0,0 +1,5 @@
CPMAddPackage (
URI "gh:taskflow/taskflow@4.1.0"
OPTIONS "TF_BUILD_EXAMPLES off"
OPTIONS "TF_BUILD_TESTS off"
)

View File

@@ -1,6 +1,10 @@
#include "app.h" #include "app.h"
#include <fstream>
#include "args.h" #include "args.h"
#include "logging.h"
#include "taskflow/core/executor.hpp"
Application::Application(Options options) Application::Application(Options options)
: m_DryRun(options.dryrun.value()), : m_DryRun(options.dryrun.value()),
@@ -10,7 +14,7 @@ Application::Application(Options options)
createAllLoggers(); createAllLoggers();
} }
void Application::run() { void Application::assemble() {
spdlog::get("app")->debug("Running command"); spdlog::get("app")->debug("Running command");
switch (m_Command) { switch (m_Command) {
case build: case build:
@@ -29,7 +33,20 @@ void Application::run() {
rebuildProject(); rebuildProject();
break; break;
} }
}
void Application::save_graph(std::string filename) {
spdlog::get("app")->info("Saving task flow graph to '{}'", filename);
spdlog::get("app")->info(
"You can use a website like "
"'https://dreampuf.github.io/GraphvizOnline/?engine=dot' to view it.");
std::ofstream os(filename);
m_Taskflow.dump(os);
}
void Application::run() {
tf::Executor executor;
executor.run(m_Taskflow).wait();
spdlog::get("app")->info("All work done!"); spdlog::get("app")->info("All work done!");
} }

View File

@@ -2,14 +2,19 @@
#define BUILD_SCRIPT_APP #define BUILD_SCRIPT_APP
#include <filesystem> #include <filesystem>
#include <taskflow/taskflow.hpp>
#include "args.h" #include "args.h"
#include "logging.h" #include "logging.h"
#include "taskflow/core/executor.hpp"
#include "taskflow/core/taskflow.hpp"
#include "types.h" #include "types.h"
class Application { class Application {
public: public:
Application(Options options); Application(Options options);
void assemble();
void save_graph(std::string filename);
void run(); void run();
private: private:
@@ -18,6 +23,8 @@ class Application {
BuildType m_BuildType; BuildType m_BuildType;
Command m_Command; Command m_Command;
tf::Taskflow m_Taskflow;
void createAllLoggers(); void createAllLoggers();
void buildProject(); void buildProject();

View File

@@ -1,6 +1,7 @@
#ifndef BUILD_SCRIPT_ARGS #ifndef BUILD_SCRIPT_ARGS
#define BUILD_SCRIPT_ARGS #define BUILD_SCRIPT_ARGS
#include <optional>
#include <structopt/app.hpp> #include <structopt/app.hpp>
#include "types.h" #include "types.h"
@@ -11,8 +12,9 @@ struct Options {
std::optional<bool> verbose = false; std::optional<bool> verbose = false;
std::optional<bool> dryrun = false; std::optional<bool> dryrun = false;
std::optional<std::string> graphFilename;
}; };
STRUCTOPT(Options, command, buildType, verbose, dryrun); STRUCTOPT(Options, command, buildType, verbose, dryrun, graphFilename);
Options parse(int argc, char** argv); Options parse(int argc, char** argv);

View File

@@ -1,87 +1,247 @@
#include <stdexcept>
#include "app.h" #include "app.h"
#include "types.h"
void Application::buildProject() { void Application::buildProject() {
checkBuildDirs(); auto checkBuildDirsTask =
switch (m_BuildType) { m_Taskflow.emplace([this]() { this->checkBuildDirs(); })
case none: .name("checkBuildDirs");
configureDir("build/debug", "Debug"); if (m_BuildType == BuildType::none) {
buildDir("build/debug"); auto configureDirDebugTask =
configureDir("build/release", "Release"); m_Taskflow
buildDir("build/release"); .emplace(
configureDir("build/relwithdeb", "RelWithDeb"); [this]() { this->configureDir("build/debug", "debug"); })
buildDir("build/relwithdeb"); .name("configureDir(build/debug)");
configureDir("build/minsizerel", "MinSizeRel"); auto buildDirDebugTask =
buildDir("build/minsizerel"); m_Taskflow.emplace([this]() { this->buildDir("build/debug"); })
break; .name("buildDir(build/debug)");
case debug:
configureDir("build/debug", "Debug"); configureDirDebugTask.precede(buildDirDebugTask);
buildDir("build/debug"); checkBuildDirsTask.precede(configureDirDebugTask);
break;
case release: auto configureDirReleaseTask =
configureDir("build/release", "Release"); m_Taskflow
buildDir("build/release"); .emplace([this]() {
break; this->configureDir("build/release", "Release");
case relwithdeb: })
configureDir("build/relwithdeb", "RelWithDeb"); .name("configureDir(build/release)");
buildDir("build/relwithdeb"); auto buildDirReleaseTask =
break; m_Taskflow.emplace([this]() { this->buildDir("build/release"); })
case minsizerel: .name("buildDir(build/release)");
configureDir("build/minsizerel", "MinSizeRel");
buildDir("build/minsizerel"); configureDirReleaseTask.precede(buildDirReleaseTask);
break; checkBuildDirsTask.precede(configureDirReleaseTask);
auto configureDirRelWithDebTask =
m_Taskflow
.emplace([this]() {
this->configureDir("build/relwithdeb", "RelWithDeb");
})
.name("configureDir(build/relwithdeb)");
auto buildDirRelWithDebTask =
m_Taskflow.emplace([this]() { this->buildDir("build/relwithdeb"); })
.name("buildDir(build/relwithdeb)");
configureDirRelWithDebTask.precede(buildDirRelWithDebTask);
checkBuildDirsTask.precede(configureDirRelWithDebTask);
auto configureDirMinSizeRelTask =
m_Taskflow
.emplace([this]() {
this->configureDir("build/minsizerel", "MinSizeRel");
})
.name("configureDir(build/minsizerel)");
auto buildDirMinSizeRelTask =
m_Taskflow.emplace([this]() { this->buildDir("build/minsizerel"); })
.name("buildDir(build/minsizerel)");
configureDirMinSizeRelTask.precede(buildDirMinSizeRelTask);
checkBuildDirsTask.precede(configureDirMinSizeRelTask);
} else if (m_BuildType == BuildType::debug) {
auto configureDirTask =
m_Taskflow
.emplace(
[this]() { this->configureDir("build/debug", "debug"); })
.name("configureDir(build/debug)");
auto buildDirTask =
m_Taskflow.emplace([this]() { this->buildDir("build/debug"); })
.name("buildDir(build/debug)");
configureDirTask.precede(buildDirTask);
checkBuildDirsTask.precede(configureDirTask);
} else if (m_BuildType == BuildType::release) {
auto configureDirTask =
m_Taskflow
.emplace([this]() {
this->configureDir("build/release", "Release");
})
.name("configureDir(build/release)");
auto buildDirTask =
m_Taskflow.emplace([this]() { this->buildDir("build/release"); })
.name("buildDir(build/release)");
configureDirTask.precede(buildDirTask);
checkBuildDirsTask.precede(configureDirTask);
} else if (m_BuildType == BuildType::relwithdeb) {
auto configureDirTask =
m_Taskflow
.emplace([this]() {
this->configureDir("build/relwithdeb", "RelWithDeb");
})
.name("configureDir(build/relwithdeb)");
auto buildDirTask =
m_Taskflow.emplace([this]() { this->buildDir("build/relwithdeb"); })
.name("buildDir(build/relwithdeb)");
configureDirTask.precede(buildDirTask);
checkBuildDirsTask.precede(configureDirTask);
} else if (m_BuildType == BuildType::minsizerel) {
auto configureDirTask =
m_Taskflow
.emplace([this]() {
this->configureDir("build/minsizerel", "MinSizeRel");
})
.name("configureDir(build/minsizerel)");
auto buildDirTask =
m_Taskflow.emplace([this]() { this->buildDir("build/minsizerel"); })
.name("buildDir(build/minsizerel)");
configureDirTask.precede(buildDirTask);
checkBuildDirsTask.precede(configureDirTask);
} }
} }
void Application::configureProject() { void Application::configureProject() {
checkBuildDirs(); auto checkBuildDirsTask =
switch (m_BuildType) { m_Taskflow.emplace([this]() { this->checkBuildDirs(); })
case none: .name("checkBuildDirs");
configureDir("build/debug", "Debug"); if (m_BuildType == BuildType::none) {
configureDir("build/release", "Release"); auto configureDirDebugTask =
configureDir("build/relwithdeb", "RelWithDeb"); m_Taskflow
configureDir("build/minsizerel", "MinSizeRel"); .emplace(
break; [this]() { this->configureDir("build/debug", "debug"); })
case debug: .name("configureDir(build/debug)");
configureDir("build/debug", "Debug"); checkBuildDirsTask.precede(configureDirDebugTask);
break;
case release: auto configureDirReleaseTask =
configureDir("build/release", "Release"); m_Taskflow
break; .emplace([this]() {
case relwithdeb: this->configureDir("build/release", "Release");
configureDir("build/relwithbeb", "RelWithDeb"); })
break; .name("configureDir(build/release)");
case minsizerel: checkBuildDirsTask.precede(configureDirReleaseTask);
configureDir("build/minsizerel", "MinSizeRel");
break; auto configureDirRelWithDebTask =
m_Taskflow
.emplace([this]() {
this->configureDir("build/relwithdeb", "RelWithDeb");
})
.name("configureDir(build/relwithdeb)");
checkBuildDirsTask.precede(configureDirRelWithDebTask);
auto configureDirMinSizeRelTask =
m_Taskflow
.emplace([this]() {
this->configureDir("build/minsizerel", "MinSizeRel");
})
.name("configureDir(build/minsizerel)");
checkBuildDirsTask.precede(configureDirMinSizeRelTask);
} else if (m_BuildType == BuildType::debug) {
auto configureDirDebugTask =
m_Taskflow
.emplace(
[this]() { this->configureDir("build/debug", "debug"); })
.name("configureDir(build/debug)");
checkBuildDirsTask.precede(configureDirDebugTask);
} else if (m_BuildType == BuildType::release) {
auto configureDirReleaseTask =
m_Taskflow
.emplace([this]() {
this->configureDir("build/release", "Release");
})
.name("configureDir(build/release)");
checkBuildDirsTask.precede(configureDirReleaseTask);
} else if (m_BuildType == BuildType::relwithdeb) {
auto configureDirRelWithDebTask =
m_Taskflow
.emplace([this]() {
this->configureDir("build/relwithdeb", "RelWithDeb");
})
.name("configureDir(build/relwithdeb)");
checkBuildDirsTask.precede(configureDirRelWithDebTask);
} else if (m_BuildType == BuildType::minsizerel) {
auto configureDirMinSizeRelTask =
m_Taskflow
.emplace([this]() {
this->configureDir("build/minsizerel", "MinSizeRel");
})
.name("configureDir(build/minsizerel)");
checkBuildDirsTask.precede(configureDirMinSizeRelTask);
} }
} }
void Application::cleanProject() { void Application::cleanProject() {
checkBuildDirs(); auto checkBuildDirsTask =
m_Taskflow.emplace([this]() { this->checkBuildDirs(); })
.name("checkBuildDirs");
switch (m_BuildType) { if (m_BuildType == BuildType::none) {
case none: auto cleanDirDebugTask =
cleanDir("build/debug"); m_Taskflow.emplace([this]() { this->cleanDir("build/debug"); })
cleanDir("build/release"); .name("cleanDir(build/debug)");
cleanDir("build/relwithdeb"); checkBuildDirsTask.precede(cleanDirDebugTask);
cleanDir("build/minsizerel");
break; auto cleanDirReleaseTask =
case debug: m_Taskflow.emplace([this]() { this->cleanDir("build/release"); })
cleanDir("build/debug"); .name("cleanDir(build/release)");
break; checkBuildDirsTask.precede(cleanDirReleaseTask);
case release:
cleanDir("build/release"); auto cleanDirRelWithDebTask =
break; m_Taskflow.emplace([this]() { this->cleanDir("build/relwithdeb"); })
case relwithdeb: .name("cleanDir(build/relwithdeb)");
cleanDir("build/relwithdeb"); checkBuildDirsTask.precede(cleanDirRelWithDebTask);
break; auto cleanDirMinSizeRelTask =
case minsizerel: m_Taskflow.emplace([this]() { this->cleanDir("build/minsizerel"); })
cleanDir("build/minsizerel"); .name("cleanDir(build/minsizerel)");
break; checkBuildDirsTask.precede(cleanDirMinSizeRelTask);
} else if (m_BuildType == BuildType::debug) {
auto cleanDirDebugTask =
m_Taskflow.emplace([this]() { this->cleanDir("build/debug"); })
.name("cleanDir(build/debug)");
checkBuildDirsTask.precede(cleanDirDebugTask);
} else if (m_BuildType == BuildType::release) {
auto cleanDirReleaseTask =
m_Taskflow.emplace([this]() { this->cleanDir("build/release"); })
.name("cleanDir(build/release)");
checkBuildDirsTask.precede(cleanDirReleaseTask);
} else if (m_BuildType == BuildType::relwithdeb) {
auto cleanDirRelWithDebTask =
m_Taskflow.emplace([this]() { this->cleanDir("build/relwithdeb"); })
.name("cleanDir(build/relwithdeb)");
checkBuildDirsTask.precede(cleanDirRelWithDebTask);
} else if (m_BuildType == BuildType::minsizerel) {
auto cleanDirMinSizeRelTask =
m_Taskflow.emplace([this]() { this->cleanDir("build/minsizerel"); })
.name("cleanDir(build/minsizerel)");
checkBuildDirsTask.precede(cleanDirMinSizeRelTask);
} }
} }
void Application::deleteProject() { void Application::deleteProject() {
// No point in using taskflow for this...
// In all cases its just deleting a single directory...
// Bit overkill for that
switch (m_BuildType) { switch (m_BuildType) {
case none: case none:
deleteDir("build"); deleteDir("build");
@@ -103,7 +263,5 @@ void Application::deleteProject() {
void Application::rebuildProject() { void Application::rebuildProject() {
deleteProject(); deleteProject();
checkBuildDirs();
configureProject();
buildProject(); buildProject();
} }

View File

@@ -35,7 +35,7 @@ void createLogger(const char* name, const char* filename, const bool verbose) {
if (verbose) if (verbose)
logger->set_level(spdlog::level::debug); logger->set_level(spdlog::level::debug);
else else
logger->set_level(spdlog::level::warn); logger->set_level(spdlog::level::info);
#endif #endif
spdlog::register_logger(logger); spdlog::register_logger(logger);

View File

@@ -9,6 +9,12 @@
int main(const int argc, char** argv) { int main(const int argc, char** argv) {
Options options = parse(argc, argv); Options options = parse(argc, argv);
Application app(options); Application app(options);
app.assemble();
if (options.graphFilename.has_value()) {
app.save_graph(options.graphFilename.value());
spdlog::get("app")->info("Exiting..");
return 0;
}
app.run(); app.run();
return 0; return 0;