Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 76 additions & 11 deletions src/amdgpu/gpu_ep.cc
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
// Copyright (c) Advanced Micro Devices, Inc.
// SPDX-License-Identifier: MIT

#include <filesystem>

#include "gpu_info.h"
#include "gpu_ep.h"

#include "gpu_options.h"
#include "mgx_options.h"

#include "common/telemetry.h"

#define EP_CALL_T(backend, fn, defval, ...) \
do { \
return (backend != nullptr && \
Expand Down Expand Up @@ -35,6 +39,23 @@

namespace gpu_ep {

namespace {

telemetry::Backend BackendForProfile(Profile profile) noexcept {
switch (profile) {
case Profile::Eager:
case Profile::DirectML:
return telemetry::Backend::DirectML;
case Profile::Auto:
case Profile::Optimized:
case Profile::MIGraphX:
return telemetry::Backend::MIGraphX;
}
return telemetry::Backend::MIGraphX;
}

} // namespace

ExecutionProvider::ExecutionProvider(ProviderFactory& factory, std::string_view ep_name,
const Ort::ConstSessionOptions& session_options, const OrtLogger* logger)
: OrtEp{ORT_API_VERSION},
Expand Down Expand Up @@ -103,6 +124,15 @@ ExecutionProvider::ExecutionProvider(ProviderFactory& factory, std::string_view
}

const ProviderInfo info{provider_options};
backend_ = BackendForProfile(info.profile);

telemetry::Config telemetry_config;
telemetry_config.enabled = info.telemetry_enable.value_or(false);
telemetry_config.file = info.telemetry_file.value_or(info.telemetry_dir.has_value());
if (info.telemetry_dir.has_value() && !info.telemetry_dir->empty()) {
telemetry_config.directory = ToPathString(*info.telemetry_dir);
}
telemetry_.emplace(std::move(telemetry_config), &factory_.TelemetryWriter());

const auto create_directml_backend = [&] {
THROW_IF_ERROR(factory.CreateDirectMLBackend(local_session_options, logger, backend_ep_));
Expand Down Expand Up @@ -172,16 +202,14 @@ ExecutionProvider::ExecutionProvider(ProviderFactory& factory, std::string_view
THROW_IF_ERROR(factory.CreateMIGraphXBackend(local_session_options, logger, backend_ep_));
};

if (info.profile == Profile::Eager) {
create_directml_backend();
} else if (info.profile == Profile::DirectML) {
create_directml_backend();
} else if (info.profile == Profile::MIGraphX) {
create_migraphx_backend();
} else if (info.profile == Profile::Hip) {
create_hip_backend();
} else {
create_migraphx_backend();
switch (backend_) {
case telemetry::Backend::DirectML:
create_directml_backend();
break;
case telemetry::Backend::MIGraphX:
case telemetry::Backend::Unknown:
create_migraphx_backend();
break;
}
ort_api.ReleaseSessionOptions(local_session_options);
}
Expand Down Expand Up @@ -213,7 +241,44 @@ Ort::Status ExecutionProvider::GetCapability(const OrtGraph* graph,
Ort::Status ExecutionProvider::Compile(const OrtGraph** graphs, const OrtNode** fused_nodes, size_t count,
OrtNodeComputeInfo** node_compute_infos, OrtNode** ep_context_nodes) const noexcept
{
EP_CALL_S(backend_ep_, Compile, graphs, fused_nodes, count, node_compute_infos, ep_context_nodes);
if (backend_ep_ == nullptr) {
return MAKE_STATUS(ORT_EP_FAIL, "Compile: invalid backend");
}
if (backend_ep_->Compile != nullptr) {
RETURN_IF_ERROR(backend_ep_->Compile(backend_ep_, graphs, fused_nodes, count,
node_compute_infos, ep_context_nodes));
}
if (count > 0 && graphs != nullptr) {
LogTelemetry(Ort::ConstGraph{graphs[0]});
}
return STATUS_OK;
}

void ExecutionProvider::LogTelemetry(const Ort::ConstGraph& graph) const noexcept try {
if (!telemetry_ || !telemetry_->IsEnabled()) {
return;
}
std::call_once(telemetry_once_, [&] {
// Generic, backend-agnostic fields collected by the wrapper.
telemetry::Record record;
record.SetEpVersion(factory_.GetVersion())
.SetBackend(backend_)
.SetParentProcess(telemetry::ParentProcessName());
const std::filesystem::path model_path{graph.GetModelPath()};
if (model_path.has_filename()) {
record.SetModelName(model_path.filename().string());
}
if (const telemetry::GetBackendDataFn collect = factory_.GetBackendTelemetryFn();
collect != nullptr) {
telemetry::BackendData data{};
if (collect(backend_ep_, &data)) {
record.Merge(data);
}
}
telemetry_->Write(record);
});
} catch (const std::exception&) {
// Telemetry must never disrupt inference.
}

void ExecutionProvider::ReleaseNodeComputeInfos(OrtNodeComputeInfo** node_compute_info,
Expand Down
11 changes: 11 additions & 0 deletions src/amdgpu/gpu_ep.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@

#pragma once

#include <mutex>
#include <optional>
#include <string>

#include "common/telemetry.h"

#include "gpu_info.h"
#include "gpu_factory.h"

Expand Down Expand Up @@ -34,10 +40,15 @@ struct ExecutionProvider : OrtEp, ApiPtrs {
[[nodiscard]] const char* GetCompiledModelCompatibilityInfo(const OrtGraph* graph) const;
Ort::Status GetKernelRegistry(const OrtKernelRegistry** kernel_registry) const;

void LogTelemetry(const Ort::ConstGraph& graph) const noexcept;

ProviderFactory& factory_;
OrtEp* backend_ep_{};

std::string ep_name_;
telemetry::Backend backend_{telemetry::Backend::Unknown};
std::optional<telemetry::Logger> telemetry_;
mutable std::once_flag telemetry_once_;
const Ort::Logger logger_{};
};

Expand Down
15 changes: 15 additions & 0 deletions src/amdgpu/gpu_factory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@ ProviderFactory::ProviderFactory(const ApiPtrs& api_ptrs, const OrtApiBase* ort_
THROW_IF_ERROR(GetSymbolFromLibrary(dml_backend_,
"CreateEpFactories", reinterpret_cast<void**>(&dml_create_ep_factories)));

// Optional: a backend may export a telemetry collector. Absence is fine.
if (!GetSymbolFromLibrary(dml_backend_, telemetry::kGetBackendDataSymbol,
reinterpret_cast<void**>(&dml_get_telemetry_)).IsOK()) {
dml_get_telemetry_ = nullptr;
}

size_t factories_created{};
// Pass ep_name_ (e.g. "amdgpu") so the directml backend registers its kernels,
// allocators, and node assignments under the same name ORT sees for this EP.
Expand All @@ -143,6 +149,12 @@ ProviderFactory::ProviderFactory(const ApiPtrs& api_ptrs, const OrtApiBase* ort_
THROW_IF_ERROR(GetSymbolFromLibrary(mgx_backend_,
"CreateEpFactories", reinterpret_cast<void**>(&mgx_create_ep_factories)));

// Optional: a backend may export a telemetry collector. Absence is fine.
if (!GetSymbolFromLibrary(mgx_backend_, telemetry::kGetBackendDataSymbol,
reinterpret_cast<void**>(&mgx_get_telemetry_)).IsOK()) {
mgx_get_telemetry_ = nullptr;
}

THROW_IF_ERROR(mgx_create_ep_factories(kMIGraphXBackend, ort_api_base, default_logger,
&mgx_ep_factory_, 1, &factories_created));

Expand All @@ -164,6 +176,9 @@ ProviderFactory::ProviderFactory(const ApiPtrs& api_ptrs, const OrtApiBase* ort_
}

ProviderFactory::~ProviderFactory() {

telemetry_writer_.Stop();

// Destroy members that hold backend function pointers before unloading the DLLs.
// ~Allocator calls backend_ep_factory_->ReleaseAllocator and ~DataTransfer calls
// backend factory methods — both would crash if the DLL is already unloaded.
Expand Down
19 changes: 18 additions & 1 deletion src/amdgpu/gpu_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include "gpu_allocator.h"
#include "gpu_data_transfer.h"

#include "common/telemetry.h"

namespace gpu_ep {

struct ProviderFactory : OrtEpFactory, ApiPtrs {
Expand All @@ -15,12 +17,14 @@ struct ProviderFactory : OrtEpFactory, ApiPtrs {
Ort::Status CreateDirectMLBackend(const OrtSessionOptions* session_options, const OrtLogger* logger, OrtEp*& ep) {
RETURN_IF_ERROR(dml_ep_factory_->CreateEp(dml_ep_factory_, nullptr, nullptr, 0, session_options, logger, &ep));
backend_ep_factory_ = dml_ep_factory_;
backend_get_telemetry_ = dml_get_telemetry_;
return STATUS_OK;
}

Ort::Status CreateMIGraphXBackend(const OrtSessionOptions* session_options, const OrtLogger* logger, OrtEp*& ep) {
RETURN_IF_ERROR(mgx_ep_factory_->CreateEp(mgx_ep_factory_, nullptr, nullptr, 0, session_options, logger, &ep));
backend_ep_factory_ = mgx_ep_factory_;
backend_get_telemetry_ = mgx_get_telemetry_;
return STATUS_OK;
}

Expand All @@ -39,6 +43,16 @@ struct ProviderFactory : OrtEpFactory, ApiPtrs {
return backend_ep_factory_;
}

// Telemetry collector exported by the active backend DLL, or null if that
// backend contributes no backend-specific telemetry.
[[nodiscard]] telemetry::GetBackendDataFn GetBackendTelemetryFn() const noexcept {
return backend_get_telemetry_;
}

[[nodiscard]] telemetry::FileWriter& TelemetryWriter() noexcept { return telemetry_writer_; }

[[nodiscard]] const char* GetVersion() const;

private:
[[nodiscard]] const char* GetVendor() const;
[[nodiscard]] const char* GetName() const;
Expand All @@ -53,7 +67,6 @@ struct ProviderFactory : OrtEpFactory, ApiPtrs {
void ReleaseEp(OrtEp* ep) const;

[[nodiscard]] uint32_t GetVendorId() const;
[[nodiscard]] const char* GetVersion() const;

// Ort::Status ValidateCompiledModelCompatibilityInfo(const std::vector<Ort::ConstHardwareDevice>& devices,
// std::string_view compatibility_info, OrtCompiledModelCompatibility* model_compatibility);
Expand All @@ -80,6 +93,8 @@ struct ProviderFactory : OrtEpFactory, ApiPtrs {
Ort::Status GetCustomOpDomains(OrtCustomOpDomain** domains, size_t num_domains) const;

OrtEpFactory* backend_ep_factory_{};
telemetry::GetBackendDataFn backend_get_telemetry_{};
telemetry::FileWriter telemetry_writer_;
const Ort::Logger default_logger_{};

std::string ep_name_;
Expand All @@ -92,11 +107,13 @@ struct ProviderFactory : OrtEpFactory, ApiPtrs {
ReleaseEpFactory_t dml_release_ep_factory_{};

OrtEpFactory* dml_ep_factory_{};
telemetry::GetBackendDataFn dml_get_telemetry_{};

void* mgx_backend_{};
ReleaseEpFactory_t mgx_release_ep_factory_{};

OrtEpFactory* mgx_ep_factory_{};
telemetry::GetBackendDataFn mgx_get_telemetry_{};

void* hip_backend_{};
ReleaseEpFactory_t hip_release_ep_factory_{};
Expand Down
4 changes: 3 additions & 1 deletion src/amdgpu/gpu_info.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ ProviderInfo::ProviderInfo(const ProviderOptions& provider_options) {
.AddAssignmentToReference(provider_option::kForceRecompile, force_recompile)
.AddAssignmentToReference(provider_option::kExhaustiveTune, exhaustive_tune)
.AddAssignmentToReference(provider_option::kMlssUseSpecificOps, mlss_use_specific_ops)
.AddAssignmentToReference(provider_option::kModelArch, model_arch)
.AddAssignmentToReference(provider_option::kTelemetryEnable, telemetry_enable)
.AddAssignmentToReference(provider_option::kTelemetryFile, telemetry_file)
.AddAssignmentToReference(provider_option::kTelemetryDir, telemetry_dir)
.Parse(provider_options));
}

Expand Down
4 changes: 3 additions & 1 deletion src/amdgpu/gpu_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ struct ProviderInfo {
std::optional<bool> exhaustive_tune{};
std::optional<fs::path> cache_dir{};
std::optional<std::string> mlss_use_specific_ops{};
std::optional<std::string> model_arch{};
std::optional<bool> telemetry_enable{};
std::optional<bool> telemetry_file{};
std::optional<std::string> telemetry_dir{};

ProviderInfo() = default;

Expand Down
4 changes: 3 additions & 1 deletion src/amdgpu/gpu_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ constexpr auto kExhaustiveTune = "exhaustive_tune"sv;
constexpr auto kProfile = "profile"sv;
constexpr auto kCacheDir = "cache_dir"sv;
constexpr auto kMlssUseSpecificOps = "mlss_use_specific_ops"sv;
constexpr auto kModelArch = "model_arch"sv;
constexpr auto kTelemetryEnable = "telemetry_enable"sv;
constexpr auto kTelemetryFile = "telemetry_file"sv;
constexpr auto kTelemetryDir = "telemetry_dir"sv;
} // provider_option

} // gpu_ep
4 changes: 2 additions & 2 deletions src/migraphx/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ target_link_libraries(migraphx-ep PRIVATE migraphx::c hip-shared flatbuffers)

if(WIN32)
set_property(TARGET migraphx-ep APPEND_STRING
PROPERTY LINK_FLAGS /DEF:${PROJECT_SOURCE_DIR}/src/shared/symbols.def)
PROPERTY LINK_FLAGS /DEF:${PROJECT_SOURCE_DIR}/src/migraphx/symbols.def)

set(MGX_FILES
"$<TARGET_FILE_DIR:migraphx::migraphx>/amdmlss.dll"
Expand Down Expand Up @@ -68,7 +68,7 @@ if(WIN32)
DESTINATION "." OPTIONAL)
else()
set_property(TARGET migraphx-ep APPEND_STRING
PROPERTY LINK_FLAGS "-Xlinker --version-script=${PROJECT_SOURCE_DIR}/src/shared/version_script.lds -Xlinker --gc-sections")
PROPERTY LINK_FLAGS "-Xlinker --version-script=${PROJECT_SOURCE_DIR}/src/migraphx/version_script.lds -Xlinker --gc-sections")

install(TARGETS migraphx-ep
DESTINATION ${CMAKE_INSTALL_BINDIR})
Expand Down
Loading