// // Copyright © 2020 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // #include #include #include #include #include #include namespace arm { namespace pipe { void ReadBytes(const unsigned char* buffer, unsigned int offset, unsigned int valueSize, uint8_t outValue[]) { ARM_PIPE_ASSERT(buffer); ARM_PIPE_ASSERT(outValue); for (unsigned int i = 0; i < valueSize; i++, offset++) { outValue[i] = static_cast(buffer[offset]); } } uint64_t ReadUint64(const unsigned char* buffer, unsigned int offset) { ARM_PIPE_ASSERT(buffer); uint64_t value = 0; value = static_cast(buffer[offset]); value |= static_cast(buffer[offset + 1]) << 8; value |= static_cast(buffer[offset + 2]) << 16; value |= static_cast(buffer[offset + 3]) << 24; value |= static_cast(buffer[offset + 4]) << 32; value |= static_cast(buffer[offset + 5]) << 40; value |= static_cast(buffer[offset + 6]) << 48; value |= static_cast(buffer[offset + 7]) << 56; return value; } uint32_t ReadUint32(const unsigned char* buffer, unsigned int offset) { ARM_PIPE_ASSERT(buffer); uint32_t value = 0; value = static_cast(buffer[offset]); value |= static_cast(buffer[offset + 1]) << 8; value |= static_cast(buffer[offset + 2]) << 16; value |= static_cast(buffer[offset + 3]) << 24; return value; } uint16_t ReadUint16(const unsigned char* buffer, unsigned int offset) { ARM_PIPE_ASSERT(buffer); uint32_t value = 0; value = static_cast(buffer[offset]); value |= static_cast(buffer[offset + 1]) << 8; return static_cast(value); } uint8_t ReadUint8(const unsigned char* buffer, unsigned int offset) { ARM_PIPE_ASSERT(buffer); return buffer[offset]; } void WriteBytes(unsigned char* buffer, unsigned int offset, const void* value, unsigned int valueSize) { ARM_PIPE_ASSERT(buffer); ARM_PIPE_ASSERT(value); for (unsigned int i = 0; i < valueSize; i++, offset++) { buffer[offset] = *(reinterpret_cast(value) + i); } } void WriteUint64(unsigned char* buffer, unsigned int offset, uint64_t value) { ARM_PIPE_ASSERT(buffer); buffer[offset] = static_cast(value & 0xFF); buffer[offset + 1] = static_cast((value >> 8) & 0xFF); buffer[offset + 2] = static_cast((value >> 16) & 0xFF); buffer[offset + 3] = static_cast((value >> 24) & 0xFF); buffer[offset + 4] = static_cast((value >> 32) & 0xFF); buffer[offset + 5] = static_cast((value >> 40) & 0xFF); buffer[offset + 6] = static_cast((value >> 48) & 0xFF); buffer[offset + 7] = static_cast((value >> 56) & 0xFF); } void WriteUint32(unsigned char* buffer, unsigned int offset, uint32_t value) { ARM_PIPE_ASSERT(buffer); buffer[offset] = static_cast(value & 0xFF); buffer[offset + 1] = static_cast((value >> 8) & 0xFF); buffer[offset + 2] = static_cast((value >> 16) & 0xFF); buffer[offset + 3] = static_cast((value >> 24) & 0xFF); } void WriteUint16(unsigned char* buffer, unsigned int offset, uint16_t value) { ARM_PIPE_ASSERT(buffer); buffer[offset] = static_cast(value & 0xFF); buffer[offset + 1] = static_cast((value >> 8) & 0xFF); } void WriteUint8(unsigned char* buffer, unsigned int offset, uint8_t value) { ARM_PIPE_ASSERT(buffer); buffer[offset] = static_cast(value); } std::string CentreAlignFormatting(const std::string& stringToPass, const int spacingWidth) { std::stringstream outputStream, centrePadding; int padding = spacingWidth - static_cast(stringToPass.size()); for (int i = 0; i < padding / 2; ++i) { centrePadding << " "; } outputStream << centrePadding.str() << stringToPass << centrePadding.str(); if (padding > 0 && padding %2 != 0) { outputStream << " "; } return outputStream.str(); } void PrintDeviceDetails(const std::pair>& devicePair) { std::string body; body.append(CentreAlignFormatting(devicePair.second->m_Name, 20)); body.append(" | "); body.append(CentreAlignFormatting(std::to_string(devicePair.first), 13)); body.append(" | "); body.append(CentreAlignFormatting(std::to_string(devicePair.second->m_Cores), 10)); body.append("\n"); std::cout << std::string(body.size(), '-') << "\n"; std::cout<< body; } void PrintCounterSetDetails(const std::pair>& counterSetPair) { std::string body; body.append(CentreAlignFormatting(counterSetPair.second->m_Name, 20)); body.append(" | "); body.append(CentreAlignFormatting(std::to_string(counterSetPair.first), 13)); body.append(" | "); body.append(CentreAlignFormatting(std::to_string(counterSetPair.second->m_Count), 10)); body.append("\n"); std::cout << std::string(body.size(), '-') << "\n"; std::cout<< body; } void PrintCounterDetails(std::shared_ptr& counter) { std::string body; body.append(CentreAlignFormatting(counter->m_Name, 20)); body.append(" | "); body.append(CentreAlignFormatting(counter->m_Description, 50)); body.append(" | "); body.append(CentreAlignFormatting(counter->m_Units, 14)); body.append(" | "); body.append(CentreAlignFormatting(std::to_string(counter->m_Uid), 6)); body.append(" | "); body.append(CentreAlignFormatting(std::to_string(counter->m_MaxCounterUid), 10)); body.append(" | "); body.append(CentreAlignFormatting(std::to_string(counter->m_Class), 8)); body.append(" | "); body.append(CentreAlignFormatting(std::to_string(counter->m_Interpolation), 14)); body.append(" | "); body.append(CentreAlignFormatting(std::to_string(counter->m_Multiplier), 20)); body.append(" | "); body.append(CentreAlignFormatting(std::to_string(counter->m_CounterSetUid), 16)); body.append(" | "); body.append(CentreAlignFormatting(std::to_string(counter->m_DeviceUid), 14)); body.append("\n"); std::cout << std::string(body.size(), '-') << "\n"; std::cout << body; } void PrintCategoryDetails(const std::unique_ptr& category, std::unordered_map> counterMap) { std::string categoryBody; std::string categoryHeader; categoryHeader.append(CentreAlignFormatting("Name", 20)); categoryHeader.append(" | "); categoryHeader.append(CentreAlignFormatting("Event Count", 14)); categoryHeader.append("\n"); categoryBody.append(CentreAlignFormatting(category->m_Name, 20)); categoryBody.append(" | "); categoryBody.append(CentreAlignFormatting(std::to_string(category->m_Counters.size()), 14)); std::cout << "\n" << "\n"; std::cout << CentreAlignFormatting("CATEGORY", static_cast(categoryHeader.size())); std::cout << "\n"; std::cout << std::string(categoryHeader.size(), '=') << "\n"; std::cout << categoryHeader; std::cout << std::string(categoryBody.size(), '-') << "\n"; std::cout << categoryBody; std::string counterHeader; counterHeader.append(CentreAlignFormatting("Counter Name", 20)); counterHeader.append(" | "); counterHeader.append(CentreAlignFormatting("Description", 50)); counterHeader.append(" | "); counterHeader.append(CentreAlignFormatting("Units", 14)); counterHeader.append(" | "); counterHeader.append(CentreAlignFormatting("UID", 6)); counterHeader.append(" | "); counterHeader.append(CentreAlignFormatting("Max UID", 10)); counterHeader.append(" | "); counterHeader.append(CentreAlignFormatting("Class", 8)); counterHeader.append(" | "); counterHeader.append(CentreAlignFormatting("Interpolation", 14)); counterHeader.append(" | "); counterHeader.append(CentreAlignFormatting("Multiplier", 20)); counterHeader.append(" | "); counterHeader.append(CentreAlignFormatting("Counter set UID", 16)); counterHeader.append(" | "); counterHeader.append(CentreAlignFormatting("Device UID", 14)); counterHeader.append("\n"); std::cout << "\n" << "\n"; std::cout << CentreAlignFormatting("EVENTS IN CATEGORY: " + category->m_Name, static_cast(counterHeader.size())); std::cout << "\n"; std::cout << std::string(counterHeader.size(), '=') << "\n"; std::cout << counterHeader; for (auto& it: category->m_Counters) { auto search = counterMap.find(it); if(search != counterMap.end()) { PrintCounterDetails(search->second); } } } void PrintCounterDirectory(ICounterDirectory& counterDirectory) { std::string devicesHeader; devicesHeader.append(CentreAlignFormatting("Device name", 20)); devicesHeader.append(" | "); devicesHeader.append(CentreAlignFormatting("UID", 13)); devicesHeader.append(" | "); devicesHeader.append(CentreAlignFormatting("Cores", 10)); devicesHeader.append("\n"); std::cout << "\n" << "\n"; std::cout << CentreAlignFormatting("DEVICES", static_cast(devicesHeader.size())); std::cout << "\n"; std::cout << std::string(devicesHeader.size(), '=') << "\n"; std::cout << devicesHeader; for (auto& it: counterDirectory.GetDevices()) { PrintDeviceDetails(it); } std::string counterSetHeader; counterSetHeader.append(CentreAlignFormatting("Counter set name", 20)); counterSetHeader.append(" | "); counterSetHeader.append(CentreAlignFormatting("UID", 13)); counterSetHeader.append(" | "); counterSetHeader.append(CentreAlignFormatting("Count", 10)); counterSetHeader.append("\n"); std::cout << "\n" << "\n"; std::cout << CentreAlignFormatting("COUNTER SETS", static_cast(counterSetHeader.size())); std::cout << "\n"; std::cout << std::string(counterSetHeader.size(), '=') << "\n"; std::cout << counterSetHeader; for (auto& it: counterDirectory.GetCounterSets()) { PrintCounterSetDetails(it); } auto counters = counterDirectory.GetCounters(); for (auto& it: counterDirectory.GetCategories()) { PrintCategoryDetails(it, counters); } std::cout << "\n"; } namespace { void ThrowIfCantGenerateNextUid(uint16_t uid, uint16_t cores = 0) { // Check that it is possible to generate the next UID without causing an overflow switch (cores) { case 0: case 1: // Number of cores not specified or set to 1 (a value of zero indicates the device is not capable of // running multiple parallel workloads and will not provide multiple streams of data for each event) if (uid == std::numeric_limits::max()) { throw arm::pipe::ProfilingException("Generating the next UID for profiling would result in an overflow"); } break; default: // cores > 1 // Multiple cores available, as max_counter_uid has to be set to: counter_uid + cores - 1, the maximum // allowed value for a counter UID is consequently: uint16_t_max - cores + 1 if (uid >= std::numeric_limits::max() - cores + 1) { throw arm::pipe::ProfilingException("Generating the next UID for profiling would result in an overflow"); } break; } } } // Anonymous namespace uint16_t GetNextUid(bool peekOnly) { // The UID used for profiling objects and events. The first valid UID is 1, as 0 is a reserved value static uint16_t uid = 1; // Check that it is possible to generate the next UID without causing an overflow (throws in case of error) ThrowIfCantGenerateNextUid(uid); if (peekOnly) { // Peek only return uid; } else { // Get the next UID return uid++; } } std::vector GetNextCounterUids(uint16_t firstUid, uint16_t cores) { // Check that it is possible to generate the next counter UID without causing an overflow (throws in case of error) ThrowIfCantGenerateNextUid(firstUid, cores); // Get the next counter UIDs size_t counterUidsSize = cores == 0 ? 1 : cores; std::vector counterUids(counterUidsSize, 0); for (size_t i = 0; i < counterUidsSize; i++) { counterUids[i] = firstUid++; } return counterUids; } } // namespace pipe } // namespace arm