blob: 94a5db223e514fd250894eb33e8003a23e613706 [file] [log] [blame]
//
// Copyright © 2017 Arm Ltd. All rights reserved.
// SPDX-License-Identifier: MIT
//
#include "SendCounterPacket.hpp"
#include "EncodeVersion.hpp"
#include "ProfilingUtils.hpp"
#include <armnn/Exceptions.hpp>
#include <boost/format.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/core/ignore_unused.hpp>
#include <cstring>
namespace armnn
{
namespace profiling
{
using boost::numeric_cast;
const unsigned int SendCounterPacket::PIPE_MAGIC;
const unsigned int SendCounterPacket::MAX_METADATA_PACKET_LENGTH;
void SendCounterPacket::SendStreamMetaDataPacket()
{
std::string info(GetSoftwareInfo());
std::string hardwareVersion(GetHardwareVersion());
std::string softwareVersion(GetSoftwareVersion());
std::string processName = GetProcessName().substr(0, 60);
uint32_t infoSize = numeric_cast<uint32_t>(info.size()) > 0 ? numeric_cast<uint32_t>(info.size()) + 1 : 0;
uint32_t hardwareVersionSize = numeric_cast<uint32_t>(hardwareVersion.size()) > 0 ?
numeric_cast<uint32_t>(hardwareVersion.size()) + 1 : 0;
uint32_t softwareVersionSize = numeric_cast<uint32_t>(softwareVersion.size()) > 0 ?
numeric_cast<uint32_t>(softwareVersion.size()) + 1 : 0;
uint32_t processNameSize = numeric_cast<uint32_t>(processName.size()) > 0 ?
numeric_cast<uint32_t>(processName.size()) + 1 : 0;
uint32_t sizeUint32 = numeric_cast<uint32_t>(sizeof(uint32_t));
uint32_t headerSize = 2 * sizeUint32;
uint32_t bodySize = 10 * sizeUint32;
uint32_t packetVersionCountSize = sizeUint32;
// Supported Packets
// Stream metadata packet (packet family=0; packet id=0)
// Connection Acknowledged packet (packet family=0, packet id=1)
// Counter Directory packet (packet family=0; packet id=2)
// Request Counter Directory packet (packet family=0, packet id=3)
// Periodic Counter Selection packet (packet family=0, packet id=4)
uint32_t packetVersionEntries = 5;
uint32_t payloadSize = numeric_cast<uint32_t>(infoSize + hardwareVersionSize + softwareVersionSize +
processNameSize + packetVersionCountSize +
(packetVersionEntries * 2 * sizeUint32));
uint32_t totalSize = headerSize + bodySize + payloadSize;
uint32_t offset = 0;
uint32_t reserved = 0;
unsigned char *writeBuffer = m_Buffer.Reserve(totalSize, reserved);
if (reserved < totalSize)
{
CancelOperationAndThrow<BufferExhaustion>(
boost::str(boost::format("No space left in buffer. Unable to reserve (%1%) bytes.")
% totalSize));
}
if (writeBuffer == nullptr)
{
CancelOperationAndThrow<RuntimeException>("Error reserving buffer memory.");
}
try
{
// Create header
WriteUint32(writeBuffer, offset, 0);
offset += sizeUint32;
WriteUint32(writeBuffer, offset, totalSize - headerSize);
// Packet body
offset += sizeUint32;
WriteUint32(writeBuffer, offset, PIPE_MAGIC); // pipe_magic
offset += sizeUint32;
WriteUint32(writeBuffer, offset, EncodeVersion(1, 0, 0)); // stream_metadata_version
offset += sizeUint32;
WriteUint32(writeBuffer, offset, MAX_METADATA_PACKET_LENGTH); // max_data_length
offset += sizeUint32;
WriteUint32(writeBuffer, offset, numeric_cast<uint32_t>(getpid())); // pid
offset += sizeUint32;
uint32_t poolOffset = bodySize;
WriteUint32(writeBuffer, offset, infoSize ? poolOffset : 0); // offset_info
offset += sizeUint32;
poolOffset += infoSize;
WriteUint32(writeBuffer, offset, hardwareVersionSize ? poolOffset : 0); // offset_hw_version
offset += sizeUint32;
poolOffset += hardwareVersionSize;
WriteUint32(writeBuffer, offset, softwareVersionSize ? poolOffset : 0); // offset_sw_version
offset += sizeUint32;
poolOffset += softwareVersionSize;
WriteUint32(writeBuffer, offset, processNameSize ? poolOffset : 0); // offset_process_name
offset += sizeUint32;
poolOffset += processNameSize;
WriteUint32(writeBuffer, offset, packetVersionEntries ? poolOffset : 0); // offset_packet_version_table
offset += sizeUint32;
WriteUint32(writeBuffer, offset, 0); // reserved
offset += sizeUint32;
// Pool
if (infoSize)
{
memcpy(&writeBuffer[offset], info.c_str(), infoSize);
offset += infoSize;
}
if (hardwareVersionSize)
{
memcpy(&writeBuffer[offset], hardwareVersion.c_str(), hardwareVersionSize);
offset += hardwareVersionSize;
}
if (softwareVersionSize)
{
memcpy(&writeBuffer[offset], softwareVersion.c_str(), softwareVersionSize);
offset += softwareVersionSize;
}
if (processNameSize)
{
memcpy(&writeBuffer[offset], processName.c_str(), processNameSize);
offset += processNameSize;
}
if (packetVersionEntries)
{
// Packet Version Count
WriteUint32(writeBuffer, offset, packetVersionEntries << 16);
// Packet Version Entries
uint32_t packetFamily = 0;
uint32_t packetId = 0;
offset += sizeUint32;
for (uint32_t i = 0; i < packetVersionEntries; ++i) {
WriteUint32(writeBuffer, offset, ((packetFamily & 0x3F) << 26) | ((packetId++ & 0x3FF) << 16));
offset += sizeUint32;
WriteUint32(writeBuffer, offset, EncodeVersion(1, 0, 0));
offset += sizeUint32;
}
}
}
catch(...)
{
CancelOperationAndThrow<RuntimeException>("Error processing packet.");
}
m_Buffer.Commit(totalSize);
}
void SendCounterPacket::SendCounterDirectoryPacket(const CounterDirectory& counterDirectory)
{
throw armnn::UnimplementedException();
}
void SendCounterPacket::SendPeriodicCounterCapturePacket(uint64_t timestamp, const IndexValuePairsVector& values)
{
uint32_t packetFamily = 1;
uint32_t packetClass = 0;
uint32_t packetType = 0;
uint32_t headerSize = numeric_cast<uint32_t>(2 * sizeof(uint32_t));
uint32_t bodySize = numeric_cast<uint32_t>((1 * sizeof(uint64_t)) +
(values.size() * (sizeof(uint16_t) + sizeof(uint32_t))));
uint32_t totalSize = headerSize + bodySize;
uint32_t offset = 0;
uint32_t reserved = 0;
unsigned char* writeBuffer = m_Buffer.Reserve(totalSize, reserved);
if (reserved < totalSize)
{
CancelOperationAndThrow<BufferExhaustion>(
boost::str(boost::format("No space left in buffer. Unable to reserve (%1%) bytes.")
% totalSize));
}
if (writeBuffer == nullptr)
{
CancelOperationAndThrow<RuntimeException>("Error reserving buffer memory.");
}
// Create header.
WriteUint32(writeBuffer,
offset,
((packetFamily & 0x3F) << 26) | ((packetClass & 0x3FF) << 19) | ((packetType & 0x3FFF) << 16));
offset += numeric_cast<uint32_t>(sizeof(uint32_t));
WriteUint32(writeBuffer, offset, bodySize);
// Copy captured Timestamp.
offset += numeric_cast<uint32_t>(sizeof(uint32_t));
WriteUint64(writeBuffer, offset, timestamp);
// Copy selectedCounterIds.
offset += numeric_cast<uint32_t>(sizeof(uint64_t));
for (const auto& pair: values)
{
WriteUint16(writeBuffer, offset, pair.first);
offset += numeric_cast<uint32_t>(sizeof(uint16_t));
WriteUint32(writeBuffer, offset, pair.second);
offset += numeric_cast<uint32_t>(sizeof(uint32_t));
}
m_Buffer.Commit(totalSize);
}
void SendCounterPacket::SendPeriodicCounterSelectionPacket(uint32_t capturePeriod,
const std::vector<uint16_t>& selectedCounterIds)
{
uint32_t packetFamily = 0;
uint32_t packetId = 4;
uint32_t headerSize = numeric_cast<uint32_t>(2 * sizeof(uint32_t));
uint32_t bodySize = numeric_cast<uint32_t>((1 * sizeof(uint32_t)) +
(selectedCounterIds.size() * sizeof(uint16_t)));
uint32_t totalSize = headerSize + bodySize;
uint32_t offset = 0;
uint32_t reserved = 0;
unsigned char* writeBuffer = m_Buffer.Reserve(totalSize, reserved);
if (reserved < totalSize)
{
CancelOperationAndThrow<BufferExhaustion>(
boost::str(boost::format("No space left in buffer. Unable to reserve (%1%) bytes.")
% totalSize));
}
if (writeBuffer == nullptr)
{
CancelOperationAndThrow<RuntimeException>("Error reserving buffer memory.");
}
// Create header.
WriteUint32(writeBuffer, offset, ((packetFamily & 0x3F) << 26) | ((packetId & 0x3FF) << 16));
offset += numeric_cast<uint32_t>(sizeof(uint32_t));
WriteUint32(writeBuffer, offset, bodySize);
// Copy capturePeriod.
offset += numeric_cast<uint32_t>(sizeof(uint32_t));
WriteUint32(writeBuffer, offset, capturePeriod);
// Copy selectedCounterIds.
offset += numeric_cast<uint32_t>(sizeof(uint32_t));
for(const uint16_t& id: selectedCounterIds)
{
WriteUint16(writeBuffer, offset, id);
offset += numeric_cast<uint32_t>(sizeof(uint16_t));
}
m_Buffer.Commit(totalSize);
}
void SendCounterPacket::SetReadyToRead()
{
m_ReadyToRead = true;
}
} // namespace profiling
} // namespace armnn