From 3f8daec8c17cb5b2b82775e357b4998ea2636b60 Mon Sep 17 00:00:00 2001 From: MistEO Date: Sat, 29 Apr 2023 00:13:40 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E6=9B=B4=E5=BF=AB=E7=9A=84=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD=EF=BC=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/MaaCore/Config/AbstractConfig.cpp | 22 ++++++- src/MaaCore/Config/AbstractConfig.h | 12 +++- .../Miscellaneous/AvatarCacheManager.cpp | 9 ++- .../Config/Miscellaneous/AvatarCacheManager.h | 3 +- src/MaaCore/Config/Miscellaneous/TilePack.cpp | 29 ++-------- src/MaaCore/Config/Miscellaneous/TilePack.h | 18 ++---- src/MaaCore/Config/ResourceLoader.cpp | 57 ++++++++++--------- src/MaaCore/Config/ResourceLoader.h | 11 ++++ 8 files changed, 91 insertions(+), 70 deletions(-) diff --git a/src/MaaCore/Config/AbstractConfig.cpp b/src/MaaCore/Config/AbstractConfig.cpp index a6c0f5c359..182c485b18 100644 --- a/src/MaaCore/Config/AbstractConfig.cpp +++ b/src/MaaCore/Config/AbstractConfig.cpp @@ -2,17 +2,33 @@ #include +#include "Utils/Demangle.hpp" #include "Utils/Logger.hpp" bool asst::AbstractConfig::load(const std::filesystem::path& path) { - LogTraceFunction; - Log.info("load", path); + return _load(path); +} +void asst::AbstractConfig::async_load(const std::filesystem::path& path) +{ + m_load_future = std::async(std::launch::async, &AbstractConfig::_load, this, path); +} + +bool asst::AbstractConfig::_load(std::filesystem::path path) +{ if (!std::filesystem::exists(path) || !std::filesystem::is_regular_file(path)) { - Log.error("file does not exist", path); + std::string class_name = utils::demangle(typeid(*this).name()); + Log.error(class_name, "file does not exist", path); return false; } + m_path = path; + + std::unique_lock lock(m_load_mutex); + + std::string class_name = utils::demangle(typeid(*this).name()); + LogTraceScope(class_name); + Log.info(path.string()); auto ret = json::open(path, true); if (!ret) { diff --git a/src/MaaCore/Config/AbstractConfig.h b/src/MaaCore/Config/AbstractConfig.h index 0dfc22e7f9..b36519d3d7 100644 --- a/src/MaaCore/Config/AbstractConfig.h +++ b/src/MaaCore/Config/AbstractConfig.h @@ -2,6 +2,9 @@ #include "AbstractResource.h" +#include +#include + namespace json { class value; @@ -13,9 +16,16 @@ namespace asst { public: virtual ~AbstractConfig() override = default; - virtual bool load(const std::filesystem::path& path) override; + virtual bool load(const std::filesystem::path& path); + virtual void async_load(const std::filesystem::path& path); protected: virtual bool parse(const json::value& json) = 0; + + bool _load(std::filesystem::path path); + + std::filesystem::path m_path; + std::future m_load_future; + std::mutex m_load_mutex; }; } diff --git a/src/MaaCore/Config/Miscellaneous/AvatarCacheManager.cpp b/src/MaaCore/Config/Miscellaneous/AvatarCacheManager.cpp index 094246d72a..b76ffcd3b0 100644 --- a/src/MaaCore/Config/Miscellaneous/AvatarCacheManager.cpp +++ b/src/MaaCore/Config/Miscellaneous/AvatarCacheManager.cpp @@ -34,7 +34,7 @@ bool asst::AvatarCacheManager::load(const std::filesystem::path& path) waiting_to_load[role].emplace(name, filepath); } - m_load_future = std::async(std::launch::async, &AvatarCacheManager::_load, this, waiting_to_load); + m_load_future = std::async(std::launch::async, &AvatarCacheManager::_load, this, std::move(waiting_to_load)); return true; } @@ -69,7 +69,7 @@ void asst::AvatarCacheManager::set_avatar(const std::string& name, battle::Role asst::imwrite(path, avatar); } -void asst::AvatarCacheManager::_load(const LoadItem& waiting_to_load) +void asst::AvatarCacheManager::_load(LoadItem waiting_to_load) { LogTraceFunction; @@ -77,7 +77,10 @@ void asst::AvatarCacheManager::_load(const LoadItem& waiting_to_load) return; } - const auto& [_1, _2, w, h] = Task.get("BattleOperAvatar")->rect_move; + std::unique_lock lock(m_load_mutex); + // const auto [_1, _2, w, h] = Task.get("BattleOperAvatar")->rect_move; + constexpr int w = 60; + constexpr int h = 60; for (const auto& [role, name_and_paths] : waiting_to_load) { for (const auto& [name, filepath] : name_and_paths) { diff --git a/src/MaaCore/Config/Miscellaneous/AvatarCacheManager.h b/src/MaaCore/Config/Miscellaneous/AvatarCacheManager.h index 660655eebc..738c569610 100644 --- a/src/MaaCore/Config/Miscellaneous/AvatarCacheManager.h +++ b/src/MaaCore/Config/Miscellaneous/AvatarCacheManager.h @@ -29,10 +29,11 @@ namespace asst private: using LoadItem = std::unordered_map>; - void _load(const LoadItem& waiting_to_load); + void _load(LoadItem waiting_to_load); std::filesystem::path m_save_path; std::future m_load_future; + std::mutex m_load_mutex; std::unordered_map> m_avatars; }; diff --git a/src/MaaCore/Config/Miscellaneous/TilePack.cpp b/src/MaaCore/Config/Miscellaneous/TilePack.cpp index 5d3169ffd3..7774857385 100644 --- a/src/MaaCore/Config/Miscellaneous/TilePack.cpp +++ b/src/MaaCore/Config/Miscellaneous/TilePack.cpp @@ -21,43 +21,24 @@ ASST_SUPPRESS_CV_WARNINGS_END #include "Utils/Logger.hpp" -bool asst::TilePack::load(const std::filesystem::path& path) +bool asst::TilePack::parse(const json::value& json) { LogTraceFunction; - auto overview_path = path / "overview.json"; - Log.info("load", overview_path); - - if (!std::filesystem::exists(overview_path)) { - return false; - } - - auto overview_opt = json::open(overview_path); - if (!overview_opt) { - Log.error(overview_path, "failed to open"); - return false; - } - - auto& overview = overview_opt.value(); - for (const auto& [_, summary] : overview.as_object()) { + for (const auto& [_, summary] : json.as_object()) { LevelKey level_key { .stageId = summary.at("stageId").as_string(), .code = summary.at("code").as_string(), .levelId = summary.at("levelId").as_string(), .name = summary.get("name", "UnknownLevelName"), }; - auto filepath = path / utils::path(summary.at("filename").as_string()); + auto filepath = m_path / utils::path(summary.at("filename").as_string()); if (!std::filesystem::exists(filepath)) { Log.error("file not exists", filepath); return false; } m_summarize.emplace_back(std::move(level_key), std::move(filepath)); } - - if (!m_tile_calculator) { - m_tile_calculator = std::make_shared(WindowWidthDefault, WindowHeightDefault); - } - return true; } @@ -122,7 +103,9 @@ std::unordered_map asst::TilePack::calc_( std::vector> tiles; Map::Level level(*json_opt); - bool ret = m_tile_calculator->run(level, side, pos, tiles, shift_x, shift_y); + Map::TileCalc calcer(WindowWidthDefault, WindowHeightDefault); + + bool ret = calcer.run(level, side, pos, tiles, shift_x, shift_y); if (!ret) { Log.info("Tiles calc error!"); diff --git a/src/MaaCore/Config/Miscellaneous/TilePack.h b/src/MaaCore/Config/Miscellaneous/TilePack.h index e2bf43e832..5b2988a535 100644 --- a/src/MaaCore/Config/Miscellaneous/TilePack.h +++ b/src/MaaCore/Config/Miscellaneous/TilePack.h @@ -2,20 +2,13 @@ #include "Common/AsstBattleDef.h" #include "Common/AsstTypes.h" -#include "Config/AbstractResource.h" - -#include +#include "Config/AbstractConfig.h" #include -namespace Map -{ - class TileCalc; -} - namespace asst { - class TilePack final : public SingletonHolder, public AbstractResource + class TilePack final : public SingletonHolder, public AbstractConfig { public: using LevelKey = Map::LevelKey; @@ -61,8 +54,6 @@ namespace asst public: virtual ~TilePack() override = default; - virtual bool load(const std::filesystem::path& path) override; - template std::optional find(const KeyT& key) const { @@ -85,11 +76,12 @@ namespace asst return calc_(file_opt->second, side, shift_x, shift_y); } + protected: + virtual bool parse(const json::value& json) override; + private: std::unordered_map calc_(const std::filesystem::path& filepath, bool side, double shift_x, double shift_y) const; - - std::shared_ptr m_tile_calculator = nullptr; LazyMap m_summarize; }; diff --git a/src/MaaCore/Config/ResourceLoader.cpp b/src/MaaCore/Config/ResourceLoader.cpp index 9370f762e2..c074549ed9 100644 --- a/src/MaaCore/Config/ResourceLoader.cpp +++ b/src/MaaCore/Config/ResourceLoader.cpp @@ -30,20 +30,28 @@ bool asst::ResourceLoader::load(const std::filesystem::path& path) return false; } -#define LoadResourceAndCheckRet(Config, Filename) \ - { \ - LogTraceScope(std::string("LoadResourceAndCheckRet ") + #Config); \ - auto full_path = path / Filename; \ - bool ret = load_resource(full_path); \ - if (!ret) { \ - Log.error(#Config, " load failed, path:", full_path); \ - return false; \ - } \ +#define LoadResourceAndCheckRet(Config, Filename) \ + { \ + auto full_path = path / Filename; \ + bool ret = load_resource(full_path); \ + if (!ret) { \ + Log.error(#Config, " load failed, path:", full_path); \ + return false; \ + } \ + } + +#define AsyncLoadConfig(Config, Filename) \ + { \ + auto full_path = path / Filename; \ + bool ret = async_load_config(full_path); \ + if (!ret) { \ + Log.error(#Config, " load failed, path:", full_path); \ + return false; \ + } \ } #define LoadResourceWithTemplAndCheckRet(Config, Filename, TemplDir) \ { \ - LogTraceScope(std::string("LoadResourceWithTemplAndCheckRet ") + #Config); \ auto full_path = path / Filename; \ auto full_templ_dir = path / TemplDir; \ bool ret = load_resource_with_templ(full_path, full_templ_dir); \ @@ -65,17 +73,16 @@ bool asst::ResourceLoader::load(const std::filesystem::path& path) std::vector> futures; - // 这俩比较慢的单独拿出来,放最前面 - futures.emplace_back(std::async(std::launch::async | std::launch::deferred, [&]() -> bool { - LoadResourceAndCheckRet(StageDropsConfig, "stages.json"_p); - return true; - })); - futures.emplace_back(std::async(std::launch::async | std::launch::deferred, [&]() -> bool { - LoadResourceAndCheckRet(TilePack, "Arknights-Tile-Pos"_p); - return true; - })); + // 不太重要又加载的慢的资源,但不怎么占内存的,实时异步加载 + AsyncLoadConfig(StageDropsConfig, "stages.json"_p); + AsyncLoadConfig(TilePack, "Arknights-Tile-Pos"_p); + AsyncLoadConfig(RoguelikeCopilotConfig, "roguelike"_p / "copilot.json"_p); + AsyncLoadConfig(RoguelikeRecruitConfig, "roguelike"_p / "recruitment.json"_p); + AsyncLoadConfig(RoguelikeShoppingConfig, "roguelike"_p / "shopping.json"_p); + AsyncLoadConfig(RoguelikeStageEncounterConfig, "roguelike"_p / "stage_encounter.json"_p); - futures.emplace_back(std::async(std::launch::async | std::launch::deferred, [&]() -> bool { + // 太占内存的资源,都是惰性加载 + futures.emplace_back(std::async(std::launch::async, [&]() -> bool { // 战斗中技能识别,二分类模型 LoadResourceAndCheckRet(OnnxSessions, "onnx"_p / "skill_ready_cls.onnx"_p); // 战斗中部署方向识别,四分类模型 @@ -89,14 +96,11 @@ bool asst::ResourceLoader::load(const std::filesystem::path& path) return true; })); - futures.emplace_back(std::async(std::launch::async | std::launch::deferred, [&]() -> bool { + // 重要的资源,实时加载 + futures.emplace_back(std::async(std::launch::async, [&]() -> bool { /* load resource with json files*/ LoadResourceAndCheckRet(GeneralConfig, "config.json"_p); LoadResourceAndCheckRet(RecruitConfig, "recruitment.json"_p); - LoadResourceAndCheckRet(RoguelikeCopilotConfig, "roguelike"_p / "copilot.json"_p); - LoadResourceAndCheckRet(RoguelikeRecruitConfig, "roguelike"_p / "recruitment.json"_p); - LoadResourceAndCheckRet(RoguelikeShoppingConfig, "roguelike"_p / "shopping.json"_p); - LoadResourceAndCheckRet(RoguelikeStageEncounterConfig, "roguelike"_p / "stage_encounter.json"_p); LoadResourceAndCheckRet(BattleDataConfig, "battle_data.json"_p); LoadResourceAndCheckRet(OcrConfig, "ocr_config.json"_p); @@ -106,7 +110,8 @@ bool asst::ResourceLoader::load(const std::filesystem::path& path) return true; })); - futures.emplace_back(std::async(std::launch::async | std::launch::deferred, [&]() -> bool { + // 重要的资源,实时加载(图片还是惰性的) + futures.emplace_back(std::async(std::launch::async, [&]() -> bool { /* load resource with json and template files*/ LoadResourceWithTemplAndCheckRet(TaskData, "tasks.json"_p, "template"_p); LoadResourceWithTemplAndCheckRet(InfrastConfig, "infrast.json"_p, "template"_p / "infrast"_p); diff --git a/src/MaaCore/Config/ResourceLoader.h b/src/MaaCore/Config/ResourceLoader.h index e1b4671027..f4b14e06e1 100644 --- a/src/MaaCore/Config/ResourceLoader.h +++ b/src/MaaCore/Config/ResourceLoader.h @@ -29,6 +29,17 @@ namespace asst return SingletonHolder::get_instance().load(path); } + template + requires std::is_base_of_v + bool async_load_config(const std::filesystem::path& path) + { + if (!std::filesystem::exists(path)) { + return m_loaded; + } + SingletonHolder::get_instance().async_load(path); + return true; + } + template requires std::is_base_of_v bool load_resource_with_templ(const std::filesystem::path& path, const std::filesystem::path& templ_dir)