// // Copyright © 2019 Arm Ltd. All rights reserved. // SPDX-License-Identifier: MIT // #include "PeriodicCounterSelectionCommandHandler.hpp" #include "ProfilingUtils.hpp" #include #include #include #include namespace armnn { namespace profiling { void PeriodicCounterSelectionCommandHandler::ParseData(const Packet& packet, CaptureData& captureData) { std::vector counterIds; uint32_t sizeOfUint32 = boost::numeric_cast(sizeof(uint32_t)); uint32_t sizeOfUint16 = boost::numeric_cast(sizeof(uint16_t)); uint32_t offset = 0; if (packet.GetLength() < 4) { // Insufficient packet size return; } // Parse the capture period uint32_t capturePeriod = ReadUint32(packet.GetData(), offset); // Set the capture period captureData.SetCapturePeriod(capturePeriod); // Parse the counter ids unsigned int counters = (packet.GetLength() - 4) / 2; if (counters > 0) { counterIds.reserve(counters); offset += sizeOfUint32; for (unsigned int i = 0; i < counters; ++i) { // Parse the counter id uint16_t counterId = ReadUint16(packet.GetData(), offset); counterIds.emplace_back(counterId); offset += sizeOfUint16; } } // Set the counter ids captureData.SetCounterIds(counterIds); } void PeriodicCounterSelectionCommandHandler::operator()(const Packet& packet) { ProfilingState currentState = m_StateMachine.GetCurrentState(); switch (currentState) { case ProfilingState::Uninitialised: case ProfilingState::NotConnected: case ProfilingState::WaitingForAck: throw RuntimeException(boost::str(boost::format("Periodic Counter Selection Command Handler invoked while in " "an wrong state: %1%") % GetProfilingStateName(currentState))); case ProfilingState::Active: { // Process the packet if (!(packet.GetPacketFamily() == 0u && packet.GetPacketId() == 4u)) { throw armnn::InvalidArgumentException(boost::str(boost::format("Expected Packet family = 0, id = 4 but " "received family = %1%, id = %2%") % packet.GetPacketFamily() % packet.GetPacketId())); } // Parse the packet to get the capture period and counter UIDs CaptureData captureData; ParseData(packet, captureData); // Get the capture data uint32_t capturePeriod = captureData.GetCapturePeriod(); // Validate that the capture period is within the acceptable range. if (capturePeriod > 0 && capturePeriod < LOWEST_CAPTURE_PERIOD) { capturePeriod = LOWEST_CAPTURE_PERIOD; } const std::vector& counterIds = captureData.GetCounterIds(); // Check whether the selected counter UIDs are valid std::vector validCounterIds; for (uint16_t counterId : counterIds) { // Check whether the counter is registered if (!m_ReadCounterValues.IsCounterRegistered(counterId)) { // Invalid counter UID, ignore it and continue continue; } // The counter is valid validCounterIds.emplace_back(counterId); } std::sort(validCounterIds.begin(), validCounterIds.end()); auto backendIdStart = std::find_if(validCounterIds.begin(), validCounterIds.end(), [&](uint16_t& counterId) { return counterId > m_MaxArmCounterId; }); std::set activeBackends; std::set backendCounterIds = std::set(backendIdStart, validCounterIds.end()); if (m_BackendCounterMap.size() != 0) { std::set newCounterIds; std::set unusedCounterIds; // Get any backend counter ids that is in backendCounterIds but not in m_PrevBackendCounterIds std::set_difference(backendCounterIds.begin(), backendCounterIds.end(), m_PrevBackendCounterIds.begin(), m_PrevBackendCounterIds.end(), std::inserter(newCounterIds, newCounterIds.begin())); // Get any backend counter ids that is in m_PrevBackendCounterIds but not in backendCounterIds std::set_difference(m_PrevBackendCounterIds.begin(), m_PrevBackendCounterIds.end(), backendCounterIds.begin(), backendCounterIds.end(), std::inserter(unusedCounterIds, unusedCounterIds.begin())); activeBackends = ProcessBackendCounterIds(capturePeriod, newCounterIds, unusedCounterIds); } else { activeBackends = ProcessBackendCounterIds(capturePeriod, backendCounterIds, {}); } // save the new backend counter ids for next time m_PrevBackendCounterIds = backendCounterIds; // Set the capture data with only the valid armnn counter UIDs m_CaptureDataHolder.SetCaptureData(capturePeriod, {validCounterIds.begin(), backendIdStart}, activeBackends); // Echo back the Periodic Counter Selection packet to the Counter Stream Buffer m_SendCounterPacket.SendPeriodicCounterSelectionPacket(capturePeriod, validCounterIds); if (capturePeriod == 0 || validCounterIds.empty()) { // No data capture stop the thread m_PeriodicCounterCapture.Stop(); } else { // Start the Period Counter Capture thread (if not running already) m_PeriodicCounterCapture.Start(); } break; } default: throw RuntimeException(boost::str(boost::format("Unknown profiling service state: %1%") % static_cast(currentState))); } } std::set PeriodicCounterSelectionCommandHandler::ProcessBackendCounterIds( const u_int32_t capturePeriod, std::set newCounterIds, std::set unusedCounterIds) { std::set changedBackends; std::set activeBackends = m_CaptureDataHolder.GetCaptureData().GetActiveBackends(); for (uint16_t counterId : newCounterIds) { auto backendId = m_CounterIdMap.GetBackendId(counterId); m_BackendCounterMap[backendId.second].emplace_back(backendId.first); changedBackends.insert(backendId.second); } // Add any new backends to active backends activeBackends.insert(changedBackends.begin(), changedBackends.end()); for (uint16_t counterId : unusedCounterIds) { auto backendId = m_CounterIdMap.GetBackendId(counterId); std::vector& backendCounters = m_BackendCounterMap[backendId.second]; backendCounters.erase(std::remove(backendCounters.begin(), backendCounters.end(), backendId.first)); if(backendCounters.size() == 0) { // If a backend has no counters associated with it we remove it from active backends and // send a capture period of zero with an empty vector, this will deactivate all the backends counters activeBackends.erase(backendId.second); ActivateBackedCounters(backendId.second, 0, {}); } else { changedBackends.insert(backendId.second); } } // If the capture period remains the same we only need to update the backends who's counters have changed if(capturePeriod == m_PrevCapturePeriod) { for (auto backend : changedBackends) { ActivateBackedCounters(backend, capturePeriod, m_BackendCounterMap[backend]); } } // Otherwise update all the backends with the new capture period and any new/unused counters else { for (auto backend : m_BackendCounterMap) { ActivateBackedCounters(backend.first, capturePeriod, backend.second); } if(capturePeriod == 0) { activeBackends = {}; } m_PrevCapturePeriod = capturePeriod; } return activeBackends; } } // namespace profiling } // namespace armnn