Files
2026-07-13 12:40:42 +08:00

278 lines
9.2 KiB
C++

// Copyright (c) 2023 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 "paddle/fluid/framework/new_executor/interpreter_base_impl.h"
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
#include "paddle/phi/kernels/autotune/gpu_timer.h"
#endif
namespace paddle {
namespace framework {
///
/// \brief Derived Class to interpret the instructions transformed
/// from legacy ProgramDesc.
///
class ProgramInterpreter : public InterpreterBaseImpl {
using ExecutionConfig = interpreter::ExecutionConfig;
using InstructionSchedulingPriorityLess = std::function<bool(size_t, size_t)>;
using SchedulingQueue =
std::priority_queue<size_t,
std::vector<size_t>,
InstructionSchedulingPriorityLess>;
public:
ProgramInterpreter(
const Place& place,
const BlockDesc& block,
Scope* scope,
const ExecutionConfig& execution_config = ExecutionConfig());
~ProgramInterpreter();
paddle::framework::FetchList Run(const std::vector<std::string>& feed_names,
const std::vector<DenseTensor>& feed_tensors,
bool need_fetch = true,
bool enable_job_schedule_profiler = false,
bool switch_stream = false) override;
paddle::framework::FetchList Run(const std::vector<std::string>& feed_names,
bool need_fetch = true,
bool enable_job_schedule_profiler = false,
bool enable_op_profiling = false,
bool switch_stream = false) override;
std::shared_ptr<ProgramDesc> GetMutableCopyProgram() override;
void Build(const std::vector<std::string>& feed_names,
std::vector<paddle::framework::OpFuncNode>* op_func_nodes,
bool switch_stream = false) override;
void ShareWorkQueueFrom(InterpreterBaseImpl* src) override;
void ShareBuildResultsFrom(const InterpreterBaseImpl& src) override;
// op dependences
const interpreter::DependencyBuilder& GetDependencyBuilder() const;
std::shared_ptr<std::vector<size_t>> GetDependencyCount() const override;
const interpreter::StreamAnalyzer& GetStreamAnalyzer() const;
bool IsSharedResultsBuild() const override;
void SetCopyProgram(std::shared_ptr<ProgramDesc> prog) override;
void SetSkipGcVars(const std::set<std::string>& skip_gc_vars) override;
const std::set<std::string>& JitInputVars() const override;
void SetJitInputVars(const std::set<std::string>& jit_input_vars) override;
const VariableScope* GetVariableScope() const override;
void reset_scope(Scope* new_scope) override;
const Scope* local_scope() const override;
const Place& GetPlace() const override { return place_; }
void SetOutputHooks(const std::vector<HookFunc>& hookfuncs) override {
output_hookfuncs_ = hookfuncs;
}
void SetInputHooks(const std::vector<HookFunc>& hookfuncs) override {
input_hookfuncs_ = hookfuncs;
}
void SetOutputHooks(const std::vector<PirHookFunc>& hookfuncs) override {}
void SetInputHooks(const std::vector<PirHookFunc>& hookfuncs) override {}
std::unordered_map<std::string, std::shared_ptr<EventInter>>*
GetForceEventsToWaitInfo() {
return force_events_to_wait_;
}
void SetForceEventsToWaitInfo(
std::unordered_map<std::string, std::shared_ptr<EventInter>>*
force_events_to_wait) {
force_events_to_wait_ = force_events_to_wait;
}
bool IsStaticBuild() const override { return static_build_; }
std::tuple<double, double> InterpreterRunTime() override;
void SetCUDAGraphState(uint8_t cuda_graph_state) override {
PADDLE_THROW(common::errors::Unavailable(
"ProgramInterpreter does not support SetCUDAGraphState, "
"please use PirInterpreter instead."));
}
// Only for debug
Variable* DebugVar(const std::string& name) const override;
private:
// build graph
void Convert(std::vector<paddle::framework::OpFuncNode>* op_func_nodes);
void BuildOperatorDependences();
void BuildAndCacheInstructionCtx(Instruction* instr_node);
void BuildSkipShareLoDInfo();
void UpdateSyncOpNum();
void AnalyseExecuteOrderForTrace();
// inplace
void BuildInplace();
bool BuildInplaceCheckVarIsOnlyInput(
const std::vector<std::vector<size_t>>& input_var2op, size_t var_index);
void SetFeedVarsInplaceSkip(const std::vector<std::string>& feed_names);
// cuda graph
void CheckCUDAGraphBeforeRun(const std::vector<std::string>& feed_names);
void PrepareForCUDAGraphCapture();
// execution
void RunImpl();
void ExecuteInstructionList(const std::vector<Instruction>& vec_instr);
void RunInstructionAsync(size_t instr_id);
void RunInstruction(const Instruction& instr_node);
void RunNextInstructions(const Instruction& instr_id,
SchedulingQueue* reserved_next_ops);
PADDLE_API void RunOperator(const Instruction& instr_node);
// Trace
void TraceInstructionList(const std::vector<Instruction>& vec_instr);
// only used when program contains no feed op
void Prepare(const std::vector<std::string>& feed_names,
const std::vector<DenseTensor>& feed_tensors,
bool prepare_feed,
bool switch_stream = false);
void RecordMemcpyD2H(const Instruction& instr_node);
// gc
void RecordStreamForGC(const Instruction& instr);
void CheckGC(const Instruction& instr);
void ClearDenseTensorArrayInLocalScope();
// workqueue
std::shared_ptr<interpreter::AsyncWorkQueue> GetWorkQueue();
// scope
bool HasLocalScope() const;
// For log and debug
std::string GetDepsString() const;
bool is_build_{false};
bool static_build_{false};
// Note(sonder): share the op dependency and event analysis procedure.
bool is_shared_results_build_{false};
// op profiling status
bool is_in_op_profiling_mode_{false};
const Place place_;
const BlockDesc& block_; // not owned
interpreter::DependencyBuilder dependency_builder_;
interpreter::StreamAnalyzer stream_analyzer_;
// NOTE(zhiqiu): when add fetch ops in GetInterpreterCore, we will
// copy a new program and block, the copy_program_ here is used to
// hold the program, otherwise block_ maybe not valid after the
// new program is deleted.
std::shared_ptr<ProgramDesc> copy_program_{nullptr};
// from variable scope
std::vector<Variable*> var_list_;
std::map<std::string, int> name2id_;
std::vector<VariableMetaInfo> vec_meta_info_;
std::vector<Instruction> vec_instruction_; // deconstruct before OpFuncNode
std::atomic<size_t> unfinished_op_number_{0};
ExecutionConfig execution_config_;
std::unordered_map<std::string, std::shared_ptr<EventInter>>*
force_events_to_wait_;
VariableScope var_scope_;
Scope* local_scope_{nullptr}; // not owned
EventsWaiter main_thread_blocker_;
std::shared_ptr<interpreter::AsyncWorkQueue> async_work_queue_;
details::ExceptionHolder exception_holder_;
std::shared_ptr<EventsWaiter::EventNotifier> exception_notifier_{nullptr};
std::shared_ptr<EventsWaiter::EventNotifier> completion_notifier_{nullptr};
std::unique_ptr<InterpreterCoreGarbageCollector> gc_;
// last_live_ops_[i] contains the id of operators that last access the i-th
// var
std::map<size_t, std::set<size_t>> last_live_ops_;
// (*dependency_count_)[i] contains the number of dependencies that the i-th
// op need to wait
std::shared_ptr<std::vector<size_t>> dependency_count_;
std::vector<std::shared_ptr<interpreter::OpDepInfo>> deps_;
std::vector<std::shared_ptr<interpreter::VarRefInfo>> refs_;
// used for Trace
int64_t sync_op_num_{-1};
std::vector<size_t> trace_execute_order_;
InstructionSchedulingPriorityLess instruction_scheduling_priority_less;
std::vector<HookFunc> output_hookfuncs_;
std::vector<HookFunc> input_hookfuncs_;
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
std::unique_ptr<phi::CalculateStreamTimer> calculate_stream_timer_;
#endif
size_t last_calculate_instr_id_;
bool enable_job_schedule_profiler_;
};
static inline const DenseTensor& GetTensorFromVar(const Variable* var) {
if (var->IsType<DenseTensor>()) {
return var->Get<DenseTensor>();
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Variable must be type of DenseTensor, but received %s.",
framework::ToTypeName(var->Type())));
}
}
static inline DenseTensor* GetMutableTensorFromVar(Variable* var) {
if (var->IsType<DenseTensor>()) {
return var->GetMutable<DenseTensor>();
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"Variable must be type of DenseTensor, but received %s.",
framework::ToTypeName(var->Type())));
}
}
} // namespace framework
} // namespace paddle