// Original TunableOp is from onnxruntime. // https://github.com/microsoft/onnxruntime/blob/main/onnxruntime/core/framework/tunable.h // https://github.com/microsoft/onnxruntime/tree/main/onnxruntime/core/providers/rocm/tunable // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. // // Adapting TunableOp into PyTorch // Copyright (c) Advanced Micro Devices, Inc. // #pragma once #include #include #include #include #include #include #include #include #include #include #include namespace at::cuda::tunable { namespace detail { struct MaybeDelete { bool owns_pointer; void operator()(std::ostream* os) const { if (owns_pointer) delete os; } }; using OstreamPtr = std::unique_ptr; static OstreamPtr get_stream(std::string filename) { if (filename.compare("out") == 0) { return OstreamPtr { &std::cout, MaybeDelete {false} }; } else if (filename.compare("err") == 0) { return OstreamPtr { &std::cerr, MaybeDelete {false} }; } else { return OstreamPtr { new std::ofstream {filename.c_str()}, MaybeDelete {true} }; } } } static void TunableLog(int level, const std::string& msg) { static const char *env_file = getenv("PYTORCH_TUNABLEOP_VERBOSE_FILENAME"); static const char *env_verbose = getenv("PYTORCH_TUNABLEOP_VERBOSE"); static int level_user = env_verbose ? atoi(env_verbose) : 0; static auto streamptr = detail::get_stream(env_file ? env_file : "err"); if (level_user >= level) { (*streamptr) << msg < KernelMap; typedef std::unordered_map ResultsMap; struct TORCH_CUDA_CPP_API TuningResults { // Validates if these results are compatible with the libraries std::unordered_map validators; // Mapping from Callable signature to Callable's tuning result ResultsMap results; }; class TORCH_CUDA_CPP_API TuningResultsManager { public: TuningResultsManager() = default; ~TuningResultsManager() = default; KernelMap Lookup(const std::string& op_signature); ResultEntry Lookup(const std::string& op_signature, const std::string& params_signature); inline void AddImpl(const std::string& op_signature, const std::string& params_signature, ResultEntry best, KernelMap& kernel_map); void Add(const std::string& op_signature, const std::string& params_signature, ResultEntry best); void Delete(const std::string& op_signature, const std::string& params_signature); inline void DisjointMergeImpl( const std::string& op_signature, const KernelMap& kernel_map, /*out*/ ResultsMap& results); void Load(const ResultsMap& results_to_load); ResultsMap Dump(); void DisjointMerge(const std::string& op_signature, const KernelMap& kernel_map); size_t GetSize(); private: std::mutex lock_; ResultsMap results_; }; class TORCH_CUDA_CPP_API TuningResultsValidator { public: using GetFunc = std::function; using ValidateFunc = std::function; using GetValidateFuncs = std::unordered_map>; TuningResultsValidator(); ~TuningResultsValidator() = default; std::unordered_map GetAllValidators() const; TuningStatus ValidateAll(const std::unordered_map& to_validate) const; void RegisterValidator(const std::string& key, const GetFunc& gf, const ValidateFunc& vf); protected: std::string GetPyTorchVersion() const; TuningStatus ValidatePyTorchVersion(const std::string& value) const; public: static constexpr const std::array mandatory_keys{"PT_VERSION"}; private: GetValidateFuncs validators_; }; class TORCH_CUDA_CPP_API TuningContext { public: TuningContext(); ~TuningContext(); TuningContext(TuningContext &) = delete; TuningContext(TuningContext &&) = delete; TuningContext &operator=(TuningContext &) = delete; TuningContext &operator=(TuningContext &&) = delete; void EnableTunableOp(bool value); bool IsTunableOpEnabled() const; void EnableTuning(bool value); bool IsTuningEnabled() const; void EnableNumericsCheck(bool value); bool IsNumericsCheckEnabled() const; void SetMaxTuningDurationMs(int max_duration_ms); int GetMaxTuningDurationMs() const; void SetMaxTuningIterations(int max_iter); int GetMaxTuningIterations() const; void SetMaxWarmupDurationMs(int max_duration_ms); int GetMaxWarmupDurationMs() const; void SetMaxWarmupIterations(int max_iter); int GetMaxWarmupIterations() const; void EnableICacheFlush(bool value); bool IsICacheFlushEnabled() const; void SetRotatingBufferSize(int size); int GetRotatingBufferSize() const; TuningResultsManager& GetTuningResultsManager(); TuningResultsValidator& GetTuningResultsValidator(); TuningResults GetTuningResults(); TuningStatus LoadTuningResults(const TuningResults& tr); void SetFilename(const std::string& filename, bool insert_device_ordinal=false); std::string GetFilename() const; void WriteFileOnExit(bool value); bool ReadFile(const std::string& filename={}); bool WriteFile(const std::string& filename={}); private: bool enable_; bool tuning_enable_; bool manager_initialized_; bool write_file_on_exit_; bool numerics_check_enable_; int max_tuning_duration_ms_; int max_tuning_iterations_; int max_warmup_duration_ms_; int max_warmup_iterations_; bool icache_flush_; int rotating_buffer_size_; mutable TuningResultsManager manager_; mutable c10::once_flag manager_init_once_; TuningResultsValidator validator_; std::string filename_; size_t results_count_from_input_file_; }; TORCH_CUDA_CPP_API TuningContext* getTuningContext(); class ITimer { public: ITimer() = default; virtual ~ITimer() = default; virtual void Start() = 0; virtual void End() = 0; /// Computes the elapsed time in milliseconds between Start() and End() virtual float Duration() = 0; }; } // namespace at::cuda::tunable