Files
paddlepaddle--paddle/paddle/fluid/eager/api/utils/global_utils.h
T
2026-07-13 12:40:42 +08:00

300 lines
9.6 KiB
C++

// Copyright (c) 2021 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 <atomic>
#include <memory>
#include "paddle/fluid/eager/grad_node_info.h"
#include "paddle/fluid/eager/hooks.h"
#include "paddle/fluid/eager/type_defs.h"
#include "paddle/fluid/imperative/tracer.h"
#include "paddle/phi/api/ext/op_meta_info.h"
#include "paddle/utils/small_vector.h"
#include "paddle/utils/test_macros.h"
namespace egr {
class UniqueNameGenerator {
public:
explicit UniqueNameGenerator(std::string prefix = "") : prefix_(prefix) {}
std::string Generate(std::string key = "eager_tmp") {
return prefix_ + key + "_" + std::to_string(id_++);
}
private:
std::atomic<int> id_{0};
std::string prefix_;
};
// Global
// TODO(jiabin): Now we are using imperative tracer, move it here when we
// deprecate imperative.
class GradNodeBase;
class Controller {
public:
TEST_API static Controller& Instance();
phi::Place GetExpectedPlace() const { return tracer_->ExpectedPlace(); }
TEST_API void SetExpectedPlace(const phi::Place& place);
void SetAMPLevel(paddle::imperative::AmpLevel level) {
tracer_->SetAmpLevel(level);
}
paddle::imperative::AmpLevel GetAMPLevel() const {
return tracer_->GetAmpLevel();
}
TEST_API void SetUsePromote(bool use_promote);
TEST_API bool GetUsePromote() const;
TEST_API bool UseLayoutAutoTune();
void DisableLayoutAutoTune() { tracer_->DisableLayoutAutoTune(); }
void EnableLayoutAutoTune() { tracer_->EnableLayoutAutoTune(); }
void SetPythonStack(std::string stack_str) {
tracer_->SetPythonStack(stack_str);
}
std::string GetPythonStack() { return tracer_->GetPythonStack(); }
bool HasGrad() const { return tracer_->HasGrad(); }
void SetHasGrad(bool has_grad) { tracer_->SetHasGrad(has_grad); }
std::string GenerateUniqueName(std::string key = "eager_in_tmp") {
return tracer_->GenerateUniqueName(key);
}
const std::shared_ptr<paddle::imperative::Tracer>& GetCurrentTracer() {
return tracer_;
}
void SetCurrentTracer(
const std::shared_ptr<paddle::imperative::Tracer>& tracer) {
tracer_ = tracer;
VLOG(6) << "Set current tracer for Controller: " << tracer_;
}
const std::shared_ptr<paddle::imperative::AmpAttrs>& GetCurrentAmpAttrs() {
return paddle::imperative::GetCurrentAmpAttrs();
}
const std::unordered_map<std::string, std::vector<paddle::OpMetaInfo>>&
GetOpMetaInfoMap() {
return op_meta_info_map_;
}
void MergeOpMetaInfoMap(
const std::unordered_map<std::string, std::vector<paddle::OpMetaInfo>>&
map) {
for (const auto& [key, value] : map) {
if (op_meta_info_map_.count(key)) {
VLOG(3) << "Replacing existing OpMetaInfo for op: " << key;
}
VLOG(3) << "Merging OpMetaInfo for op: " << key;
op_meta_info_map_[key] = value;
}
}
std::unordered_map<std::string,
std::vector<std::vector<std::unordered_map<int, int>>>>&
GetCustomEdgesSlotMap() {
return custom_edges_slot_map_;
}
// For Cpp Hook
void RegisterBackwardFinalHook(const std::function<void()>& call_back) {
VLOG(6) << "RegisterBackwardFinalHook";
final_backward_hooks_.emplace_back(
std::make_shared<CppVoidHook>(std::move(call_back)));
VLOG(6) << "Size: " << final_backward_hooks_.size();
}
// For Python hook
void RegisterBackwardFinalHook(const std::shared_ptr<VoidHook>& call_back) {
final_backward_hooks_.emplace_back(call_back);
}
const std::vector<std::shared_ptr<VoidHook>>& FinalBackwardHooks() const {
return final_backward_hooks_;
}
void ClearFinalBackwardHooks() { final_backward_hooks_.clear(); }
void ClearForceSequentialNodes() { force_sequential_nodes_.clear(); }
void PushBackForceSequentialNodes(GradNodeBase* node) {
force_sequential_nodes_.push_back(node);
}
void EraseForceSequentialNodes(GradNodeBase* node) {
for (auto iter = force_sequential_nodes_.begin();
iter != force_sequential_nodes_.end();
++iter) {
if (*iter == node) {
force_sequential_nodes_.erase(iter);
return;
}
}
}
std::list<GradNodeBase*> GetForceSequentialNodes() {
return force_sequential_nodes_;
}
TEST_API void SetIsInBackward(bool is_in_backward);
TEST_API bool GetIsInBackward() const;
private:
Controller() = default;
static Controller* controller_;
static thread_local std::shared_ptr<paddle::imperative::Tracer> tracer_;
std::unordered_map<std::string, std::vector<paddle::OpMetaInfo>>
op_meta_info_map_;
/* op_type : {{{grad_outputs}, {grad_inputs}, {input}, {output}, {attrs}},
* {{grad_outputs}, {grad_inputs}, {input}, {output}, {attrs}}}*/
std::unordered_map<std::string,
std::vector<std::vector<std::unordered_map<int, int>>>>
custom_edges_slot_map_;
std::vector<std::shared_ptr<VoidHook>> final_backward_hooks_;
std::list<GradNodeBase*> force_sequential_nodes_;
bool is_in_backward_{false};
DISABLE_COPY_AND_ASSIGN(Controller);
};
class EagerBackwardStateGuard {
public:
EagerBackwardStateGuard() { Controller::Instance().SetIsInBackward(true); }
~EagerBackwardStateGuard() { Controller::Instance().SetIsInBackward(false); }
};
class EagerBackwardSubGraphNodeRecorder {
public:
/**
* @brief Get the singleton instance of EagerBackwardSubGraphNodeRecorder
* @return Reference to the singleton instance
*
* Uses static local variable for thread-safe singleton initialization
* (C++11 guarantee). The instance is created on first call and destroyed
* automatically at program termination.
*/
static EagerBackwardSubGraphNodeRecorder& Instance() {
static EagerBackwardSubGraphNodeRecorder instance;
return instance;
}
public:
void AddGradNode(const GradNodeBase* node) {
if (need_capture_viz_subgraph_) viz_nodes_.insert(node);
if (need_capture_vlog_subgraph_) {
vlog_nodes_.insert(node);
// record the node's vlog level
node_to_vlog_level_[node] = subgraph_bwd_vlog_level_;
}
}
bool NeedCaptureSubGraph() {
return need_capture_viz_subgraph_ || need_capture_vlog_subgraph_;
}
void StartCaptureSubGraphForViz() { need_capture_viz_subgraph_ = true; }
void StopCaptureSubGraphForViz() { need_capture_viz_subgraph_ = false; }
void StartCaptureSubGraphForVlog() { need_capture_vlog_subgraph_ = true; }
void StopCaptureSubGraphForVlog() { need_capture_vlog_subgraph_ = false; }
void SetDumpDirPath(const std::string& path) { dump_dir_path_ = path; }
const std::string& GetDumpDirPath() { return dump_dir_path_; }
void SetNeedDumpGradTensors(bool need_dump) {
need_dump_grad_tensors_ = need_dump;
}
bool GetNeedDumpGradTensors() { return need_dump_grad_tensors_; }
int GetSubGraphBwdVlogLevel(const GradNodeBase* node) {
auto it = node_to_vlog_level_.find(node);
if (it != node_to_vlog_level_.end()) {
return it->second;
}
return 0;
}
void SetSubGraphBwdVlogLevel(int level) { subgraph_bwd_vlog_level_ = level; }
// Is Gradnode within the scope of backward vlog guard
bool IsGradNodeInVlogGuard(GradNodeBase* node) {
return vlog_nodes_.count(node);
}
bool IsGradNodeInVizGuard(const GradNodeBase* node) {
return viz_nodes_.count(node);
}
bool NeedDumpBwdSubGraph() {
return !viz_nodes_.empty() && !dump_dir_path_.empty();
}
bool NeedBwdVlogGuard() { return !vlog_nodes_.empty(); }
private:
std::unordered_set<const GradNodeBase*> viz_nodes_;
std::unordered_set<const GradNodeBase*> vlog_nodes_;
std::unordered_map<const GradNodeBase*, int> node_to_vlog_level_;
std::string dump_dir_path_;
bool need_capture_vlog_subgraph_ = false;
bool need_capture_viz_subgraph_ = false;
bool need_dump_grad_tensors_ = false;
int subgraph_bwd_vlog_level_ = 0;
};
/**
* @class LogIndent
* @brief Singleton class for managing log indentation levels globally
*
* This class implements the singleton pattern to provide a centralized way
* to manage indentation levels for formatted log output. It ensures only
* one instance exists throughout the application lifecycle.
*/
class LogIndent {
public:
/**
* @brief Get the singleton instance of LogIndent
* @return Reference to the singleton instance
*
* Uses static local variable for thread-safe singleton initialization
* (C++11 guarantee). The instance is created on first call and destroyed
* automatically at program termination.
*/
static LogIndent& Instance() {
static LogIndent instance;
return instance;
}
/**
* @brief Increase the current indentation level by 1
*
* Call this method when entering a nested scope to increase
* log indentation for better visual hierarchy.
*/
void IncreaseIndentLevel() { FLAGS_indentlevel = FLAGS_indentlevel + 1; }
/**
* @brief Decrease the current indentation level by 1
*
* Reduces the indentation level, but never goes below 0.
* Call this when leaving a nested scope.
*/
void DecreaseIndentLevel() {
if (FLAGS_indentlevel > 0) {
FLAGS_indentlevel = FLAGS_indentlevel - 1;
}
}
LogIndent(const LogIndent&) = delete;
LogIndent& operator=(const LogIndent&) = delete;
private:
LogIndent() = default;
~LogIndent() = default;
};
} // namespace egr