sys: Improved startup time by running startup tasks in parallel

This commit is contained in:
WerWolv 2022-09-19 16:54:19 +02:00
parent 7b61268f22
commit 4c01a749de
8 changed files with 54 additions and 25 deletions

View File

@ -171,6 +171,8 @@ namespace hex {
void setGPUVendor(const std::string &vendor); void setGPUVendor(const std::string &vendor);
void setPortableVersion(bool enabled); void setPortableVersion(bool enabled);
void addInitArgument(const std::string &key, const std::string &value = { });
} }
struct ProgramArguments { struct ProgramArguments {

View File

@ -3,6 +3,7 @@
#include <hex.hpp> #include <hex.hpp>
#include <chrono> #include <chrono>
#include <mutex>
#include <fmt/core.h> #include <fmt/core.h>
#include <fmt/color.h> #include <fmt/color.h>
@ -30,6 +31,9 @@ namespace hex::log {
template<typename... T> template<typename... T>
[[maybe_unused]] void print(const fmt::text_style &ts, const std::string &level, const std::string &fmt, auto... args) { [[maybe_unused]] void print(const fmt::text_style &ts, const std::string &level, const std::string &fmt, auto... args) {
static std::mutex logMutex;
std::scoped_lock lock(logMutex);
auto dest = getDestination(); auto dest = getDestination();
printPrefix(dest, ts, level); printPrefix(dest, ts, level);

View File

@ -385,6 +385,13 @@ namespace hex {
s_portableVersion = enabled; s_portableVersion = enabled;
} }
void addInitArgument(const std::string &key, const std::string &value) {
static std::mutex initArgumentsMutex;
std::scoped_lock lock(initArgumentsMutex);
getInitArguments()[key] = value;
}
} }

View File

@ -19,8 +19,8 @@ namespace hex::init {
bool loop(); bool loop();
void addStartupTask(const std::string &taskName, const TaskFunction &task) { void addStartupTask(const std::string &taskName, const TaskFunction &task, bool async) {
this->m_tasks.emplace_back(taskName, task); this->m_tasks.emplace_back(taskName, task, async);
} }
private: private:
@ -37,7 +37,7 @@ namespace hex::init {
std::future<bool> processTasksAsync(); std::future<bool> processTasksAsync();
std::vector<std::pair<std::string, TaskFunction>> m_tasks; std::vector<std::tuple<std::string, TaskFunction, bool>> m_tasks;
std::string m_gpuVendor; std::string m_gpuVendor;
}; };

View File

@ -9,6 +9,7 @@ namespace hex::init {
struct Task { struct Task {
std::string name; std::string name;
std::function<bool()> function; std::function<bool()> function;
bool async;
}; };
std::vector<Task> getInitTasks(); std::vector<Task> getInitTasks();

View File

@ -43,15 +43,27 @@ namespace hex::init {
return std::async(std::launch::async, [this] { return std::async(std::launch::async, [this] {
bool status = true; bool status = true;
for (const auto &[name, task] : this->m_tasks) { u32 tasksCompleted = 0;
{ for (const auto &[name, task, async] : this->m_tasks) {
if (!async) {
std::lock_guard guard(this->m_progressMutex); std::lock_guard guard(this->m_progressMutex);
this->m_currTaskName = name; this->m_currTaskName = name;
} }
try { auto runTask = [&, task = task] {
if (!task()) if (!task())
status = false; status = false;
tasksCompleted++;
};
try {
if (async) {
std::thread(runTask).detach();
} else {
runTask();
}
} catch (std::exception &e) { } catch (std::exception &e) {
log::error("Init task '{}' threw an exception: {}", name, e.what()); log::error("Init task '{}' threw an exception: {}", name, e.what());
status = false; status = false;
@ -63,6 +75,9 @@ namespace hex::init {
} }
} }
while (tasksCompleted < this->m_tasks.size())
std::this_thread::sleep_for(100ms);
// Small extra delay so the last progress step is visible // Small extra delay so the last progress step is visible
std::this_thread::sleep_for(200ms); std::this_thread::sleep_for(200ms);

View File

@ -40,7 +40,7 @@ namespace hex::init {
auto latestVersion = releases.body["tag_name"].get<std::string_view>(); auto latestVersion = releases.body["tag_name"].get<std::string_view>();
if (latestVersion != currVersion) if (latestVersion != currVersion)
ImHexApi::System::getInitArguments().insert({ "update-available", latestVersion.data() }); ImHexApi::System::impl::addInitArgument("update-available", latestVersion.data());
return true; return true;
} }
@ -52,7 +52,7 @@ namespace hex::init {
if (tip.code != 200) if (tip.code != 200)
return false; return false;
ImHexApi::System::getInitArguments().insert({ "tip-of-the-day", tip.body }); ImHexApi::System::impl::addInitArgument("tip-of-the-day", tip.body);
return true; return true;
} }
@ -99,7 +99,7 @@ namespace hex::init {
} }
if (!result) if (!result)
ImHexApi::System::getInitArguments().insert({ "folder-creation-error", {} }); ImHexApi::System::impl::addInitArgument("folder-creation-error");
return result; return result;
} }
@ -246,7 +246,7 @@ namespace hex::init {
if (plugins.empty()) { if (plugins.empty()) {
log::error("No plugins found!"); log::error("No plugins found!");
ImHexApi::System::getInitArguments().insert({ "no-plugins", {} }); ImHexApi::System::impl::addInitArgument("no-plugins");
return false; return false;
} }
@ -274,17 +274,17 @@ namespace hex::init {
if (loadErrors == plugins.size()) { if (loadErrors == plugins.size()) {
log::error("No plugins loaded successfully!"); log::error("No plugins loaded successfully!");
ImHexApi::System::getInitArguments().insert({ "no-plugins", {} }); ImHexApi::System::impl::addInitArgument("no-plugins");
return false; return false;
} }
if (builtinPlugins == 0) { if (builtinPlugins == 0) {
log::error("Built-in plugin not found!"); log::error("Built-in plugin not found!");
ImHexApi::System::getInitArguments().insert({ "no-builtin-plugin", {} }); ImHexApi::System::impl::addInitArgument("no-builtin-plugin");
return false; return false;
} else if (builtinPlugins > 1) { } else if (builtinPlugins > 1) {
log::error("Found more than one built-in plugin!"); log::error("Found more than one built-in plugin!");
ImHexApi::System::getInitArguments().insert({ "multiple-builtin-plugins", {} }); ImHexApi::System::impl::addInitArgument("multiple-builtin-plugins");
return false; return false;
} }
@ -324,20 +324,20 @@ namespace hex::init {
std::vector<Task> getInitTasks() { std::vector<Task> getInitTasks() {
return { return {
{"Checking for updates...", checkForUpdates }, { "Checking for updates...", checkForUpdates, false },
{ "Downloading information...", downloadInformation}, { "Downloading information...", downloadInformation, true },
{ "Creating directories...", createDirectories }, { "Loading fonts...", loadFonts, true },
{ "Loading settings...", loadSettings }, { "Creating directories...", createDirectories, false },
{ "Loading plugins...", loadPlugins }, { "Loading settings...", loadSettings, false },
{ "Loading fonts...", loadFonts }, { "Loading plugins...", loadPlugins, false },
}; };
} }
std::vector<Task> getExitTasks() { std::vector<Task> getExitTasks() {
return { return {
{"Saving settings...", storeSettings }, { "Saving settings...", storeSettings, false },
{ "Cleaning up shared data...", deleteSharedData}, { "Cleaning up shared data...", deleteSharedData, false },
{ "Unloading plugins...", unloadPlugins }, { "Unloading plugins...", unloadPlugins, false },
}; };
} }

View File

@ -33,8 +33,8 @@ int main(int argc, char **argv, char **envp) {
init::WindowSplash splashWindow; init::WindowSplash splashWindow;
for (const auto &[name, task] : init::getInitTasks()) for (const auto &[name, task, async] : init::getInitTasks())
splashWindow.addStartupTask(name, task); splashWindow.addStartupTask(name, task, async);
if (!splashWindow.loop()) if (!splashWindow.loop())
ImHexApi::System::getInitArguments().insert({ "tasks-failed", {} }); ImHexApi::System::getInitArguments().insert({ "tasks-failed", {} });
@ -42,7 +42,7 @@ int main(int argc, char **argv, char **envp) {
// Clean up // Clean up
ON_SCOPE_EXIT { ON_SCOPE_EXIT {
for (const auto &[name, task] : init::getExitTasks()) for (const auto &[name, task, async] : init::getExitTasks())
task(); task();
}; };