From cfed86f9af8fd68a38222a21ab50c14032b36061 Mon Sep 17 00:00:00 2001 From: Megvii Engine Team Date: Mon, 27 Jun 2022 19:05:39 +0800 Subject: [PATCH] feat(persistentcache): change file persistent cache with append model GitOrigin-RevId: 7a427bdab4198a48190f0ecd7a45f4c0c889be8c --- .../impl/utils/infile_persistent_cache.cpp | 11 +-- src/core/impl/utils/persistent_cache.cpp | 72 +++++++++++++------ .../megbrain/utils/infile_persistent_cache.h | 34 --------- .../include/megbrain/utils/persistent_cache.h | 59 +++++++++------ src/opr/test/dnn/convolution.cpp | 63 ++++++++++++++++ 5 files changed, 154 insertions(+), 85 deletions(-) diff --git a/src/core/impl/utils/infile_persistent_cache.cpp b/src/core/impl/utils/infile_persistent_cache.cpp index 9604f6652..07383bdcc 100644 --- a/src/core/impl/utils/infile_persistent_cache.cpp +++ b/src/core/impl/utils/infile_persistent_cache.cpp @@ -120,22 +120,13 @@ InFilePersistentCache::BlobStorage& InFilePersistentCache::BlobStorage::init_fro return *this; } +template void InFilePersistentCache::BlobStorage::write_to_file(OutputFile& out_file) const { uint32_t u_size = size; out_file.write(u_size); out_file.write(data_refhold.get(), u_size); } -InFilePersistentCache::BlobStorage& InFilePersistentCache::BlobStorage::init_data_ref( - const Blob& b) { - data_refhold = std::make_unique(b.size + 1); - memcpy(data_refhold.get(), b.ptr, b.size); - data_refhold.get()[b.size] = 0; // for C-string safety - ptr = data_refhold.get(); - size = b.size; - return *this; -} - //////////////////////// InFilePersistentCache ////////////////////// template diff --git a/src/core/impl/utils/persistent_cache.cpp b/src/core/impl/utils/persistent_cache.cpp index 026e025ca..c41fd89c2 100644 --- a/src/core/impl/utils/persistent_cache.cpp +++ b/src/core/impl/utils/persistent_cache.cpp @@ -21,10 +21,62 @@ std::shared_ptr PersistentCache::sm_impl = std::shared_ptr PersistentCache::set_impl( std::shared_ptr impl) { mgb_assert(impl); + merge_old_cache(impl); sm_impl.swap(impl); return impl; } +void PersistentCache::merge_old_cache(std::shared_ptr impl) { + MGB_LOCK_GUARD(PersistentCache::inst().m_mtx); + if (sm_impl) { + auto& old_cache = sm_impl->m_cache; + if (old_cache.size() > 0) { + mgb_log_debug("find old persistent cache, now append to it!!"); + auto& new_cache = impl->m_cache; + CacheMap tmp_cache; + + //! CacheMap do not imp deepcopy and = operator, so we insert manually + auto insert = [](CacheMap& dst, CacheMap& in) { + for (auto& x : in) { + auto category = x.first; + for (auto& y : x.second) { + auto& key = y.first; + auto& value = y.second; + BlobStorage key_storage; + key_storage.init_data_ref(key).init_hash(); + dst[category][std::move(key_storage)].init_data_ref(value); + } + } + }; + insert(tmp_cache, old_cache); + insert(tmp_cache, new_cache); + + impl->m_cache = std::move(tmp_cache); + } else { + mgb_log_debug("do not find any old persistent cache"); + } + } +} + +PersistentCache::BlobStorage& PersistentCache::BlobStorage::init_data_ref( + const Blob& b) { + data_refhold = std::make_unique(b.size + 1); + memcpy(data_refhold.get(), b.ptr, b.size); + data_refhold.get()[b.size] = 0; // for C-string safety + ptr = data_refhold.get(); + size = b.size; + return *this; +} + +PersistentCache::BlobStorage& PersistentCache::BlobStorage::init_hash() { + hash = XXHash{}.update(ptr, size).digest(); + return *this; +} + +bool PersistentCache::BlobStorage::operator==(const BlobStorage& rhs) const { + return size == rhs.size && !memcmp(ptr, rhs.ptr, size); +} + std::string PersistentCache::make_category_from_comp_node(CompNode comp_node) { auto&& env = CompNodeEnv::from_comp_node(comp_node); switch (env.property().type) { @@ -65,26 +117,6 @@ std::string PersistentCache::make_category_from_comp_node(CompNode comp_node) { // ================= InMemoryPersistentCache ================== using Blob = PersistentCache::Blob; -InMemoryPersistentCache::BlobStorage& InMemoryPersistentCache::BlobStorage:: - init_data_ref(const Blob& b) { - data_refhold = std::make_unique(b.size + 1); - memcpy(data_refhold.get(), b.ptr, b.size); - data_refhold.get()[b.size] = 0; // for C-string safety - ptr = data_refhold.get(); - size = b.size; - return *this; -} - -InMemoryPersistentCache::BlobStorage& InMemoryPersistentCache::BlobStorage:: - init_hash() { - hash = XXHash{}.update(ptr, size).digest(); - return *this; -} - -bool InMemoryPersistentCache::BlobStorage::operator==(const BlobStorage& rhs) const { - return size == rhs.size && !memcmp(ptr, rhs.ptr, size); -} - Maybe InMemoryPersistentCache::get(const std::string& category, const Blob& key) { decltype(m_cache.begin()) iter0; { diff --git a/src/core/include/megbrain/utils/infile_persistent_cache.h b/src/core/include/megbrain/utils/infile_persistent_cache.h index 926c525d0..d68727c4b 100644 --- a/src/core/include/megbrain/utils/infile_persistent_cache.h +++ b/src/core/include/megbrain/utils/infile_persistent_cache.h @@ -17,33 +17,6 @@ class InFilePersistentCache final : public PersistentCache { class InputFile; class InputMemory; class OutputFile; - struct BlobStorage : public Blob { - std::unique_ptr data_refhold; - size_t hash = 0; - - template - BlobStorage& init_from_input(Input& inp); - void write_to_file(OutputFile& out_file) const; - BlobStorage& init_data_ref(const Blob& b); - - BlobStorage& init_hash() { - hash = XXHash{}.update(ptr, size).digest(); - return *this; - } - - bool operator==(const BlobStorage& rhs) const { - return size == rhs.size && !memcmp(ptr, rhs.ptr, size); - } - - struct Hash { - size_t operator()(const BlobStorage& b) const { return b.hash; } - }; - }; - std::unordered_map< - std::string, - std::unordered_map> - m_cache; - MGB_MUTEX m_mtx; std::shared_ptr m_always_open_file; template @@ -68,13 +41,6 @@ public: MGE_WIN_DECLSPEC_FUC void put( const std::string& category, const Blob& key, const Blob& value) override; bool support_dump_cache() override { return true; } - - std::unordered_map< - std::string, - std::unordered_map> - get_cache() { - return std::move(m_cache); - } }; } // namespace mgb diff --git a/src/core/include/megbrain/utils/persistent_cache.h b/src/core/include/megbrain/utils/persistent_cache.h index 8e7b68b51..911b93342 100644 --- a/src/core/include/megbrain/utils/persistent_cache.h +++ b/src/core/include/megbrain/utils/persistent_cache.h @@ -23,6 +23,41 @@ public: size_t size; }; + struct BlobStorage : public Blob { + std::unique_ptr data_refhold; + size_t hash = 0; + + BlobStorage& init_data_ref(const Blob& b); + + BlobStorage& init_hash(); + + bool operator==(const BlobStorage& rhs) const; + + struct Hash { + size_t operator()(const BlobStorage& b) const { return b.hash; } + }; + + template + BlobStorage& init_from_input(Input& inp); + + template + void write_to_file(OutputFile& out_file) const; + }; + + typedef std::unordered_map< + std::string, + std::unordered_map> + CacheMap; + CacheMap m_cache; + + MGB_MUTEX m_mtx; + + //! will make m_cache empty + CacheMap get_cache() { return std::move(m_cache); } + + //! clear cache + MGE_WIN_DECLSPEC_FUC void clear_cache() { m_cache.clear(); } + virtual Maybe get(const std::string& category, const Blob& key) = 0; virtual void put( @@ -34,6 +69,9 @@ public: MGE_WIN_DECLSPEC_FUC static std::shared_ptr set_impl( std::shared_ptr impl); + //! merge sm_impl m_cache, use to append insert cache + MGE_WIN_DECLSPEC_FUC static void merge_old_cache(std::shared_ptr); + //! get the instance; the default implementation just caches in //! memory static PersistentCache& inst() { return *sm_impl; } @@ -48,32 +86,11 @@ public: * The implementation is thread safe. */ class InMemoryPersistentCache final : public PersistentCache { - struct BlobStorage : public PersistentCache::Blob { - std::unique_ptr data_refhold; - size_t hash = 0; - - BlobStorage& init_data_ref(const Blob& b); - - BlobStorage& init_hash(); - - bool operator==(const BlobStorage& rhs) const; - - struct Hash { - size_t operator()(const BlobStorage& b) const { return b.hash; } - }; - }; - MGE_WIN_DECLSPEC_FUC Maybe get( const std::string& category, const Blob& key) override; MGE_WIN_DECLSPEC_FUC void put( const std::string& category, const Blob& key, const Blob& value) override; - std::unordered_map< - std::string, - std::unordered_map> - m_cache; - MGB_MUTEX m_mtx; - public: MGE_WIN_DECLSPEC_FUC InMemoryPersistentCache() = default; }; diff --git a/src/opr/test/dnn/convolution.cpp b/src/opr/test/dnn/convolution.cpp index 8d5882054..2686874d0 100644 --- a/src/opr/test/dnn/convolution.cpp +++ b/src/opr/test/dnn/convolution.cpp @@ -9,6 +9,7 @@ #include "megbrain/test/autocheck.h" #include "megbrain/test/helper.h" #include "megbrain/test/megdnn_helper.h" +#include "megbrain/utils/infile_persistent_cache.h" #include "megdnn/algorithm_cache.h" #include "megdnn/dtype.h" #include "megdnn/oprs/base.h" @@ -354,6 +355,10 @@ TEST(TestOprDNN, ConvBiasExePolicy) { HostTensorND host_y; auto func = graph->compile({make_callback_copy(conv_bias, host_y)}); func->execute(); + //! force clear all PersistentCache by get_cache + PersistentCache::inst().clear_cache(); + size_t old_size = PersistentCache::inst().get_cache().size(); + ASSERT_EQ(old_size, 0); //! set a new cache PersistentCache::set_impl(std::make_shared()); }; @@ -372,6 +377,64 @@ TEST(TestOprDNN, ConvBiasExePolicy) { PersistentCache::set_impl(orig_impl); } +TEST(TestOprDNN, PersistentCacheAppend) { + PersistentCache::inst().clear_cache(); + auto orig_impl = + PersistentCache::set_impl(std::make_shared()); + + auto orig_impl_size = orig_impl->get_cache().size(); + + auto category_a = "test_category_a"; + std::vector blob_key{1, 2, 3, 4, 5, 6, 7, 8}; + std::vector blob_value{-1, -2, -3, -4, -5, -6, -7, -8}; + PersistentCache::Blob key = {.ptr = blob_key.data(), .size = blob_key.size()}; + PersistentCache::Blob value = {.ptr = blob_value.data(), .size = blob_value.size()}; + + //! trigger call InMemoryPersistentCache put + PersistentCache::inst().put(category_a, key, value); + + auto now_size = PersistentCache::inst().get_cache().size(); + + //! assert new key not in InMemoryPersistentCache imp + ASSERT_EQ(orig_impl_size + 1, now_size); + + //! trigger append call InFilePersistentCache init + PersistentCache::set_impl(std::make_shared()); + auto size_after_restore = PersistentCache::inst().get_cache().size(); + + //! assert key not in InFilePersistentCache imp + //! as memory instance do cache do not sync cache to file + ASSERT_EQ(size_after_restore, orig_impl_size); + + auto t_file_imp = std::make_shared(); + auto category_b = "test_category_b"; + //! trigger call InFilePersistentCache put + t_file_imp->put(category_b, key, value); + //! set new file imp + PersistentCache::set_impl(t_file_imp); + + //! trigger InFilePersistentCache append init + auto old_cache = + PersistentCache::set_impl(std::make_shared()); + //! assert set_impl return old cache exactly + ASSERT_EQ(old_cache->m_cache.size(), now_size); + //! test key get + auto get_value = PersistentCache::inst().get(category_b, key); + ASSERT_TRUE( + !memcmp(get_value.val().ptr, blob_value.data(), + blob_value.size() * sizeof(int8_t))); + + size_after_restore = PersistentCache::inst().get_cache().size(); + //! assert key still in orig_impl imp + ASSERT_EQ(size_after_restore, now_size); + + //! restore old impl, may memory or file, trigger may memory append init + PersistentCache::set_impl(orig_impl); + size_after_restore = PersistentCache::inst().get_cache().size(); + //! assert key not in orig_impl imp, caused by get_cache will clear m_cache + ASSERT_EQ(size_after_restore + 1, now_size); +} + TEST(TestOprDNN, ConvBiasExePolicy_Quantized8Asym) { using Param = opr::ConvBias::Param; Param param; -- GitLab