/* * Copyright (C) 2020-2025 Intel Corporation * * SPDX-License-Identifier: MIT * */ #include "level_zero/tools/source/metrics/metric.h" #include "shared/source/device/sub_device.h" #include "shared/source/execution_environment/execution_environment.h" #include "level_zero/core/source/device/device.h" #include "level_zero/core/source/device/device_imp.h" #include "level_zero/core/source/driver/driver.h" #include "level_zero/core/source/driver/driver_handle_imp.h" #include "level_zero/tools/source/metrics/metric_ip_sampling_source.h" #include "level_zero/tools/source/metrics/metric_oa_source.h" #include #include namespace L0 { void MetricSource::getMetricGroupSourceIdProperty(zet_base_properties_t *property) { zet_intel_metric_source_id_exp_t *groupProperty = reinterpret_cast(property); groupProperty->sourceId = type; } MetricDeviceContext::MetricDeviceContext(Device &inputDevice) : device(inputDevice) { auto deviceNeo = device.getNEODevice(); std::tuple subDeviceMap; uint32_t hwSubDeviceIndex = 0u; bool requiresSubDeviceHierarchy = false; if (deviceNeo->getExecutionEnvironment()->getSubDeviceHierarchy(deviceNeo->getRootDeviceIndex(), &subDeviceMap)) { hwSubDeviceIndex = std::get<1>(subDeviceMap); requiresSubDeviceHierarchy = true; } if (requiresSubDeviceHierarchy) { subDeviceIndex = hwSubDeviceIndex; multiDeviceCapable = false; } else { bool isSubDevice = deviceNeo->isSubDevice(); subDeviceIndex = isSubDevice ? static_cast(deviceNeo)->getSubDeviceIndex() : 0; multiDeviceCapable = !isSubDevice && device.isImplicitScalingCapable(); } metricSources[MetricSource::metricSourceTypeOa] = OaMetricSourceImp::create(*this); metricSources[MetricSource::metricSourceTypeIpSampling] = IpSamplingMetricSourceImp::create(*this); if (NEO::debugManager.flags.DisableProgrammableMetricsSupport.get()) { isProgrammableMetricsEnabled = false; } } bool MetricDeviceContext::enable() { bool status = false; std::lock_guard lock(enableMetricsMutex); for (auto const &entry : metricSources) { auto const &metricSource = entry.second; // Enable only if not already enabled. if (!isEnableChecked) { metricSource->enable(); } status |= metricSource->isAvailable(); } isEnableChecked = true; return status; } ze_result_t MetricDeviceContext::metricGroupGet(uint32_t *pCount, zet_metric_group_handle_t *phMetricGroups) { ze_result_t result = ZE_RESULT_SUCCESS; uint32_t availableCount = 0; uint32_t requestCount = *pCount; for (auto const &entry : metricSources) { auto const &metricSource = entry.second; if (!metricSource->isAvailable()) { continue; } result = metricSource->metricGroupGet(&requestCount, phMetricGroups); if (result == ZE_RESULT_ERROR_UNSUPPORTED_FEATURE) { result = ZE_RESULT_SUCCESS; continue; } if (result != ZE_RESULT_SUCCESS) { break; } availableCount += requestCount; if (*pCount == 0) { requestCount = 0; } else { DEBUG_BREAK_IF(availableCount > *pCount); phMetricGroups += requestCount; requestCount = *pCount - availableCount; if (requestCount == 0) { break; } } } *pCount = availableCount; return result; } ze_result_t MetricDeviceContext::activateMetricGroupsPreferDeferred(uint32_t count, zet_metric_group_handle_t *phMetricGroups) { // Create a map of metric source types and Metric groups std::map> metricGroupsPerMetricSourceMap{}; for (auto index = 0u; index < count; index++) { auto &metricGroupSource = static_cast(MetricGroup::fromHandle(phMetricGroups[index]))->getMetricSource(); metricGroupsPerMetricSourceMap[metricGroupSource.getType()].push_back(phMetricGroups[index]); } for (auto const &entry : metricSources) { auto const &metricSourceEntry = entry.second; auto status = ZE_RESULT_SUCCESS; if (!metricSourceEntry->isAvailable()) { continue; } auto sourceType = metricSourceEntry->getType(); if (metricGroupsPerMetricSourceMap.find(sourceType) == metricGroupsPerMetricSourceMap.end()) { status = metricSourceEntry->activateMetricGroupsPreferDeferred(0, nullptr); } else { auto &metricGroupVec = metricGroupsPerMetricSourceMap[sourceType]; status = metricSourceEntry->activateMetricGroupsPreferDeferred( static_cast(metricGroupVec.size()), metricGroupVec.data()); } if (status != ZE_RESULT_SUCCESS) { return status; } } return ZE_RESULT_SUCCESS; } ze_result_t MetricDeviceContext::appendMetricMemoryBarrier(CommandList &commandList) { bool isSuccess = false; for (auto const &entry : metricSources) { auto const &metricSource = entry.second; if (!metricSource->isAvailable()) { continue; } ze_result_t result = metricSource->appendMetricMemoryBarrier(commandList); if (result == ZE_RESULT_SUCCESS) { isSuccess = true; } else if (result != ZE_RESULT_ERROR_UNSUPPORTED_FEATURE) { return result; } } return isSuccess == false ? ZE_RESULT_ERROR_UNSUPPORTED_FEATURE : ZE_RESULT_SUCCESS; } bool MetricDeviceContext::isImplicitScalingCapable() const { return multiDeviceCapable; } ze_result_t MetricDeviceContext::activateMetricGroups() { for (auto const &entry : metricSources) { auto const &metricSource = entry.second; metricSource->activateMetricGroupsAlreadyDeferred(); } return ZE_RESULT_SUCCESS; } uint32_t MetricDeviceContext::getSubDeviceIndex() const { return subDeviceIndex; } Device &MetricDeviceContext::getDevice() const { return device; } void MetricDeviceContext::enableMetricApiForDevice(zet_device_handle_t hDevice, bool &isFailed) { auto deviceImp = static_cast(L0::Device::fromHandle(hDevice)); // Initialize device. isFailed |= !deviceImp->metricContext->enable(); // Initialize sub devices if available. for (uint32_t i = 0; i < deviceImp->numSubDevices; ++i) { isFailed |= !deviceImp->subDevices[i]->getMetricDeviceContext().enable(); } } ze_result_t MetricDeviceContext::enableMetricApi() { bool failed = false; for (auto &globalDriverHandle : *globalDriverHandles) { auto driverHandle = L0::DriverHandle::fromHandle(globalDriverHandle); auto rootDevices = std::vector(); auto subDevices = std::vector(); // Obtain root devices. uint32_t rootDeviceCount = 0; driverHandle->getDevice(&rootDeviceCount, nullptr); rootDevices.resize(rootDeviceCount); driverHandle->getDevice(&rootDeviceCount, rootDevices.data()); for (auto rootDeviceHandle : rootDevices) { enableMetricApiForDevice(rootDeviceHandle, failed); } if (failed) { break; } } return failed ? ZE_RESULT_ERROR_DEPENDENCY_UNAVAILABLE : ZE_RESULT_SUCCESS; } ze_result_t MetricDeviceContext::getConcurrentMetricGroups(uint32_t metricGroupCount, zet_metric_group_handle_t *phMetricGroups, uint32_t *pConcurrentGroupCount, uint32_t *pCountPerConcurrentGroup) { if (!areMetricGroupsFromSameDeviceHierarchy(metricGroupCount, phMetricGroups)) { METRICS_LOG_ERR("%s", "Mix of root device and sub-device metric group handle is not allowed"); return ZE_RESULT_ERROR_INVALID_ARGUMENT; } std::map> metricGroupsPerMetricSourceMap{}; for (auto index = 0u; index < metricGroupCount; index++) { auto &metricGroupSource = static_cast(MetricGroup::fromHandle(phMetricGroups[index]))->getMetricSource(); metricGroupsPerMetricSourceMap[&metricGroupSource].push_back(phMetricGroups[index]); } // Calculate the maximum concurrent group count uint32_t maxConcurrentGroupCount = 0; for (auto &[source, metricGroups] : metricGroupsPerMetricSourceMap) { uint32_t perSourceConcurrentCount = 0; auto status = source->getConcurrentMetricGroups(metricGroups, &perSourceConcurrentCount, nullptr); if (status != ZE_RESULT_SUCCESS) { METRICS_LOG_ERR("Per source concurrent metric group query returned error status %d", status); *pConcurrentGroupCount = 0; return status; } maxConcurrentGroupCount = std::max(maxConcurrentGroupCount, perSourceConcurrentCount); } if (*pConcurrentGroupCount == 0) { *pConcurrentGroupCount = maxConcurrentGroupCount; return ZE_RESULT_SUCCESS; } if (*pConcurrentGroupCount != maxConcurrentGroupCount) { METRICS_LOG_ERR("Input Concurrent Group Count %d is not same as expected %d", *pConcurrentGroupCount, maxConcurrentGroupCount); *pConcurrentGroupCount = 0; return ZE_RESULT_ERROR_INVALID_ARGUMENT; } std::vector> concurrentGroups(maxConcurrentGroupCount); for (auto &entry : metricGroupsPerMetricSourceMap) { auto source = entry.first; auto &metricGroups = entry.second; // Using maximum possible concurrent group count uint32_t perSourceConcurrentCount = metricGroupCount; std::vector countPerConcurrentGroup(perSourceConcurrentCount); auto status = source->getConcurrentMetricGroups(metricGroups, &perSourceConcurrentCount, countPerConcurrentGroup.data()); if (status != ZE_RESULT_SUCCESS) { METRICS_LOG_ERR("getConcurrentMetricGroups returned error status %d", status); *pConcurrentGroupCount = 0; return status; } DEBUG_BREAK_IF(static_cast(concurrentGroups.size() < perSourceConcurrentCount)); auto metricGroupsStartOffset = metricGroups.begin(); [[maybe_unused]] uint32_t totalMetricGroupCount = 0; // Copy the handles to appropriate groups for (uint32_t groupIndex = 0; groupIndex < perSourceConcurrentCount; groupIndex++) { totalMetricGroupCount += countPerConcurrentGroup[groupIndex]; DEBUG_BREAK_IF(totalMetricGroupCount > static_cast(metricGroups.size())); concurrentGroups[groupIndex].insert(concurrentGroups[groupIndex].end(), metricGroupsStartOffset, metricGroupsStartOffset + countPerConcurrentGroup[groupIndex]); metricGroupsStartOffset += countPerConcurrentGroup[groupIndex]; } } // Update the concurrent Group count and count per concurrent grup *pConcurrentGroupCount = static_cast(concurrentGroups.size()); for (uint32_t index = 0u; index < *pConcurrentGroupCount; index++) { pCountPerConcurrentGroup[index] = static_cast(concurrentGroups[index].size()); } // Update the output metric groups size_t availableSize = metricGroupCount; for (auto &concurrentGroup : concurrentGroups) { memcpy_s(phMetricGroups, availableSize * sizeof(zet_metric_group_handle_t), concurrentGroup.data(), concurrentGroup.size() * sizeof(zet_metric_group_handle_t)); availableSize -= concurrentGroup.size(); phMetricGroups += concurrentGroup.size(); } DEBUG_BREAK_IF(availableSize != 0); return ZE_RESULT_SUCCESS; } ze_result_t MetricDeviceContext::metricProgrammableGet( uint32_t *pCount, zet_metric_programmable_exp_handle_t *phMetricProgrammables) { if (!isProgrammableMetricsEnabled) { *pCount = 0; return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; } ze_result_t result = ZE_RESULT_SUCCESS; uint32_t availableCount = 0; uint32_t requestCount = *pCount; for (auto const &entry : metricSources) { auto const &metricSource = entry.second; if (!metricSource->isAvailable()) { continue; } result = metricSource->metricProgrammableGet(&requestCount, phMetricProgrammables); if (result == ZE_RESULT_ERROR_UNSUPPORTED_FEATURE) { result = ZE_RESULT_SUCCESS; continue; } if (result != ZE_RESULT_SUCCESS) { // Currently there is no error possible other than unsupported feature DEBUG_BREAK_IF(true); break; } availableCount += requestCount; if (*pCount == 0) { requestCount = 0; } else { DEBUG_BREAK_IF(availableCount > *pCount); phMetricProgrammables += requestCount; requestCount = *pCount - availableCount; if (requestCount == 0) { break; } } } *pCount = availableCount; return result; } ze_result_t MetricDeviceContext::createMetricGroupsFromMetrics(uint32_t metricCount, zet_metric_handle_t *phMetrics, const char metricGroupNamePrefix[ZET_INTEL_MAX_METRIC_GROUP_NAME_PREFIX_EXP], const char description[ZET_MAX_METRIC_GROUP_DESCRIPTION], uint32_t *pMetricGroupCount, zet_metric_group_handle_t *phMetricGroups) { if (!isProgrammableMetricsEnabled) { return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; } if (metricCount == 0) { return ZE_RESULT_ERROR_INVALID_ARGUMENT; } zet_metric_group_handle_t *cleanupMetricGroups = phMetricGroups; // Create a map of metric source types and Metrics std::map> metricsPerMetricSourceMap{}; for (auto index = 0u; index < metricCount; index++) { auto metricImp = static_cast(Metric::fromHandle(phMetrics[index])); if (metricImp->isImmutable()) { *pMetricGroupCount = 0; return ZE_RESULT_ERROR_INVALID_ARGUMENT; } auto &metricSource = metricImp->getMetricSource(); metricsPerMetricSourceMap[&metricSource].push_back(phMetrics[index]); } auto isGetMetricGroupCountPath = *pMetricGroupCount == 0u; uint32_t remainingMetricGroupCount = *pMetricGroupCount; auto cleanupApi = [&]() { if (!isGetMetricGroupCountPath) { for (uint32_t index = 0; index < (*pMetricGroupCount - remainingMetricGroupCount); index++) { zetMetricGroupDestroyExp(cleanupMetricGroups[index]); } } }; for (auto &metricSourceEntry : metricsPerMetricSourceMap) { MetricSource *metricSource = metricSourceEntry.first; std::vector metricGroupList{}; uint32_t metricGroupCountPerSource = remainingMetricGroupCount; auto status = metricSource->createMetricGroupsFromMetrics(metricSourceEntry.second, metricGroupNamePrefix, description, &metricGroupCountPerSource, metricGroupList); if (status != ZE_RESULT_SUCCESS) { if (status == ZE_RESULT_ERROR_UNSUPPORTED_FEATURE) { continue; } cleanupApi(); *pMetricGroupCount = 0; return status; } if (isGetMetricGroupCountPath) { *pMetricGroupCount += metricGroupCountPerSource; } else { memcpy_s(phMetricGroups, remainingMetricGroupCount * sizeof(zet_metric_group_handle_t), metricGroupList.data(), metricGroupCountPerSource * sizeof(metricGroupList[0])); DEBUG_BREAK_IF(metricGroupCountPerSource > remainingMetricGroupCount); phMetricGroups += metricGroupCountPerSource; remainingMetricGroupCount -= metricGroupCountPerSource; if (!remainingMetricGroupCount) { break; } } } *pMetricGroupCount = *pMetricGroupCount - remainingMetricGroupCount; return ZE_RESULT_SUCCESS; } bool MetricDeviceContext::areMetricGroupsFromSameDeviceHierarchy(uint32_t count, zet_metric_group_handle_t *phMetricGroups) { bool isRootDevice = isImplicitScalingCapable(); // Verify whether metricGroups belong to the device heirarchy for (uint32_t index = 0; index < count; index++) { auto metricGroupImp = static_cast(MetricGroup::fromHandle(phMetricGroups[index])); if (isRootDevice != metricGroupImp->isRootDevice()) { return false; } } return true; } bool MetricDeviceContext::areMetricsFromSameDeviceHierarchy(uint32_t count, zet_metric_handle_t *phMetrics) { bool isRootDevice = isImplicitScalingCapable(); // Verify whether metricGroups belong to the device heirarchy for (uint32_t index = 0; index < count; index++) { auto metricImp = static_cast(Metric::fromHandle(phMetrics[index])); if (isRootDevice != metricImp->isRootDevice()) { return false; } } return true; } ze_result_t MetricDeviceContext::metricGroupCreate(const char name[ZET_MAX_METRIC_GROUP_NAME], const char description[ZET_MAX_METRIC_GROUP_DESCRIPTION], zet_metric_group_sampling_type_flag_t samplingType, zet_metric_group_handle_t *pMetricGroupHandle) { return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; } bool MetricDeviceContext::areMetricGroupsFromSameSource(uint32_t count, zet_metric_group_handle_t *phMetricGroups, uint32_t *sourceType) { DEBUG_BREAK_IF(count == 0); auto metricGroupImp = static_cast(MetricGroup::fromHandle(phMetricGroups[0])); *sourceType = metricGroupImp->getMetricSource().getType(); // Verify whether all metric groups have the same source type for (uint32_t index = 1; index < count; index++) { metricGroupImp = static_cast(MetricGroup::fromHandle(phMetricGroups[index])); if (*sourceType != metricGroupImp->getMetricSource().getType()) { *sourceType = MetricSource::metricSourceTypeUndefined; return false; } } return true; } bool MetricDeviceContext::areMetricsFromSameSource(uint32_t count, zet_metric_handle_t *phMetrics, uint32_t *sourceType) { DEBUG_BREAK_IF(count == 0); auto metricImp = static_cast(Metric::fromHandle(phMetrics[0])); *sourceType = metricImp->getMetricSource().getType(); // Verify whether all metrics have the same source type for (uint32_t index = 1; index < count; index++) { auto metricImp = static_cast(Metric::fromHandle(phMetrics[index])); if (*sourceType != metricImp->getMetricSource().getType()) { *sourceType = MetricSource::metricSourceTypeUndefined; return false; } } return true; } ze_result_t MetricDeviceContext::calcOperationCreate(zet_context_handle_t hContext, zet_intel_metric_calculate_exp_desc_t *pCalculateDesc, uint32_t *pCount, zet_metric_handle_t *phExcludedMetrics, zet_intel_metric_calculate_operation_exp_handle_t *phCalculateOperation) { if (pCalculateDesc->timeAggregationWindow == 0) { METRICS_LOG_ERR("%s", "Must define an aggregation window"); return ZE_RESULT_ERROR_INVALID_ARGUMENT; } uint32_t metricGroupsSourceType = MetricSource::metricSourceTypeUndefined; MetricGroupImp *metricGroupImp = nullptr; if (pCalculateDesc->metricGroupCount > 0) { if (!areMetricGroupsFromSameSource(pCalculateDesc->metricGroupCount, pCalculateDesc->phMetricGroups, &metricGroupsSourceType)) { METRICS_LOG_ERR("%s", "Metric groups must be from the same domain"); return ZE_RESULT_ERROR_INVALID_ARGUMENT; } if (!areMetricGroupsFromSameDeviceHierarchy(pCalculateDesc->metricGroupCount, pCalculateDesc->phMetricGroups)) { METRICS_LOG_ERR("%s", "Mix of root device and sub-device metric group handle is not allowed"); return ZE_RESULT_ERROR_INVALID_ARGUMENT; } metricGroupImp = static_cast(MetricGroup::fromHandle(pCalculateDesc->phMetricGroups[0])); } uint32_t metricsSourceType = MetricSource::metricSourceTypeUndefined; MetricImp *metricImp = nullptr; if (pCalculateDesc->metricCount > 0) { if (!areMetricsFromSameSource(pCalculateDesc->metricCount, pCalculateDesc->phMetrics, &metricsSourceType)) { METRICS_LOG_ERR("%s", "Metrics must be from the same domain"); return ZE_RESULT_ERROR_INVALID_ARGUMENT; } metricImp = static_cast(Metric::fromHandle(pCalculateDesc->phMetrics[0])); // IpSampling does not use multi-device metrics if ((metricImp->getMetricSource().getType() != MetricSource::metricSourceTypeIpSampling) && (!areMetricsFromSameDeviceHierarchy(pCalculateDesc->metricCount, pCalculateDesc->phMetrics))) { METRICS_LOG_ERR("%s", "Mix of root device and sub-device metric handle is not allowed"); return ZE_RESULT_ERROR_INVALID_ARGUMENT; } } if (pCalculateDesc->metricGroupCount > 0) { if ((pCalculateDesc->metricCount > 0) && (metricGroupsSourceType != metricsSourceType)) { METRICS_LOG_ERR("%s", "Metric groups and metrics must be from the same domain"); return ZE_RESULT_ERROR_INVALID_ARGUMENT; } } else if (pCalculateDesc->metricCount == 0) { METRICS_LOG_ERR("%s", "Must define at least one metric group or metric"); return ZE_RESULT_ERROR_INVALID_ARGUMENT; } MetricSource &metricSource = (metricGroupImp) ? metricGroupImp->getMetricSource() : metricImp->getMetricSource(); // NOLINT(clang-analyzer-core.CallAndMessage) return metricSource.calcOperationCreate(*this, pCalculateDesc, pCount, phExcludedMetrics, phCalculateOperation); } ze_result_t MultiDeviceMetricImp::getProperties(zet_metric_properties_t *pProperties) { return subDeviceMetrics[0]->getProperties(pProperties); } MultiDeviceMetricImp *MultiDeviceMetricImp::create(MetricSource &metricSource, std::vector &subDeviceMetrics) { return new (std::nothrow) MultiDeviceMetricImp(metricSource, subDeviceMetrics); } MetricImp *MultiDeviceMetricImp::getMetricAtSubDeviceIndex(uint32_t index) { if (index < subDeviceMetrics.size()) { return subDeviceMetrics.at(index); } return nullptr; } 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->getMetricDeviceContext().metricGroupGet(pCount, phMetricGroups); } ze_result_t metricStreamerOpen(zet_context_handle_t hContext, zet_device_handle_t hDevice, zet_metric_group_handle_t hMetricGroup, zet_metric_streamer_desc_t *pDesc, ze_event_handle_t hNotificationEvent, zet_metric_streamer_handle_t *phMetricStreamer) { return MetricGroup::fromHandle(hMetricGroup)->streamerOpen(hContext, hDevice, pDesc, hNotificationEvent, phMetricStreamer); } bool MultiDomainDeferredActivationTracker::activateMetricGroupsDeferred(uint32_t count, zet_metric_group_handle_t *phMetricGroups) { // Activation: postpone until zetMetricStreamerOpen or zeCommandQueueExecuteCommandLists // Deactivation: execute immediately. if (phMetricGroups == nullptr) { deActivateAllDomains(); return true; } auto isMetricGroupProvided = [phMetricGroups, count](const zet_metric_group_handle_t hMetricGroup) { for (auto index = 0u; index < count; index++) { if (hMetricGroup == phMetricGroups[index]) { return true; } } return false; }; // Deactive existing metric groups which are not provided in phMetricGroups std::vector deactivateList = {}; for (const auto &[domainId, metricGroupPair] : domains) { const auto &hMetricGroup = metricGroupPair.first; if (isMetricGroupProvided(hMetricGroup) == false) { deActivateDomain(domainId); deactivateList.push_back(domainId); } } // Remove deactivated ones from the map for (const auto &domainId : deactivateList) { domains.erase(domainId); } // Activate-deferred new metric groups if any for (auto index = 0u; index < count; index++) { zet_metric_group_handle_t hMetricGroup = MetricGroup::fromHandle(phMetricGroups[index])->getMetricGroupForSubDevice(subDeviceIndex); zet_metric_group_properties_t properties = {ZET_STRUCTURE_TYPE_METRIC_GROUP_PROPERTIES, nullptr}; auto metricGroup = MetricGroup::fromHandle(hMetricGroup); metricGroup->getProperties(&properties); auto domain = properties.domain; // Domain already associated with the same handle. if (domains[domain].first == hMetricGroup) { continue; } domains[domain].first = hMetricGroup; domains[domain].second = false; } return true; } ze_result_t MultiDomainDeferredActivationTracker::activateMetricGroupsAlreadyDeferred() { for (auto &entry : domains) { auto &metricGroupEntry = entry.second; DEBUG_BREAK_IF(metricGroupEntry.first == nullptr); auto metricGroup = MetricGroup::fromHandle(metricGroupEntry.first); metricGroup->activate(); metricGroupEntry.second = true; } return ZE_RESULT_SUCCESS; } void MultiDomainDeferredActivationTracker::deActivateDomain(uint32_t domain) { auto &metricGroupPair = domains[domain]; if (metricGroupPair.second == true) { MetricGroup::fromHandle(metricGroupPair.first)->deactivate(); } } void MultiDomainDeferredActivationTracker::deActivateAllDomains() { for (auto &entry : domains) { deActivateDomain(entry.first); } domains.clear(); } bool MultiDomainDeferredActivationTracker::isMetricGroupActivated(const zet_metric_group_handle_t hMetricGroup) const { for (auto const &entry : domains) { auto const &metricGroup = entry.second; if (metricGroup.first == hMetricGroup) { return true; } } return false; } bool MultiDomainDeferredActivationTracker::isMetricGroupActivatedInHw() const { for (auto const &entry : domains) { auto const &metricGroup = entry.second; if (metricGroup.second == true) { return true; } } return false; } void MetricCollectorEventNotify::attachEvent(ze_event_handle_t hEvent) { // Associate L0 notification event with metric notification. pNotificationEvent = Event::fromHandle(hEvent); if (pNotificationEvent != nullptr) { pNotificationEvent->setMetricNotification(this); } } void MetricCollectorEventNotify::detachEvent() { // Remove association to L0 event. if (pNotificationEvent != nullptr) { pNotificationEvent->setMetricNotification(nullptr); } } void MetricGroupUserDefined::updateErrorString(std::string &errorString, size_t *errorStringSize, char *pErrorString) { if (*errorStringSize == 0) { *errorStringSize = errorString.length() + 1; } else { *errorStringSize = std::min(*errorStringSize, errorString.length() + 1); strncpy_s(pErrorString, *errorStringSize, errorString.data(), *errorStringSize); } } MetricProgrammable *HomogeneousMultiDeviceMetricProgrammable::create(MetricSource &metricSource, std::vector &subDeviceProgrammables) { return static_cast(new (std::nothrow) HomogeneousMultiDeviceMetricProgrammable(metricSource, subDeviceProgrammables)); } ze_result_t HomogeneousMultiDeviceMetricProgrammable::getProperties(zet_metric_programmable_exp_properties_t *pProperties) { return subDeviceProgrammables[0]->getProperties(pProperties); } ze_result_t HomogeneousMultiDeviceMetricProgrammable::getParamInfo(uint32_t *pParameterCount, zet_metric_programmable_param_info_exp_t *pParameterInfo) { return subDeviceProgrammables[0]->getParamInfo(pParameterCount, pParameterInfo); } ze_result_t HomogeneousMultiDeviceMetricProgrammable::getParamValueInfo(uint32_t parameterOrdinal, uint32_t *pValueInfoCount, zet_metric_programmable_param_value_info_exp_t *pValueInfo) { return subDeviceProgrammables[0]->getParamValueInfo(parameterOrdinal, pValueInfoCount, pValueInfo); } ze_result_t HomogeneousMultiDeviceMetricProgrammable::createMetric(zet_metric_programmable_param_value_exp_t *pParameterValues, uint32_t parameterCount, const char name[ZET_MAX_METRIC_NAME], const char description[ZET_MAX_METRIC_DESCRIPTION], uint32_t *pMetricHandleCount, zet_metric_handle_t *phMetricHandles) { auto isCountEstimationPath = *pMetricHandleCount == 0; ze_result_t status = ZE_RESULT_SUCCESS; uint32_t expectedMetricHandleCount = 0; auto isExpectedHandleCount = [&](const uint32_t actualHandleCount) { if (expectedMetricHandleCount != 0 && expectedMetricHandleCount != actualHandleCount) { METRICS_LOG_ERR("Unexpected Metric Handle Count for subdevice expected:%d, actual:%d", expectedMetricHandleCount, actualHandleCount); return false; } expectedMetricHandleCount = actualHandleCount; return true; }; if (isCountEstimationPath) { for (auto &subDeviceProgrammable : subDeviceProgrammables) { uint32_t metricHandleCount = 0; status = subDeviceProgrammable->createMetric(pParameterValues, parameterCount, name, description, &metricHandleCount, nullptr); if (status != ZE_RESULT_SUCCESS || metricHandleCount == 0u) { *pMetricHandleCount = 0; return status; } if (!isExpectedHandleCount(metricHandleCount)) { *pMetricHandleCount = 0; return ZE_RESULT_ERROR_UNKNOWN; } } *pMetricHandleCount = expectedMetricHandleCount; return status; } std::vector> metricHandlesPerSubDeviceList{}; auto cleanupApi = [&]() { for (auto &metricHandlesPerSubDevice : metricHandlesPerSubDeviceList) { for (auto &metricHandle : metricHandlesPerSubDevice) { if (metricHandle != nullptr) { [[maybe_unused]] auto status = static_cast(metricHandle)->destroy(); DEBUG_BREAK_IF(status != ZE_RESULT_SUCCESS); } } metricHandlesPerSubDevice.clear(); } metricHandlesPerSubDeviceList.clear(); }; metricHandlesPerSubDeviceList.resize(subDeviceProgrammables.size()); for (uint32_t index = 0; index < static_cast(subDeviceProgrammables.size()); index++) { auto &subDeviceProgrammable = subDeviceProgrammables[index]; uint32_t metricHandleCount = *pMetricHandleCount; metricHandlesPerSubDeviceList[index].resize(metricHandleCount); status = subDeviceProgrammable->createMetric(pParameterValues, parameterCount, name, description, &metricHandleCount, metricHandlesPerSubDeviceList[index].data()); if (status != ZE_RESULT_SUCCESS || metricHandleCount == 0u) { cleanupApi(); *pMetricHandleCount = 0; return status; } if (!isExpectedHandleCount(metricHandleCount)) { cleanupApi(); *pMetricHandleCount = 0; return ZE_RESULT_ERROR_UNKNOWN; } metricHandlesPerSubDeviceList[index].resize(metricHandleCount); } DEBUG_BREAK_IF(metricHandlesPerSubDeviceList[0].size() > *pMetricHandleCount); // Create Root device Metric handles from sub-device handles for (uint32_t index = 0; index < static_cast(metricHandlesPerSubDeviceList[0].size()); index++) { std::vector homogenousMetricList{}; homogenousMetricList.reserve(subDeviceProgrammables.size()); for (auto &metricHandlesPerSubdevice : metricHandlesPerSubDeviceList) { homogenousMetricList.push_back(static_cast(Metric::fromHandle(metricHandlesPerSubdevice[index]))); } phMetricHandles[index] = HomogeneousMultiDeviceMetricCreated::create(metricSource, homogenousMetricList)->toHandle(); } *pMetricHandleCount = static_cast(metricHandlesPerSubDeviceList[0].size()); return ZE_RESULT_SUCCESS; } ze_result_t HomogeneousMultiDeviceMetricCreated::destroy() { auto status = ZE_RESULT_SUCCESS; for (auto &subDeviceMetric : subDeviceMetrics) { ze_result_t subDeviceStatus = subDeviceMetric->destroy(); // Hold the first error if (status == ZE_RESULT_SUCCESS) { status = subDeviceStatus; } } // release only if object is unused if (status != ZE_RESULT_ERROR_HANDLE_OBJECT_IN_USE) { subDeviceMetrics.clear(); delete this; } return status; } MetricImp *HomogeneousMultiDeviceMetricCreated::create(MetricSource &metricSource, std::vector &subDeviceMetrics) { return new (std::nothrow) HomogeneousMultiDeviceMetricCreated(metricSource, subDeviceMetrics); } ze_result_t metricProgrammableGet(zet_device_handle_t hDevice, uint32_t *pCount, zet_metric_programmable_exp_handle_t *phMetricProgrammables) { auto device = Device::fromHandle(hDevice); return static_cast(device->getMetricDeviceContext()).metricProgrammableGet(pCount, phMetricProgrammables); } ze_result_t metricProgrammableGetProperties( zet_metric_programmable_exp_handle_t hMetricProgrammable, zet_metric_programmable_exp_properties_t *pProperties) { return L0::MetricProgrammable::fromHandle(hMetricProgrammable)->getProperties(pProperties); } ze_result_t metricProgrammableGetParamInfo( zet_metric_programmable_exp_handle_t hMetricProgrammable, uint32_t *pParameterCount, zet_metric_programmable_param_info_exp_t *pParameterInfo) { return L0::MetricProgrammable::fromHandle(hMetricProgrammable)->getParamInfo(pParameterCount, pParameterInfo); } ze_result_t metricProgrammableGetParamValueInfo( zet_metric_programmable_exp_handle_t hMetricProgrammable, uint32_t parameterOrdinal, uint32_t *pValueInfoCount, zet_metric_programmable_param_value_info_exp_t *pValueInfo) { return L0::MetricProgrammable::fromHandle(hMetricProgrammable)->getParamValueInfo(parameterOrdinal, pValueInfoCount, pValueInfo); } ze_result_t metricCreateFromProgrammable( zet_metric_programmable_exp_handle_t hMetricProgrammable, zet_metric_programmable_param_value_exp_t *pParameterValues, uint32_t parameterCount, const char name[ZET_MAX_METRIC_NAME], const char description[ZET_MAX_METRIC_DESCRIPTION], uint32_t *pMetricHandleCount, zet_metric_handle_t *phMetricHandles) { return L0::MetricProgrammable::fromHandle(hMetricProgrammable)->createMetric(pParameterValues, parameterCount, name, description, pMetricHandleCount, phMetricHandles); } ze_result_t metricCalculateOperationCreate( zet_context_handle_t hContext, zet_device_handle_t hDevice, zet_intel_metric_calculate_exp_desc_t *pCalculateDesc, uint32_t *pCount, zet_metric_handle_t *phExcludedMetrics, zet_intel_metric_calculate_operation_exp_handle_t *phCalculateOperation) { DeviceImp *deviceImp = static_cast(L0::Device::fromHandle(hDevice)); return deviceImp->getMetricDeviceContext().calcOperationCreate(hContext, pCalculateDesc, pCount, phExcludedMetrics, phCalculateOperation); } ze_result_t metricCalculateOperationDestroy( zet_intel_metric_calculate_operation_exp_handle_t hCalculateOperation) { return MetricCalcOp::fromHandle(hCalculateOperation)->destroy(); } ze_result_t metricCalculateGetReportFormat( zet_intel_metric_calculate_operation_exp_handle_t hCalculateOperation, uint32_t *pCount, zet_metric_handle_t *phMetrics) { return MetricCalcOp::fromHandle(hCalculateOperation)->getReportFormat(pCount, phMetrics); } ze_result_t metricCalculateValues( const size_t rawDataSize, size_t *pOffset, const uint8_t *pRawData, zet_intel_metric_calculate_operation_exp_handle_t hCalculateOperation, uint32_t *pTotalMetricReportsCount, zet_intel_metric_result_exp_t *pMetricResults) { return MetricCalcOp::fromHandle(hCalculateOperation)->metricCalculateValues(rawDataSize, pOffset, pRawData, pTotalMetricReportsCount, pMetricResults); } ze_result_t metricCalculateMultipleValues( const size_t rawDataSize, size_t *offset, const uint8_t *pRawData, zet_intel_metric_calculate_operation_exp_handle_t hCalculateOperation, uint32_t *pSetCount, uint32_t *pMetricsReportCountPerSet, uint32_t *pTotalMetricReportCount, zet_intel_metric_result_exp_t *pMetricResults) { return MetricCalcOp::fromHandle(hCalculateOperation)->metricCalculateMultipleValues(rawDataSize, offset, pRawData, pSetCount, pMetricsReportCountPerSet, pTotalMetricReportCount, pMetricResults); } ze_result_t metricsEnable(zet_device_handle_t hDevice) { auto isFailed = false; MetricDeviceContext::enableMetricApiForDevice(hDevice, isFailed); return isFailed ? ZE_RESULT_ERROR_DEPENDENCY_UNAVAILABLE : ZE_RESULT_SUCCESS; } } // namespace L0