GitOrigin-RevId: 7a427bdab4
tags/v1.11.0
| @@ -120,22 +120,13 @@ InFilePersistentCache::BlobStorage& InFilePersistentCache::BlobStorage::init_fro | |||
| return *this; | |||
| } | |||
| template <typename OutputFile> | |||
| 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<uint8_t[]>(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 <typename Input> | |||
| @@ -21,10 +21,62 @@ std::shared_ptr<PersistentCache> PersistentCache::sm_impl = | |||
| std::shared_ptr<PersistentCache> PersistentCache::set_impl( | |||
| std::shared_ptr<PersistentCache> impl) { | |||
| mgb_assert(impl); | |||
| merge_old_cache(impl); | |||
| sm_impl.swap(impl); | |||
| return impl; | |||
| } | |||
| void PersistentCache::merge_old_cache(std::shared_ptr<PersistentCache> 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<uint8_t[]>(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<uint8_t[]>(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<Blob> InMemoryPersistentCache::get(const std::string& category, const Blob& key) { | |||
| decltype(m_cache.begin()) iter0; | |||
| { | |||
| @@ -17,33 +17,6 @@ class InFilePersistentCache final : public PersistentCache { | |||
| class InputFile; | |||
| class InputMemory; | |||
| class OutputFile; | |||
| struct BlobStorage : public Blob { | |||
| std::unique_ptr<uint8_t[]> data_refhold; | |||
| size_t hash = 0; | |||
| template <typename Input> | |||
| 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<BlobStorage, BlobStorage, BlobStorage::Hash>> | |||
| m_cache; | |||
| MGB_MUTEX m_mtx; | |||
| std::shared_ptr<OutputFile> m_always_open_file; | |||
| template <typename Input> | |||
| @@ -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<BlobStorage, BlobStorage, BlobStorage::Hash>> | |||
| get_cache() { | |||
| return std::move(m_cache); | |||
| } | |||
| }; | |||
| } // namespace mgb | |||
| @@ -23,6 +23,41 @@ public: | |||
| size_t size; | |||
| }; | |||
| struct BlobStorage : public Blob { | |||
| std::unique_ptr<uint8_t[]> 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 <typename Input> | |||
| BlobStorage& init_from_input(Input& inp); | |||
| template <typename OutputFile> | |||
| void write_to_file(OutputFile& out_file) const; | |||
| }; | |||
| typedef std::unordered_map< | |||
| std::string, | |||
| std::unordered_map<BlobStorage, BlobStorage, BlobStorage::Hash>> | |||
| 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<Blob> 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<PersistentCache> set_impl( | |||
| std::shared_ptr<PersistentCache> impl); | |||
| //! merge sm_impl m_cache, use to append insert cache | |||
| MGE_WIN_DECLSPEC_FUC static void merge_old_cache(std::shared_ptr<PersistentCache>); | |||
| //! 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<uint8_t[]> 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<Blob> 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<BlobStorage, BlobStorage, BlobStorage::Hash>> | |||
| m_cache; | |||
| MGB_MUTEX m_mtx; | |||
| public: | |||
| MGE_WIN_DECLSPEC_FUC InMemoryPersistentCache() = default; | |||
| }; | |||
| @@ -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<InMemoryPersistentCache>()); | |||
| }; | |||
| @@ -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<InMemoryPersistentCache>()); | |||
| auto orig_impl_size = orig_impl->get_cache().size(); | |||
| auto category_a = "test_category_a"; | |||
| std::vector<int8_t> blob_key{1, 2, 3, 4, 5, 6, 7, 8}; | |||
| std::vector<int8_t> 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<InFilePersistentCache>()); | |||
| 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<InFilePersistentCache>(); | |||
| 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<InFilePersistentCache>()); | |||
| //! 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; | |||