blob: 01bc461dd27a1dce7584729a990beda177b2b073 [file] [log] [blame]
//
// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
// SPDX-License-Identifier: MIT
//
#include <common/include/Assert.hpp>
#include <common/include/CommonProfilingUtils.hpp>
#include <common/include/ProfilingException.hpp>
#include <iostream>
#include <limits>
#include <sstream>
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<uint8_t>(buffer[offset]);
}
}
uint64_t ReadUint64(const unsigned char* buffer, unsigned int offset)
{
ARM_PIPE_ASSERT(buffer);
uint64_t value = 0;
value = static_cast<uint64_t>(buffer[offset]);
value |= static_cast<uint64_t>(buffer[offset + 1]) << 8;
value |= static_cast<uint64_t>(buffer[offset + 2]) << 16;
value |= static_cast<uint64_t>(buffer[offset + 3]) << 24;
value |= static_cast<uint64_t>(buffer[offset + 4]) << 32;
value |= static_cast<uint64_t>(buffer[offset + 5]) << 40;
value |= static_cast<uint64_t>(buffer[offset + 6]) << 48;
value |= static_cast<uint64_t>(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<uint32_t>(buffer[offset]);
value |= static_cast<uint32_t>(buffer[offset + 1]) << 8;
value |= static_cast<uint32_t>(buffer[offset + 2]) << 16;
value |= static_cast<uint32_t>(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<uint32_t>(buffer[offset]);
value |= static_cast<uint32_t>(buffer[offset + 1]) << 8;
return static_cast<uint16_t>(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<const unsigned char*>(value) + i);
}
}
void WriteUint64(unsigned char* buffer, unsigned int offset, uint64_t value)
{
ARM_PIPE_ASSERT(buffer);
buffer[offset] = static_cast<unsigned char>(value & 0xFF);
buffer[offset + 1] = static_cast<unsigned char>((value >> 8) & 0xFF);
buffer[offset + 2] = static_cast<unsigned char>((value >> 16) & 0xFF);
buffer[offset + 3] = static_cast<unsigned char>((value >> 24) & 0xFF);
buffer[offset + 4] = static_cast<unsigned char>((value >> 32) & 0xFF);
buffer[offset + 5] = static_cast<unsigned char>((value >> 40) & 0xFF);
buffer[offset + 6] = static_cast<unsigned char>((value >> 48) & 0xFF);
buffer[offset + 7] = static_cast<unsigned char>((value >> 56) & 0xFF);
}
void WriteUint32(unsigned char* buffer, unsigned int offset, uint32_t value)
{
ARM_PIPE_ASSERT(buffer);
buffer[offset] = static_cast<unsigned char>(value & 0xFF);
buffer[offset + 1] = static_cast<unsigned char>((value >> 8) & 0xFF);
buffer[offset + 2] = static_cast<unsigned char>((value >> 16) & 0xFF);
buffer[offset + 3] = static_cast<unsigned char>((value >> 24) & 0xFF);
}
void WriteUint16(unsigned char* buffer, unsigned int offset, uint16_t value)
{
ARM_PIPE_ASSERT(buffer);
buffer[offset] = static_cast<unsigned char>(value & 0xFF);
buffer[offset + 1] = static_cast<unsigned char>((value >> 8) & 0xFF);
}
void WriteUint8(unsigned char* buffer, unsigned int offset, uint8_t value)
{
ARM_PIPE_ASSERT(buffer);
buffer[offset] = static_cast<unsigned char>(value);
}
std::string CentreAlignFormatting(const std::string& stringToPass, const int spacingWidth)
{
std::stringstream outputStream, centrePadding;
int padding = spacingWidth - static_cast<int>(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<const unsigned short, std::unique_ptr<Device>>& 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<const unsigned short, std::unique_ptr<CounterSet>>& 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>& 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>& category,
std::unordered_map<unsigned short, std::shared_ptr<Counter>> 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<int>(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<int>(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<int>(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<int>(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<uint16_t>::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<uint16_t>::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<uint16_t> 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<uint16_t> counterUids(counterUidsSize, 0);
for (size_t i = 0; i < counterUidsSize; i++)
{
counterUids[i] = firstUid++;
}
return counterUids;
}
} // namespace pipe
} // namespace arm