// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #include #include #include #include #include #include #include #include #include "paddle/common/macros.h" #include "paddle/fluid/framework/op_proto_maker.h" #include "paddle/fluid/framework/program_desc.h" #include "paddle/fluid/framework/scope.h" #include "paddle/utils/string/string_helper.h" #include "paddle/fluid/ir_adaptor/translator/program_translator.h" #include "paddle/pir/include/core/dialect.h" #include "paddle/pir/include/core/ir_context.h" #include "paddle/pir/include/core/program.h" COMMON_DECLARE_bool(enable_pir_in_executor); COMMON_DECLARE_bool(enable_pir_with_pt_in_dy2st); namespace paddle { namespace framework { namespace ir { class Graph; } class InterpreterCore; namespace details { void AppendSkipDeletionVars(const std::vector& append_vars, std::set* all_vars); // TODO(Aurelius84) : Need remove skip_no_need_buffer after cinn fix this // problem. std::set ParseSafeEagerDeletionSkipVarsSet( const ProgramDesc& backward_program, bool skip_no_need_buffer = false); } // namespace details int64_t hash_with_seed(int64_t value, int64_t seed); class InterpreterCoreInfo { public: struct CacheValue { std::shared_ptr core_{nullptr}; std::set skip_eager_delete_vars_; std::unique_ptr ir_prog_{nullptr}; }; bool IsAvailable(bool is_grad) const { const auto& core = is_grad ? backward_info_.core_ : forward_info_.core_; return core != nullptr; } CacheValue& GetMutable(bool is_grad) { return is_grad ? backward_info_ : forward_info_; } private: CacheValue forward_info_; CacheValue backward_info_; }; class InterpreterCoreInfoCacheKey { public: InterpreterCoreInfoCacheKey(int64_t program_id, const framework::Scope* scope, int64_t place_hash_key, bool use_cuda_graph = false, int64_t cuda_graph_dispatch_key = 0, bool is_grad = false, bool in_pir_mode = false) : program_id_(program_id), scope_(scope), place_hash_key_(place_hash_key), use_cuda_graph_(use_cuda_graph), cuda_graph_dispatch_key_(cuda_graph_dispatch_key), is_grad_(is_grad), in_pir_mode_(in_pir_mode) {} int64_t hash() const { int64_t hash_result = program_id_; if (in_pir_mode_) { int64_t scope_i = reinterpret_cast(scope_); hash_result = hash_with_seed(hash_result, scope_i); hash_result = hash_with_seed(hash_result, place_hash_key_); // CUDA Graph is available in pir mode only hash_result = hash_with_seed(hash_result, static_cast(use_cuda_graph_)); hash_result = hash_with_seed(hash_result, cuda_graph_dispatch_key_); } return hash_result; } bool is_grad() const { return is_grad_; } InterpreterCoreInfoCacheKey with_pir_mode(bool in_pir_mode) const { // Create a new key with the specified PIR mode if the current key's // PIR mode is different from the specified one. Otherwise, return // the current key itself. This function is used to switch legacy IR // and PT mode. if (in_pir_mode == in_pir_mode_) { return *this; } return InterpreterCoreInfoCacheKey(program_id_, scope_, place_hash_key_, use_cuda_graph_, cuda_graph_dispatch_key_, is_grad_, in_pir_mode); } private: int64_t program_id_; const framework::Scope* scope_; int64_t place_hash_key_; bool use_cuda_graph_; int64_t cuda_graph_dispatch_key_; bool is_grad_; bool in_pir_mode_; }; class InterpreterCoreInfoCache { public: static InterpreterCoreInfoCache& Instance(); bool Has(const InterpreterCoreInfoCacheKey& key) const { int64_t hash_key = key.hash(); return info_map_.find(hash_key) != info_map_.end() && info_map_.at(hash_key).IsAvailable(key.is_grad()); } InterpreterCoreInfo::CacheValue& GetMutable( const InterpreterCoreInfoCacheKey& key) { int64_t hash_key = key.hash(); return info_map_[hash_key].GetMutable(key.is_grad()); } void UpdateSkipEagerDeleteVars(const InterpreterCoreInfoCacheKey& key, const std::set& skip_vars) { auto& cached_value = GetMutable(key); cached_value.skip_eager_delete_vars_ = std::move(skip_vars); } std::set& GetSkipEagerDeleteVars( const InterpreterCoreInfoCacheKey& key) { auto& cached_value = GetMutable(key); return cached_value.skip_eager_delete_vars_; } size_t Size() const { return info_map_.size(); } void Finalize() { // NOTE(Aurelius84): DO NOT perform finalize in destructor // to avoid problems caused by destructor order of static // object. info_map_.clear(); } private: std::unordered_map info_map_; }; std::shared_ptr CreateProgramInterpreterCoreInfoToCache( const ProgramDesc& program_desc, const phi::Place& place, framework::Scope* scope, const InterpreterCoreInfoCacheKey& key); std::shared_ptr CreatePirInterpreterCoreInfoToCache( std::unique_ptr ir_prog, const phi::Place& place, framework::Scope* scope, const InterpreterCoreInfoCacheKey& key, bool used_for_sot); std::unique_ptr ApplyIrPass( pir::Program* program, phi::Place place, const std::set& no_need_buffer_names); std::unique_ptr ApplyRemoveShadowFeedPass( const std::unique_ptr program, const pir::Block* block, const phi::Place& place, const paddle::framework::Scope* scope); std::unique_ptr ConstructForwardIrProgram( const paddle::framework::BlockDesc* forward_global_block, const paddle::framework::BlockDesc* backward_global_block, const std::vector& output_names, const std::vector& x, const std::vector& x_names, const std::vector& params, const phi::Place& place); std::unique_ptr ConstructBackwardIrProgram( const paddle::framework::BlockDesc* backward_global_block, const std::vector& out_grad, const std::vector& x_grad, const std::vector& params_grad, const paddle::framework::Scope* scope, const phi::Place& place); } // namespace framework } // namespace paddle