/* * Copyright (C) 2019-2020 Intel Corporation * * SPDX-License-Identifier: MIT * */ #include "level_zero/tools/source/metrics/metric.h" #include "shared/source/os_interface/os_library.h" #include "level_zero/core/source/device/device.h" #include "level_zero/core/source/driver/driver.h" #include "level_zero/core/source/driver/driver_handle_imp.h" #include "level_zero/source/inc/ze_intel_gpu.h" #include "level_zero/tools/source/metrics/metric_enumeration_imp.h" #include "level_zero/tools/source/metrics/metric_query_imp.h" #include #include namespace L0 { struct MetricGroupDomains { public: MetricGroupDomains(MetricContext &metricContext); ze_result_t activateDeferred(const uint32_t count, zet_metric_group_handle_t *phMetricGroups); ze_result_t activate(); ze_result_t deactivate(); bool isActivated(const zet_metric_group_handle_t hMetricGroup); protected: bool activateMetricGroupDeffered(const zet_metric_group_handle_t hMetricGroup); bool activateEventMetricGroup(const zet_metric_group_handle_t hMetricGroup); protected: MetricsLibrary &metricsLibrary; // Map holds activated domains and associated metric groups. // Content: std::map> domains; }; struct MetricContextImp : public MetricContext { public: MetricContextImp(Device &device); ~MetricContextImp() override; bool loadDependencies() override; bool isInitialized() override; void setInitializationState(const ze_result_t state) override; Device &getDevice() override; MetricsLibrary &getMetricsLibrary() override; MetricEnumeration &getMetricEnumeration() override; MetricTracer *getMetricTracer() override; void setMetricTracer(MetricTracer *pMetricTracer) override; void setMetricsLibrary(MetricsLibrary &metricsLibrary) override; void setMetricEnumeration(MetricEnumeration &metricEnumeration) override; ze_result_t activateMetricGroups() override; ze_result_t activateMetricGroupsDeferred(const uint32_t count, zet_metric_group_handle_t *phMetricGroups) override; bool isMetricGroupActivated(const zet_metric_group_handle_t hMetricGroup) override; void setUseCompute(const bool useCompute) override; bool isComputeUsed() override; protected: ze_result_t initializationState = ZE_RESULT_ERROR_UNINITIALIZED; struct Device &device; std::unique_ptr metricEnumeration = nullptr; std::unique_ptr metricsLibrary = nullptr; MetricGroupDomains metricGroupDomains; MetricTracer *pMetricTracer = nullptr; bool useCompute = false; }; MetricContextImp::MetricContextImp(Device &deviceInput) : device(deviceInput), metricEnumeration(std::unique_ptr(new (std::nothrow) MetricEnumeration(*this))), metricsLibrary(std::unique_ptr(new (std::nothrow) MetricsLibrary(*this))), metricGroupDomains(*this) { } MetricContextImp::~MetricContextImp() { metricsLibrary.reset(); metricEnumeration.reset(); } bool MetricContextImp::loadDependencies() { bool result = true; if (metricEnumeration->loadMetricsDiscovery() != ZE_RESULT_SUCCESS) { result = false; DEBUG_BREAK_IF(!result); } if (result && !metricsLibrary->load()) { result = false; DEBUG_BREAK_IF(!result); } if (result) { setInitializationState(ZE_RESULT_SUCCESS); } return result; } bool MetricContextImp::isInitialized() { return initializationState == ZE_RESULT_SUCCESS; } void MetricContextImp::setInitializationState(const ze_result_t state) { initializationState = state; } Device &MetricContextImp::getDevice() { return device; } MetricsLibrary &MetricContextImp::getMetricsLibrary() { return *metricsLibrary; } MetricEnumeration &MetricContextImp::getMetricEnumeration() { return *metricEnumeration; } MetricTracer *MetricContextImp::getMetricTracer() { return pMetricTracer; } void MetricContextImp::setMetricTracer(MetricTracer *pMetricTracer) { this->pMetricTracer = pMetricTracer; } void MetricContextImp::setMetricsLibrary(MetricsLibrary &metricsLibrary) { this->metricsLibrary.release(); this->metricsLibrary.reset(&metricsLibrary); } void MetricContextImp::setMetricEnumeration(MetricEnumeration &metricEnumeration) { this->metricEnumeration.release(); this->metricEnumeration.reset(&metricEnumeration); } void MetricContextImp::setUseCompute(const bool useCompute) { this->useCompute = useCompute; } bool MetricContextImp::isComputeUsed() { return useCompute; } ze_result_t MetricContextImp::activateMetricGroupsDeferred(const uint32_t count, zet_metric_group_handle_t *phMetricGroups) { // Activation: postpone until zetMetricTracerOpen or zeCommandQueueExecuteCommandLists // Deactivation: execute immediately. return phMetricGroups ? metricGroupDomains.activateDeferred(count, phMetricGroups) : metricGroupDomains.deactivate(); } bool MetricContextImp::isMetricGroupActivated(const zet_metric_group_handle_t hMetricGroup) { return metricGroupDomains.isActivated(hMetricGroup); } ze_result_t MetricContextImp::activateMetricGroups() { return metricGroupDomains.activate(); } void MetricContext::enableMetricApi(ze_result_t &result) { if (!getenv_tobool("ZE_ENABLE_METRICS")) { result = ZE_RESULT_SUCCESS; return; } if (!isMetricApiAvailable()) { result = ZE_RESULT_ERROR_UNKNOWN; return; } DriverHandle *driverHandle = L0::DriverHandle::fromHandle(GlobalDriver.get()); uint32_t count = 0; result = driverHandle->getDevice(&count, nullptr); if (result != ZE_RESULT_SUCCESS) { result = ZE_RESULT_ERROR_UNKNOWN; return; } std::vector devices(count); result = driverHandle->getDevice(&count, devices.data()); if (result != ZE_RESULT_SUCCESS) { result = ZE_RESULT_ERROR_UNKNOWN; return; } for (auto deviceHandle : devices) { Device *device = L0::Device::fromHandle(deviceHandle); if (!device->getMetricContext().loadDependencies()) { result = ZE_RESULT_ERROR_UNKNOWN; return; } } } std::unique_ptr MetricContext::create(Device &device) { auto metricContextImp = new (std::nothrow) MetricContextImp(device); std::unique_ptr metricContext{metricContextImp}; return metricContext; } bool MetricContext::isMetricApiAvailable() { std::unique_ptr library = nullptr; // Check Metrics Discovery availability. library.reset(NEO::OsLibrary::load(MetricEnumeration::getMetricsDiscoveryFilename())); if (library == nullptr) { return false; } // Check Metrics Library availability. library.reset(NEO::OsLibrary::load(MetricsLibrary::getFilename())); if (library == nullptr) { return false; } return true; } MetricGroupDomains::MetricGroupDomains(MetricContext &metricContext) : metricsLibrary(metricContext.getMetricsLibrary()) {} ze_result_t MetricGroupDomains::activateDeferred(const uint32_t count, zet_metric_group_handle_t *phMetricGroups) { // For each metric group: for (uint32_t i = 0; i < count; ++i) { DEBUG_BREAK_IF(!phMetricGroups[i]); // Try to associate it with a domain (oa, ...). if (!activateMetricGroupDeffered(phMetricGroups[i])) { return ZE_RESULT_ERROR_UNKNOWN; } } return ZE_RESULT_SUCCESS; } bool MetricGroupDomains::activateMetricGroupDeffered(const zet_metric_group_handle_t hMetricGroup) { const auto properites = MetricGroup::getProperties(hMetricGroup); const auto domain = properites.domain; const bool isDomainFree = domains[domain].first == nullptr; const bool isSameGroup = domains[domain].first == hMetricGroup; // The same metric group has been already associated. if (isSameGroup) { return true; } // Domain has been already associated with a different metric group. if (!isDomainFree) { return false; } // Associate metric group with domain and mark it as not active. // Activation will be performed during zeCommandQueueExecuteCommandLists (query) // or zetMetricTracerOpen (time based sampling). domains[domain].first = hMetricGroup; domains[domain].second = false; return true; } ze_result_t MetricGroupDomains::activate() { // For each domain. for (auto &domain : domains) { auto hMetricGroup = domain.second.first; bool &metricGroupActive = domain.second.second; bool metricGroupEventBased = hMetricGroup && MetricGroup::getProperties(hMetricGroup).samplingType == ZET_METRIC_GROUP_SAMPLING_TYPE_EVENT_BASED; // Activate only event based metric groups. // Time based metric group will be activated during zetMetricTracerOpen. if (metricGroupEventBased && !metricGroupActive) { metricGroupActive = activateEventMetricGroup(hMetricGroup); if (metricGroupActive == false) { DEBUG_BREAK_IF(true); return ZE_RESULT_ERROR_UNKNOWN; } } } return ZE_RESULT_SUCCESS; } bool MetricGroupDomains::activateEventMetricGroup(const zet_metric_group_handle_t hMetricGroup) { // Obtain metric group configuration handle from metrics library. auto hConfiguration = metricsLibrary.getConfiguration(hMetricGroup); // Validate metrics library handle. if (!hConfiguration.IsValid()) { DEBUG_BREAK_IF(true); return false; } // Write metric group configuration to gpu. const bool result = metricsLibrary.activateConfiguration(hConfiguration); DEBUG_BREAK_IF(!result); return result; } ze_result_t MetricGroupDomains::deactivate() { // Deactivate metric group for each domain. for (auto &domain : domains) { auto hMetricGroup = domain.second.first; auto metricGroup = MetricGroup::fromHandle(hMetricGroup); bool metricGroupActivated = domain.second.second; auto metricGroupEventBased = (metricGroup != nullptr) ? MetricGroup::getProperties(hMetricGroup).samplingType == ZET_METRIC_GROUP_SAMPLING_TYPE_EVENT_BASED : false; auto hConfigurationEmpty = ConfigurationHandle_1_0{}; auto hConfiguration = metricGroupEventBased ? metricsLibrary.getConfiguration(hMetricGroup) : hConfigurationEmpty; // Deactivate metric group configuration using metrics library. if (hConfiguration.IsValid() && metricGroupActivated) { metricsLibrary.deactivateConfiguration(hConfiguration); } // Mark domain as free. domain.second = {}; } return ZE_RESULT_SUCCESS; } bool MetricGroupDomains::isActivated(const zet_metric_group_handle_t hMetricGroup) { auto metricGroupProperties = MetricGroup::getProperties(hMetricGroup); // 1. Check whether domain is activated. const auto domain = domains.find(metricGroupProperties.domain); if (domain == domains.end()) { return false; } // 2. Check whether the specific MetricGroup is activated. return domain->second.first == hMetricGroup; } ze_result_t metricGroupGet(zet_device_handle_t hDevice, uint32_t *pCount, zet_metric_group_handle_t *phMetricGroups) { auto device = Device::fromHandle(hDevice); return device->getMetricContext().getMetricEnumeration().metricGroupGet(*pCount, phMetricGroups); } ze_result_t metricTracerOpen(zet_device_handle_t hDevice, zet_metric_group_handle_t hMetricGroup, zet_metric_tracer_desc_t *pDesc, ze_event_handle_t hNotificationEvent, zet_metric_tracer_handle_t *phMetricTracer) { *phMetricTracer = MetricTracer::open(hDevice, hMetricGroup, *pDesc, hNotificationEvent); return (*phMetricTracer != nullptr) ? ZE_RESULT_SUCCESS : ZE_RESULT_ERROR_UNKNOWN; } } // namespace L0