diff --git a/src/core/include/megbrain/utils/persistent_cache.h b/src/core/include/megbrain/utils/persistent_cache.h index 1e00bf76..523a4ad6 100644 --- a/src/core/include/megbrain/utils/persistent_cache.h +++ b/src/core/include/megbrain/utils/persistent_cache.h @@ -130,7 +130,7 @@ namespace mgb { }; struct ResultEntry { - std::string algo; //! identifier of the algorithm + std::string algo; //! serialized algo desc uint32_t attribute; //! algo attribute, e.g. reproducible double time; //! execution time in seconds size_t workspace; //! workspace in bytes diff --git a/src/opr/impl/search_policy/algo_chooser.cpp b/src/opr/impl/search_policy/algo_chooser.cpp index 9951aa32..9df0320f 100644 --- a/src/opr/impl/search_policy/algo_chooser.cpp +++ b/src/opr/impl/search_policy/algo_chooser.cpp @@ -45,7 +45,7 @@ using namespace mgb; // timeout delta to be added with fastest known algorithm for new algos constexpr double TIMEOUT_TOLERANCE = 2; -#define CACHE_KEY_VERSION "v4" +#define CACHE_KEY_VERSION "v5" namespace { template @@ -278,6 +278,47 @@ std::vector flatten_search_space( return ret; } +//! serialize a algo's desc to string. format is +//! handle_type|algo_type|size_of_param|size_of_name|string_of_param|string_of_name +static void serialize_write_pod(const Algorithm::Info::Desc& val, + std::string& result) { + megdnn::Algorithm::serialize_write_pod(val.handle_type, result); + megdnn::Algorithm::serialize_write_pod(val.type, result); + uint32_t param_size = val.param.size(); + uint32_t name_size = val.name.size(); + megdnn::Algorithm::serialize_write_pod(param_size, result); + megdnn::Algorithm::serialize_write_pod(name_size, result); + result += val.param; + result += val.name; +} + +static Algorithm::Info::Desc deserialize_read_pod(const std::string& data, + size_t offset = 0) { + Algorithm::Info::Desc ret; +#define cb(_val, _type) \ + _val = megdnn::Algorithm::deserialize_read_pod<_type>(data.data(), \ + offset); \ + offset += sizeof(_val) + + cb(ret.handle_type, megdnn::Handle::HandleType); + cb(ret.type, uint32_t); + + uint32_t param_size = 0; + uint32_t name_size = 0; + cb(param_size, uint32_t); + cb(name_size, uint32_t); + + if (param_size > 0) { + ret.param = std::string(data.data() + offset, param_size); + offset += param_size; + } + if (name_size > 0) { + ret.name = std::string(data.data() + offset, name_size); + offset += name_size; + } + return ret; +} + } // namespace namespace mgb { @@ -360,6 +401,16 @@ AlgoChooser::AlgoChooserHelper::choose_by_profile( } } + typename AlgoChooser::ImplExecutionPolicy tmp_policy; + bool retrive_from_cache = true; + bool allow_log = false; + construct_execution_policy(selected_strategy, tmp_policy, + retrive_from_cache, allow_log); + if (tmp_policy.algo.valid()) { + // return policy when contruct successed + return tmp_policy; + } + if (enable_update) { CircularDepsChecker circular_deps_checker; auto&& search_items = @@ -378,13 +429,13 @@ AlgoChooser::AlgoChooserHelper::choose_by_profile( } typename AlgoChooser::ImplExecutionPolicy policy; - construct_execution_policy(selected_strategy, true, policy); + construct_execution_policy(selected_strategy, policy); return policy; MIDOUT_E } template -typename AlgoChooser::ImplAlgo +typename AlgoChooser::ImplAlgoDesc AlgoChooser::AlgoChooserHelper::get_profile_result_from_cache( const ExecutionStrategy& selected_strategy) const { MIDOUT_B(Opr, midout_iv(MGB_HASH_STR("get_profile_result_from_cache"))) @@ -401,12 +452,6 @@ AlgoChooser::AlgoChooserHelper::get_profile_result_from_cache( if (prof.empty()) return {}; - std::unordered_map algo_map; - for (auto i : get_all_candidates()) { - auto ins = algo_map.emplace(i.desc.name.c_str(), i); - mgb_assert(ins.second, "duplicated algo name: %s", i.desc.name.c_str()); - } - auto target_attr = extract_algo_attribute(selected_strategy); bool skip_by_negative = false; for (auto&& i : prof) { @@ -418,17 +463,8 @@ AlgoChooser::AlgoChooserHelper::get_profile_result_from_cache( static_cast(attr_of_algo & target_attr.second); if (contain_attr_all_positive) { if (!contain_attr_any_negative) { - auto iter = algo_map.find(i.algo); - mgb_assert( - iter != algo_map.end(), - "algorithm %s exists in profiling result but not in " - "algo_map; please report this bug; opr: %s{%s}, " - "layouts: %s ", - i.algo.c_str(), m_base_mgb_opr->cname(), - m_base_mgb_opr->dyn_typeinfo()->name, - format_fixlayouts(m_layouts, arity_in, arity_out) - .c_str()); - return iter->second; + Algorithm::Info::Desc algo_desc = deserialize_read_pod(i.algo); + return algo_desc; } else { skip_by_negative = true; } @@ -454,29 +490,35 @@ AlgoChooser::AlgoChooserHelper::get_profile_result_from_cache( template void AlgoChooser::AlgoChooserHelper::construct_execution_policy( - const ExecutionStrategy& selected_strategy, bool retrive_from_cache, - typename AlgoChooser::ImplExecutionPolicy& policy) const { + const ExecutionStrategy& selected_strategy, + typename AlgoChooser::ImplExecutionPolicy& policy, + bool retrive_from_cache, bool allow_log) const { MIDOUT_B(Opr, midout_iv(MGB_HASH_STR("construct_execution_policy"))) if (!policy.algo.valid()) { if (retrive_from_cache) { - policy.algo = get_profile_result_from_cache(selected_strategy).desc; + policy.algo = get_profile_result_from_cache(selected_strategy); if (!policy.algo.valid()) { - auto target_attr = extract_algo_attribute(selected_strategy); - std::string layouts_str = - format_fixlayouts(m_layouts, arity_in, arity_out); - std::string msg = ssprintf( - "(mbg_opr : %s, layouts %s, with attribute(%s) and " - "without attribute(%s)", - m_base_mgb_opr->dyn_typeinfo()->name, - layouts_str.c_str(), - Algorithm::attribute_str(target_attr.first).c_str(), - Algorithm::attribute_str(target_attr.second).c_str()); - mgb_log_warn( - "No algo get from cache for %s. This may caused by " - "mismatch with model and cache file. ex. profiling " - "with version1, but inferencing on version2 or " - "profiling modelA but inferencing modelB", - msg.c_str()); + if (allow_log) { + auto target_attr = + extract_algo_attribute(selected_strategy); + std::string layouts_str = format_fixlayouts( + m_layouts, arity_in, arity_out); + std::string msg = ssprintf( + "(mbg_opr : %s, layouts %s, with attribute(%s) and " + "without attribute(%s)", + m_base_mgb_opr->dyn_typeinfo()->name, + layouts_str.c_str(), + Algorithm::attribute_str(target_attr.first).c_str(), + Algorithm::attribute_str(target_attr.second) + .c_str()); + mgb_log_warn( + "No algo get from cache for %s. This may caused by " + "mismatch with model and cache file or imcomplete " + "cache file. ex. profiling with version1, but " + "inferencing on version2 or profiling modelA but " + "inferencing modelB", + msg.c_str()); + } return; } } else { @@ -513,8 +555,8 @@ void AlgoChooser::AlgoChooserHelper::construct_execution_policy( m_allow_weight_preprocess); policy.sub_policy.push_back({}); sub_helper.construct_execution_policy(selected_strategy, - retrive_from_cache, - policy.sub_policy.back()); + policy.sub_policy.back(), + retrive_from_cache, allow_log); if (!policy.sub_policy.back().algo.valid()) { // means sub_helper.construct_execution_policy fails. clean up // policy.algo and return @@ -606,17 +648,22 @@ AlgoChooser::AlgoChooserHelper::profile_single_algo( param.allow_weight_preprocess = m_allow_weight_preprocess; Algorithm* palgo = m_megdnn_opr->get_algorithm_from_desc(policy.algo); - mgb_assert(palgo, "Unknown algo description"); + mgb_assert(palgo, "can not find algo when profile single algo"); + auto rst = TimedProfiler::profile(param, timeout); // MIOpen conv profiles all available algos when a specfic shape is // provided for the first time, which probably adds to the result time. // Therefore, a second profile execution is needed. - if (strncmp(palgo->name(), "MIOpen", 6) == 0) + if (strncmp(palgo->name(), "MIOpen", 6) == 0) { rst = TimedProfiler::profile(param, timeout); + } if (!rst.valid()) return None; + + std::string algo_desc; + serialize_write_pod(policy.algo, algo_desc); return AlgoChooserProfileCache::ResultEntry{ - palgo->name(), static_cast(palgo->attribute()), + algo_desc, static_cast(palgo->attribute()), rst.val().time, param.workspace}; MIDOUT_E } @@ -655,7 +702,9 @@ void AlgoChooser::AlgoChooserHelper::profile( } //! check workspace limit - construct_execution_policy(selected_strategy, true, policy); + construct_execution_policy(selected_strategy, policy); + mgb_assert(policy.algo.valid(), + "construct execution policy must success when profiling"); if (get_workspace_size_bytes(policy) >= workspace_limit) { continue; } @@ -779,15 +828,15 @@ AlgoChooser::AlgoChooserHelper::extract_algo_attribute( AlgoChooser::AlgoChooserHelper::choose_by_profile( \ const ExecutionStrategy& select_strategy, bool enable_update) \ const; \ - template typename AlgoChooser::ImplAlgo \ + template typename AlgoChooser::ImplAlgoDesc \ AlgoChooser::AlgoChooserHelper:: \ get_profile_result_from_cache( \ const ExecutionStrategy& select_strategy) const; \ template void \ AlgoChooser::AlgoChooserHelper::construct_execution_policy( \ - const ExecutionStrategy& select_strategy, bool retrive_from_cache, \ - typename AlgoChooser::ImplExecutionPolicy& policy) \ - const; \ + const ExecutionStrategy& select_strategy, \ + typename AlgoChooser::ImplExecutionPolicy& policy, \ + bool retrive_from_cache, bool allow_log) const; \ template size_t \ AlgoChooser::AlgoChooserHelper::get_workspace_size_bytes( \ const typename AlgoChooser::ImplExecutionPolicy& \ @@ -856,7 +905,8 @@ size_t AlgoChooser::setup_algo(const FixedTensorLayouts& layouts, policy = algo_choose_hook(mgb_opr); auto strategy = ExecutionStrategy::HEURISTIC | ExecutionStrategy::REPRODUCIBLE; - helper.construct_execution_policy(strategy, false, policy); + bool retrive_from_cache = false; + helper.construct_execution_policy(strategy, policy, retrive_from_cache); } if (!policy.algo.valid()) { policy = get_policy(helper); diff --git a/src/opr/include/megbrain/opr/search_policy/algo_chooser.h b/src/opr/include/megbrain/opr/search_policy/algo_chooser.h index 986cd668..60a7e6ff 100644 --- a/src/opr/include/megbrain/opr/search_policy/algo_chooser.h +++ b/src/opr/include/megbrain/opr/search_policy/algo_chooser.h @@ -61,6 +61,7 @@ class AlgoChooser { static constexpr int arity = OprArityTrait::arity; using ImplAlgo = typename Opr::AlgorithmInfo; + using ImplAlgoDesc = typename Opr::AlgorithmInfo::Desc; using ImplExecutionPolicy = megdnn::ExecutionPolicy; using MGBOpr = typename MegDNNOpr2MGBOpr::MGBOpr; @@ -120,7 +121,7 @@ public: bool enable_update) const; //! get all profile algorithm from cache, return invalid if not exists - ImplAlgo get_profile_result_from_cache( + ImplAlgoDesc get_profile_result_from_cache( const ExecutionStrategy& selected_strategy) const; /** @@ -130,11 +131,13 @@ public: * \param[in,out] policy execution policy * \param retrive_from_cache retrive algo from cache if set True, get * from heuristic otherwise. - * \return true if contruct success and false when fail + * \param allow_log no warning log print if set True, print warning info + * otherwise. */ void construct_execution_policy( const ExecutionStrategy& selected_strategy, - bool retrive_from_cache, ImplExecutionPolicy& policy) const; + ImplExecutionPolicy& policy, bool retrive_from_cache = true, + bool allow_log = true) const; //! get workspace size required for specific execution policy size_t get_workspace_size_bytes(