#include "inc/rocprofiler.h" #include #include #include #include #include "core/context.h" #include "core/hsa_queue.h" #include "core/intercept_queue.h" #include "core/proxy_queue.h" #include "core/simple_proxy_queue.h" #include "util/exception.h" #include "util/hsa_rsrc_factory.h" #include "util/logger.h" #define PUBLIC_API __attribute__((visibility("default"))) #define CONSTRUCTOR_API __attribute__((constructor)) #define DESTRUCTOR_API __attribute__((destructor)) #define API_METHOD_PREFIX \ hsa_status_t status = HSA_STATUS_SUCCESS; \ try { #define API_METHOD_SUFFIX \ } \ catch (std::exception & e) { \ ERR_LOGGING(__FUNCTION__ << "(), " << e.what()); \ status = rocprofiler::GetExcStatus(e); \ } \ return status; /////////////////////////////////////////////////////////////////////////////////////////////////// // Internal library methods // namespace rocprofiler { decltype(hsa_queue_create)* hsa_queue_create_fn; decltype(hsa_queue_destroy)* hsa_queue_destroy_fn; decltype(hsa_signal_store_relaxed)* hsa_signal_store_relaxed_fn; decltype(hsa_signal_store_relaxed)* hsa_signal_store_screlease_fn; decltype(hsa_queue_load_write_index_relaxed)* hsa_queue_load_write_index_relaxed_fn; decltype(hsa_queue_store_write_index_relaxed)* hsa_queue_store_write_index_relaxed_fn; decltype(hsa_queue_load_read_index_relaxed)* hsa_queue_load_read_index_relaxed_fn; decltype(hsa_queue_load_write_index_scacquire)* hsa_queue_load_write_index_scacquire_fn; decltype(hsa_queue_store_write_index_screlease)* hsa_queue_store_write_index_screlease_fn; decltype(hsa_queue_load_read_index_scacquire)* hsa_queue_load_read_index_scacquire_fn; #ifdef ROCP_HSA_PROXY decltype(hsa_amd_queue_intercept_create)* hsa_amd_queue_intercept_create_fn; decltype(hsa_amd_queue_intercept_register)* hsa_amd_queue_intercept_register_fn; #endif ::HsaApiTable* kHsaApiTable; void SaveHsaApi(::HsaApiTable* table) { kHsaApiTable = table; hsa_queue_create_fn = table->core_->hsa_queue_create_fn; hsa_queue_destroy_fn = table->core_->hsa_queue_destroy_fn; hsa_signal_store_relaxed_fn = table->core_->hsa_signal_store_relaxed_fn; hsa_signal_store_screlease_fn = table->core_->hsa_signal_store_screlease_fn; hsa_queue_load_write_index_relaxed_fn = table->core_->hsa_queue_load_write_index_relaxed_fn; hsa_queue_store_write_index_relaxed_fn = table->core_->hsa_queue_store_write_index_relaxed_fn; hsa_queue_load_read_index_relaxed_fn = table->core_->hsa_queue_load_read_index_relaxed_fn; hsa_queue_load_write_index_scacquire_fn = table->core_->hsa_queue_load_write_index_scacquire_fn; hsa_queue_store_write_index_screlease_fn = table->core_->hsa_queue_store_write_index_screlease_fn; hsa_queue_load_read_index_scacquire_fn = table->core_->hsa_queue_load_read_index_scacquire_fn; #ifdef ROCP_HSA_PROXY hsa_amd_queue_intercept_create_fn = table->amd_ext_->hsa_amd_queue_intercept_create_fn; hsa_amd_queue_intercept_register_fn = table->amd_ext_->hsa_amd_queue_intercept_register_fn; #endif } void RestoreHsaApi() { ::HsaApiTable* table = kHsaApiTable; table->core_->hsa_queue_create_fn = hsa_queue_create_fn; table->core_->hsa_queue_destroy_fn = hsa_queue_destroy_fn; table->core_->hsa_signal_store_relaxed_fn = hsa_signal_store_relaxed_fn; table->core_->hsa_signal_store_screlease_fn = hsa_signal_store_screlease_fn; table->core_->hsa_queue_load_write_index_relaxed_fn = hsa_queue_load_write_index_relaxed_fn; table->core_->hsa_queue_store_write_index_relaxed_fn = hsa_queue_store_write_index_relaxed_fn; table->core_->hsa_queue_load_read_index_relaxed_fn = hsa_queue_load_read_index_relaxed_fn; table->core_->hsa_queue_load_write_index_scacquire_fn = hsa_queue_load_write_index_scacquire_fn; table->core_->hsa_queue_store_write_index_screlease_fn = hsa_queue_store_write_index_screlease_fn; table->core_->hsa_queue_load_read_index_scacquire_fn = hsa_queue_load_read_index_scacquire_fn; #ifdef ROCP_HSA_PROXY table->amd_ext_->hsa_amd_queue_intercept_create_fn = hsa_amd_queue_intercept_create_fn; table->amd_ext_->hsa_amd_queue_intercept_register_fn = hsa_amd_queue_intercept_register_fn; #endif } CONSTRUCTOR_API void constructor() { util::Logger::Create(); util::HsaRsrcFactory::Create(); } DESTRUCTOR_API void destructor() { rocprofiler::MetricsDict::Destroy(); util::HsaRsrcFactory::Destroy(); util::Logger::Destroy(); } hsa_status_t GetExcStatus(const std::exception& e) { const util::exception* rocprofiler_exc_ptr = dynamic_cast(&e); return (rocprofiler_exc_ptr) ? static_cast(rocprofiler_exc_ptr->status()) : HSA_STATUS_ERROR; } const MetricsDict* GetMetrics(const hsa_agent_t& agent) { rocprofiler::util::HsaRsrcFactory* hsa_rsrc = &rocprofiler::util::HsaRsrcFactory::Instance(); const rocprofiler::util::AgentInfo* agent_info = hsa_rsrc->GetAgentInfo(agent); if (agent_info == NULL) { EXC_RAISING(HSA_STATUS_ERROR, "agent is not found"); } const MetricsDict* metrics = MetricsDict::Create(agent_info); if (metrics == NULL) EXC_RAISING(HSA_STATUS_ERROR, "MetricsDict create failed"); return metrics; } util::Logger::mutex_t util::Logger::mutex_; util::Logger* util::Logger::instance_ = NULL; } /////////////////////////////////////////////////////////////////////////////////////////////////// // Public library methods // extern "C" { // HSA-runtime tool on-load method PUBLIC_API bool OnLoad(HsaApiTable* table, uint64_t runtime_version, uint64_t failed_tool_count, const char* const* failed_tool_names) { rocprofiler::SaveHsaApi(table); rocprofiler::ProxyQueue::InitFactory(); rocprofiler::InterceptQueue::SetTool(getenv("ROCP_TOOL_LIB")); // HSA intercepting if (getenv("ROCP_HSA_INTERCEPT") != NULL) { rocprofiler::InterceptQueue::HsaIntercept(table); rocprofiler::ProxyQueue::HsaIntercept(table); } return true; } // HSA-runtime tool on-unload method PUBLIC_API void OnUnload() { rocprofiler::RestoreHsaApi(); } // Returns the last error message PUBLIC_API hsa_status_t rocprofiler_error_string(const char** str) { API_METHOD_PREFIX *str = rocprofiler::util::Logger::LastMessage().c_str(); API_METHOD_SUFFIX } // Create new profiling context PUBLIC_API hsa_status_t rocprofiler_open(hsa_agent_t agent, rocprofiler_feature_t* features, uint32_t feature_count, rocprofiler_t** handle, uint32_t mode, rocprofiler_properties_t* properties) { API_METHOD_PREFIX rocprofiler::util::HsaRsrcFactory* hsa_rsrc = &rocprofiler::util::HsaRsrcFactory::Instance(); const rocprofiler::util::AgentInfo* agent_info = hsa_rsrc->GetAgentInfo(agent); if (agent_info == NULL) { EXC_RAISING(HSA_STATUS_ERROR, "agent is not found"); } rocprofiler::Queue* queue = NULL; if (mode != 0) { if (mode & ROCPROFILER_MODE_STANDALONE) { if (mode & ROCPROFILER_MODE_CREATEQUEUE) { if (hsa_rsrc->CreateQueue(agent_info, properties->queue_depth, &(properties->queue)) == false) { EXC_RAISING(HSA_STATUS_ERROR, "CreateQueue() failed"); } } queue = new rocprofiler::HsaQueue(agent_info, properties->queue); } else { EXC_RAISING(HSA_STATUS_ERROR, "invalid mode (" << mode << ")"); } } *handle = new rocprofiler::Context(agent_info, queue, features, feature_count, properties->handler, properties->handler_arg); API_METHOD_SUFFIX } // Delete profiling info PUBLIC_API hsa_status_t rocprofiler_close(rocprofiler_t* handle) { API_METHOD_PREFIX rocprofiler::Context* context = reinterpret_cast(handle); if (context) delete context; API_METHOD_SUFFIX } // Reset context PUBLIC_API hsa_status_t rocprofiler_reset(rocprofiler_t* handle, uint32_t group_index) { API_METHOD_PREFIX rocprofiler::Context* context = reinterpret_cast(handle); context->Reset(group_index); API_METHOD_SUFFIX } // Get profiling group count PUBLIC_API hsa_status_t rocprofiler_group_count(const rocprofiler_t* handle, uint32_t* group_count) { API_METHOD_PREFIX const rocprofiler::Context* context = reinterpret_cast(handle); *group_count = context->GetGroupCount(); API_METHOD_SUFFIX } // Get profiling group for a given group index PUBLIC_API hsa_status_t rocprofiler_get_group(rocprofiler_t* handle, uint32_t group_index, rocprofiler_group_t* group) { API_METHOD_PREFIX rocprofiler::Context* context = reinterpret_cast(handle); *group = context->GetGroupInfo(group_index); API_METHOD_SUFFIX } // Start profiling PUBLIC_API hsa_status_t rocprofiler_start(rocprofiler_t* handle, uint32_t group_index) { API_METHOD_PREFIX rocprofiler::Context* context = reinterpret_cast(handle); context->Start(group_index); API_METHOD_SUFFIX } // Stop profiling PUBLIC_API hsa_status_t rocprofiler_stop(rocprofiler_t* handle, uint32_t group_index) { API_METHOD_PREFIX rocprofiler::Context* context = reinterpret_cast(handle); context->Stop(group_index); API_METHOD_SUFFIX } // Get profiling data PUBLIC_API hsa_status_t rocprofiler_get_data(rocprofiler_t* handle, uint32_t group_index) { API_METHOD_PREFIX rocprofiler::Context* context = reinterpret_cast(handle); context->GetData(group_index); API_METHOD_SUFFIX } // Start profiling PUBLIC_API hsa_status_t rocprofiler_group_start(rocprofiler_group_t* group) { API_METHOD_PREFIX rocprofiler_start(group->context, group->index); API_METHOD_SUFFIX } // Stop profiling PUBLIC_API hsa_status_t rocprofiler_group_stop(rocprofiler_group_t* group) { API_METHOD_PREFIX rocprofiler_stop(group->context, group->index); API_METHOD_SUFFIX } // Get profiling data PUBLIC_API hsa_status_t rocprofiler_group_get_data(rocprofiler_group_t* group) { API_METHOD_PREFIX rocprofiler::Context* context = reinterpret_cast(group->context); context->GetData(group->index); API_METHOD_SUFFIX } // Get metrics data PUBLIC_API hsa_status_t rocprofiler_get_metrics(const rocprofiler_t* handle) { API_METHOD_PREFIX const rocprofiler::Context* context = reinterpret_cast(handle); context->GetMetricsData(); API_METHOD_SUFFIX } // Set kernel dispatch observer PUBLIC_API hsa_status_t rocprofiler_set_dispatch_callback(rocprofiler_callback_t callback, void* data) { API_METHOD_PREFIX rocprofiler::InterceptQueue::SetDispatchCB(callback, data); API_METHOD_SUFFIX } // Set kernel dispatch observer PUBLIC_API hsa_status_t rocprofiler_remove_dispatch_callback() { API_METHOD_PREFIX rocprofiler::InterceptQueue::UnsetDispatchCB(); API_METHOD_SUFFIX } // Method for iterating the events output data PUBLIC_API hsa_status_t rocprofiler_iterate_trace_data( rocprofiler_t* handle, hsa_ven_amd_aqlprofile_data_callback_t callback, void* data) { API_METHOD_PREFIX rocprofiler::Context* context = reinterpret_cast(handle); context->IterateTraceData(callback, data); API_METHOD_SUFFIX } // Return the info for a given info kind PUBLIC_API hsa_status_t rocprofiler_get_info( hsa_agent_t agent, rocprofiler_info_kind_t kind, void *data) { API_METHOD_PREFIX uint32_t* result_32bit_ptr = reinterpret_cast(data); switch (kind) { case ROCPROFILER_INFO_KIND_METRIC_COUNT: *result_32bit_ptr = rocprofiler::GetMetrics(agent)->Size(); break; case ROCPROFILER_INFO_KIND_TRACE_COUNT: *result_32bit_ptr = 1; break; default: EXC_RAISING(HSA_STATUS_ERROR, "unknown info kind(" << kind << ")"); } API_METHOD_SUFFIX } // Iterate over the info for a given info kind, and invoke an application-defined callback on every iteration PUBLIC_API hsa_status_t rocprofiler_iterate_info( hsa_agent_t agent, rocprofiler_info_kind_t kind, hsa_status_t (*callback)(const rocprofiler_info_data_t info, void *data), void *data) { API_METHOD_PREFIX rocprofiler_info_data_t info{}; info.kind = kind; switch (kind) { case ROCPROFILER_INFO_KIND_METRIC: { const rocprofiler::MetricsDict* dict = rocprofiler::GetMetrics(agent); rocprofiler::MetricsDict::const_iterator_t it = dict->Begin(); rocprofiler::MetricsDict::const_iterator_t end = dict->End(); while (it != end) { const rocprofiler::Metric* metric = it->second; std::string name = metric->GetName(); const auto* expr = metric->GetExpr(); std::string description = "Performance metric " + name + " " + ((expr == NULL) ? "basic" : "= " + expr->String()); info.metric.name = strdup(name.c_str()); info.metric.description = strdup(description.c_str()); status = callback(info, data); ++it; } break; } case ROCPROFILER_INFO_KIND_TRACE: { info.trace.name = strdup("TT"); info.trace.description = strdup("Thread Trace"); info.trace.parameter_count = 5; status = callback(info, data); break; } default: EXC_RAISING(HSA_STATUS_ERROR, "unknown info kind(" << kind << ")"); } if (status == HSA_STATUS_INFO_BREAK) status = HSA_STATUS_SUCCESS; if (status != HSA_STATUS_SUCCESS) ERR_LOGGING("iterate_info error, info kind(" << kind << ")"); API_METHOD_SUFFIX } // Iterate over the info for a given info query, and invoke an application-defined callback on every iteration PUBLIC_API hsa_status_t rocprofiler_query_info( hsa_agent_t agent, rocprofiler_info_query_t query, hsa_status_t (*callback)(const rocprofiler_info_data_t info, void *data), void *data) { API_METHOD_PREFIX EXC_RAISING(HSA_STATUS_ERROR, "Not implemented"); API_METHOD_SUFFIX } } // extern "C"