perf: 更快的加载!

This commit is contained in:
MistEO
2023-04-29 00:13:40 +08:00
parent 83b0254641
commit 3f8daec8c1
8 changed files with 91 additions and 70 deletions

View File

@@ -2,17 +2,33 @@
#include <meojson/json.hpp>
#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) {

View File

@@ -2,6 +2,9 @@
#include "AbstractResource.h"
#include <future>
#include <mutex>
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<bool> m_load_future;
std::mutex m_load_mutex;
};
}

View File

@@ -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<std::mutex> 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) {

View File

@@ -29,10 +29,11 @@ namespace asst
private:
using LoadItem = std::unordered_map<battle::Role, std::unordered_map<std::string, std::filesystem::path>>;
void _load(const LoadItem& waiting_to_load);
void _load(LoadItem waiting_to_load);
std::filesystem::path m_save_path;
std::future<void> m_load_future;
std::mutex m_load_mutex;
std::unordered_map<battle::Role, std::unordered_map<std::string, cv::Mat>> m_avatars;
};

View File

@@ -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<Map::TileCalc>(WindowWidthDefault, WindowHeightDefault);
}
return true;
}
@@ -122,7 +103,9 @@ std::unordered_map<asst::Point, asst::TilePack::TileInfo> asst::TilePack::calc_(
std::vector<std::vector<Map::Tile>> 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!");

View File

@@ -2,20 +2,13 @@
#include "Common/AsstBattleDef.h"
#include "Common/AsstTypes.h"
#include "Config/AbstractResource.h"
#include <memory>
#include "Config/AbstractConfig.h"
#include <Arknights-Tile-Pos/TileDef.hpp>
namespace Map
{
class TileCalc;
}
namespace asst
{
class TilePack final : public SingletonHolder<TilePack>, public AbstractResource
class TilePack final : public SingletonHolder<TilePack>, 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 <typename KeyT>
std::optional<LazyMap::value_type> 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<Point, TileInfo> calc_(const std::filesystem::path& filepath, bool side, double shift_x,
double shift_y) const;
std::shared_ptr<Map::TileCalc> m_tile_calculator = nullptr;
LazyMap m_summarize;
};

View File

@@ -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<Config>(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<Config>(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<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<Config>(full_path, full_templ_dir); \
@@ -65,17 +73,16 @@ bool asst::ResourceLoader::load(const std::filesystem::path& path)
std::vector<std::future<bool>> 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);

View File

@@ -29,6 +29,17 @@ namespace asst
return SingletonHolder<T>::get_instance().load(path);
}
template <Singleton T>
requires std::is_base_of_v<AbstractConfig, T>
bool async_load_config(const std::filesystem::path& path)
{
if (!std::filesystem::exists(path)) {
return m_loaded;
}
SingletonHolder<T>::get_instance().async_load(path);
return true;
}
template <Singleton T>
requires std::is_base_of_v<AbstractConfigWithTempl, T>
bool load_resource_with_templ(const std::filesystem::path& path, const std::filesystem::path& templ_dir)