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

248 lines
7.1 KiB
C++

// Copyright (c) 2021 CINN 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 <dlfcn.h>
#include <fstream>
#include <memory>
#include <mutex>
#include <string>
#include <string_view>
#include "paddle/cinn/backends/llvm/codegen_llvm.h"
#include "paddle/cinn/backends/llvm/execution_engine.h"
#include "paddle/cinn/backends/llvm/simple_jit.h"
#include "paddle/cinn/hlir/framework/graph_compiler_util.h"
#include "paddle/cinn/lang/packed_func.h"
#ifdef CINN_WITH_CUDA
#include "paddle/cinn/runtime/cuda/cuda_module.h"
#endif
#ifdef CINN_WITH_CUSTOM_DEVICE
#include "paddle/cinn/runtime/custom_device/custom_device_backend_api.h"
#endif
#ifdef CINN_WITH_HIP
#include "paddle/cinn/runtime/hip/hip_module.h"
#endif
#ifdef CINN_WITH_SYCL
#include "paddle/cinn/runtime/sycl/sycl_module.h"
#endif
namespace cinn {
namespace backends {
/**
* A class for dumping the code after compilation.
* Use FLAGS_cinn_dump_group_lowered_func to specify the directory to dump
* lowered function. Use FLAGS_cinn_dump_group_source_code to specify the
* directory to dump the source code. Use FLAGS_cinn_dump_group_ptx to specify
* the directory to dump ptx. Use FLAGS_cinn_dump_group_instruction to specify
* the directory to dump instruction.
*/
class CompilationInfoDumper {
public:
explicit CompilationInfoDumper(const hlir::framework::CompilationResult& info,
const int device_id)
: info_(info), device_id_(device_id) {
DumpLoweredFunc();
DumpSourceCode();
DumpPtxCode();
DumpInstruction();
}
static void DumpLoweredFuncByGroupIndex(const ir::LoweredFunc& lowered_func,
const int gidx,
const int device_id);
static void DumpSourceCodeByGroupIndex(const std::string& source_code,
const int gidx,
const int device_id);
static void DumpPtxCodeByGroupIndex(const std::string& source_ptx,
const int gidx,
const int device_id);
private:
void DumpLoweredFunc();
void DumpSourceCode();
void DumpPtxCode();
void DumpInstruction();
static void Dump(const std::string& base_path,
const int idx,
const int device_id,
const std::string& file_name,
const std::string& content);
const hlir::framework::CompilationResult& info_;
const int device_id_;
};
class SourceCodePrint {
public:
static SourceCodePrint* GetInstance() {
static SourceCodePrint print;
return &print;
}
void write(const std::string& source_code);
private:
SourceCodePrint();
~SourceCodePrint();
std::ofstream of;
std::mutex mtx_;
};
class Compiler final {
public:
static std::unique_ptr<Compiler> Create(const Target& target) {
return std::unique_ptr<Compiler>(new Compiler(target));
}
/**
* Compile and link to a CINN module.
*/
void Build(const ir::Module& module, const std::string& code = "");
void AppendCX86(const ir::Module& module);
void AppendBroadcastSwitchModule(const ir::Module& module);
void EndCompile();
void ExportObject(const std::string& path);
std::string GetSourceCode(const ir::Module& module);
void BuildDefault(const ir::Module& module);
/**
* Retrieve a function by \p fn_name.
* @return function address or null if not exists.
*/
void* Lookup(std::string_view fn_name);
std::vector<void*> GetFnPtr() const { return fn_ptr_; }
/**
* Set pir fusion hash
*/
void SetFusionHash(size_t hash) { fusion_hash_ = hash; }
/**
* Get pir fusion hash
*/
size_t GetFusionHash() const { return fusion_hash_; }
std::string GetDeviceId() const;
void LoadAndRegisterFromCache();
~Compiler() {
#ifdef CINN_WITH_CUDA
// Release GPU Resource: CUDA module handle
if (cuda_module_handle_) {
CUresult result =
cuModuleUnload(static_cast<CUmodule>(cuda_module_handle_));
if (result != CUDA_SUCCESS) {
LOG(WARNING) << "Failed to unload CUDA module. Error code: " << result;
}
cuda_module_handle_ = nullptr;
}
#endif
// Release CPU Resource: dynamic library handle
if (dynamic_library_handle_) {
int result = dlclose(dynamic_library_handle_);
if (result != 0) {
LOG(WARNING) << "Error closing dynamic library handle for "
<< dynamic_library_path_ << ". Error: " << dlerror();
}
dynamic_library_handle_ = nullptr;
}
}
private:
// do not register device symbol until end=true for build function
void RegisterDeviceModuleSymbol();
void RegisterCudaModuleSymbol();
void RegisterCustomDeviceModuleSymbol();
void RegisterHipModuleSymbol();
void RegisterSyclModuleSymbol();
void CompileCudaModule(const ir::Module& module,
const std::string& code = "");
void CompileCustomDeviceModule(const ir::Module& module,
const std::string& code = "");
void CompileHipModule(const ir::Module& module, const std::string& code = "");
void CompileSyclModule(const ir::Module& module,
const std::string& code = "");
void CompileX86Module(const ir::Module& module);
explicit Compiler(const Target& target)
: target_(target), engine_(ExecutionEngine::Create(ExecutionOptions())) {}
CINN_DISALLOW_COPY_AND_ASSIGN(Compiler);
private:
Target target_;
std::unique_ptr<ExecutionEngine> engine_;
std::vector<void*> fn_ptr_;
// only heterogeneous systems need to record device func and module
std::vector<std::string> device_fn_name_;
std::string device_fn_code_;
// kernel cache control
size_t fusion_hash_{0};
// dynamic library support
std::string dynamic_library_path_;
void* dynamic_library_handle_{nullptr};
#ifdef CINN_WITH_CUDA
std::unique_ptr<runtime::cuda::CUDAModule> cuda_module_;
void* cuda_module_handle_{nullptr};
#endif
#ifdef CINN_WITH_CUSTOM_DEVICE
std::unique_ptr<runtime::CustomModule> device_module_;
#endif
#ifdef CINN_WITH_HIP
std::unique_ptr<runtime::hip::HIPModule> hip_module_;
#endif
#ifdef CINN_WITH_SYCL
std::unique_ptr<runtime::sycl::SYCLModule> sycl_module_;
#endif
// Dynamic library helper methods
std::string GetCachePath() const;
#ifdef CINN_WITH_CUDA
std::string GetDeviceArch();
std::string GetComputeArch();
std::string GenerateObjectWithoutCache(const std::string& source_code);
std::string GenerateFatbinWithoutCache();
void SaveKernelNamesToMeta();
void LoadKernelNamesFromMeta();
#endif
};
} // namespace backends
} // namespace cinn