IVGCVSW-4072 Add stream header to Timeline Message Directory packet
* Refactored the WriteTimelineMessageDirectoryPacket function
* Added the stream header to the packet
* Updated decoders/parsers
* Updated unit tests accordingly
* Minor refactoring
Signed-off-by: Matteo Martincigh <matteo.martincigh@arm.com>
Change-Id: I58f15fde54adc6414ca9fd5fb8d6157cad867339
diff --git a/src/profiling/ProfilingUtils.cpp b/src/profiling/ProfilingUtils.cpp
index 4dde235..8a7d914 100644
--- a/src/profiling/ProfilingUtils.cpp
+++ b/src/profiling/ProfilingUtils.cpp
@@ -134,6 +134,13 @@
WriteUint16(packetBuffer->GetWritableData(), offset, value);
}
+void WriteUint8(const IPacketBufferPtr& packetBuffer, unsigned int offset, uint8_t value)
+{
+ BOOST_ASSERT(packetBuffer);
+
+ WriteUint8(packetBuffer->GetWritableData(), offset, value);
+}
+
void WriteBytes(unsigned char* buffer, unsigned int offset, const void* value, unsigned int valueSize)
{
BOOST_ASSERT(buffer);
@@ -177,6 +184,13 @@
buffer[offset + 1] = static_cast<unsigned char>((value >> 8) & 0xFF);
}
+void WriteUint8(unsigned char* buffer, unsigned int offset, uint8_t value)
+{
+ BOOST_ASSERT(buffer);
+
+ buffer[offset] = static_cast<unsigned char>(value);
+}
+
void ReadBytes(const IPacketBufferPtr& packetBuffer, unsigned int offset, unsigned int valueSize, uint8_t outValue[])
{
BOOST_ASSERT(packetBuffer);
@@ -294,6 +308,91 @@
return name;
}
+// Calculate the actual length an SwString will be including the terminating null character
+// padding to bring it to the next uint32_t boundary but minus the leading uint32_t encoding
+// the size to allow the offset to be correctly updated when decoding a binary packet.
+uint32_t CalculateSizeOfPaddedSwString(const std::string& str)
+{
+ std::vector<uint32_t> swTraceString;
+ StringToSwTraceString<SwTraceCharPolicy>(str, swTraceString);
+ unsigned int uint32_t_size = sizeof(uint32_t);
+ uint32_t size = (boost::numeric_cast<uint32_t>(swTraceString.size()) - 1) * uint32_t_size;
+ return size;
+}
+
+// Read TimelineMessageDirectoryPacket from given IPacketBuffer and offset
+SwTraceMessage ReadSwTraceMessage(const unsigned char* packetBuffer, unsigned int& offset)
+{
+ BOOST_ASSERT(packetBuffer);
+
+ unsigned int uint32_t_size = sizeof(uint32_t);
+
+ SwTraceMessage swTraceMessage;
+
+ // Read the decl_id
+ uint32_t readDeclId = ReadUint32(packetBuffer, offset);
+ swTraceMessage.m_Id = readDeclId;
+
+ // SWTrace "namestring" format
+ // length of the string (first 4 bytes) + string + null terminator
+
+ // Check the decl_name
+ offset += uint32_t_size;
+ uint32_t swTraceDeclNameLength = ReadUint32(packetBuffer, offset);
+
+ offset += uint32_t_size;
+ std::vector<unsigned char> swTraceStringBuffer(swTraceDeclNameLength - 1);
+ std::memcpy(swTraceStringBuffer.data(),
+ packetBuffer + offset, swTraceStringBuffer.size());
+
+ swTraceMessage.m_Name.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end()); // name
+
+ // Check the ui_name
+ offset += CalculateSizeOfPaddedSwString(swTraceMessage.m_Name);
+ uint32_t swTraceUINameLength = ReadUint32(packetBuffer, offset);
+
+ offset += uint32_t_size;
+ swTraceStringBuffer.resize(swTraceUINameLength - 1);
+ std::memcpy(swTraceStringBuffer.data(),
+ packetBuffer + offset, swTraceStringBuffer.size());
+
+ swTraceMessage.m_UiName.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end()); // ui_name
+
+ // Check arg_types
+ offset += CalculateSizeOfPaddedSwString(swTraceMessage.m_UiName);
+ uint32_t swTraceArgTypesLength = ReadUint32(packetBuffer, offset);
+
+ offset += uint32_t_size;
+ swTraceStringBuffer.resize(swTraceArgTypesLength - 1);
+ std::memcpy(swTraceStringBuffer.data(),
+ packetBuffer + offset, swTraceStringBuffer.size());
+
+ swTraceMessage.m_ArgTypes.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end()); // arg_types
+
+ std::string swTraceString(swTraceStringBuffer.begin(), swTraceStringBuffer.end());
+
+ // Check arg_names
+ offset += CalculateSizeOfPaddedSwString(swTraceString);
+ uint32_t swTraceArgNamesLength = ReadUint32(packetBuffer, offset);
+
+ offset += uint32_t_size;
+ swTraceStringBuffer.resize(swTraceArgNamesLength - 1);
+ std::memcpy(swTraceStringBuffer.data(),
+ packetBuffer + offset, swTraceStringBuffer.size());
+
+ swTraceString.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end());
+ std::stringstream stringStream(swTraceString);
+ std::string argName;
+ while (std::getline(stringStream, argName, ','))
+ {
+ swTraceMessage.m_ArgNames.push_back(argName);
+ }
+
+ offset += CalculateSizeOfPaddedSwString(swTraceString);
+
+ return swTraceMessage;
+}
+
/// Creates a timeline packet header
///
/// \params
@@ -334,91 +433,6 @@
return std::make_pair(packetHeaderWord0, packetHeaderWord1);
}
-// Calculate the actual length an SwString will be including the terminating null character
-// padding to bring it to the next uint32_t boundary but minus the leading uint32_t encoding
-// the size to allow the offset to be correctly updated when decoding a binary packet.
-uint32_t CalculateSizeOfPaddedSwString(const std::string& str)
-{
- std::vector<uint32_t> swTraceString;
- StringToSwTraceString<SwTraceCharPolicy>(str, swTraceString);
- unsigned int uint32_t_size = sizeof(uint32_t);
- uint32_t size = (boost::numeric_cast<uint32_t>(swTraceString.size()) - 1) * uint32_t_size;
- return size;
-}
-
-// Read TimelineMessageDirectoryPacket from given IPacketBuffer and offset
-SwTraceMessage ReadSwTraceMessage(const unsigned char* packetBuffer, unsigned int& offset)
-{
- BOOST_ASSERT(packetBuffer);
-
- unsigned int uint32_t_size = sizeof(uint32_t);
-
- SwTraceMessage swTraceMessage;
-
- // Read the decl_id
- uint32_t readDeclId = ReadUint32(packetBuffer, offset);
- swTraceMessage.id = readDeclId;
-
- // SWTrace "namestring" format
- // length of the string (first 4 bytes) + string + null terminator
-
- // Check the decl_name
- offset += uint32_t_size;
- uint32_t swTraceDeclNameLength = ReadUint32(packetBuffer, offset);
-
- offset += uint32_t_size;
- std::vector<unsigned char> swTraceStringBuffer(swTraceDeclNameLength - 1);
- std::memcpy(swTraceStringBuffer.data(),
- packetBuffer + offset, swTraceStringBuffer.size());
-
- swTraceMessage.name.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end()); // name
-
- // Check the ui_name
- offset += CalculateSizeOfPaddedSwString(swTraceMessage.name);
- uint32_t swTraceUINameLength = ReadUint32(packetBuffer, offset);
-
- offset += uint32_t_size;
- swTraceStringBuffer.resize(swTraceUINameLength - 1);
- std::memcpy(swTraceStringBuffer.data(),
- packetBuffer + offset, swTraceStringBuffer.size());
-
- swTraceMessage.uiName.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end()); // ui_name
-
- // Check arg_types
- offset += CalculateSizeOfPaddedSwString(swTraceMessage.uiName);
- uint32_t swTraceArgTypesLength = ReadUint32(packetBuffer, offset);
-
- offset += uint32_t_size;
- swTraceStringBuffer.resize(swTraceArgTypesLength - 1);
- std::memcpy(swTraceStringBuffer.data(),
- packetBuffer + offset, swTraceStringBuffer.size());
-
- swTraceMessage.argTypes.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end()); // arg_types
-
- std::string swTraceString(swTraceStringBuffer.begin(), swTraceStringBuffer.end());
-
- // Check arg_names
- offset += CalculateSizeOfPaddedSwString(swTraceString);
- uint32_t swTraceArgNamesLength = ReadUint32(packetBuffer, offset);
-
- offset += uint32_t_size;
- swTraceStringBuffer.resize(swTraceArgNamesLength - 1);
- std::memcpy(swTraceStringBuffer.data(),
- packetBuffer + offset, swTraceStringBuffer.size());
-
- swTraceString.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end());
- std::stringstream stringStream(swTraceString);
- std::string argName;
- while (std::getline(stringStream, argName, ','))
- {
- swTraceMessage.argNames.push_back(argName);
- }
-
- offset += CalculateSizeOfPaddedSwString(swTraceString);
-
- return swTraceMessage;
-}
-
/// Creates a packet header for the timeline messages:
/// * declareLabel
/// * declareEntity
@@ -675,11 +689,15 @@
}
// Utils
+ unsigned int uint8_t_size = sizeof(uint8_t);
unsigned int uint32_t_size = sizeof(uint32_t);
+ unsigned int uint64_t_size = sizeof(uint64_t);
+ unsigned int threadId_size = sizeof(std::thread::id);
// The payload/data of the packet consists of swtrace event definitions encoded according
// to the swtrace directory specification. The messages being the five defined below:
- // | decl_id | decl_name | ui_name | arg_types | arg_names |
+ //
+ // | decl_id | decl_name | ui_name | arg_types | arg_names |
// |-----------|---------------------|-----------------------|-------------|-------------------------------------|
// | 0 | declareLabel | declare label | ps | guid,value |
// | 1 | declareEntity | declare entity | p | guid |
@@ -687,42 +705,50 @@
// | 3 | declareRelationship | declare relationship | Ippp | relationshipType,relationshipGuid, |
// | | | | | headGuid,tailGuid |
// | 4 | declareEvent | declare event | @tp | timestamp,threadId,eventGuid |
-
std::vector<std::vector<std::string>> timelineDirectoryMessages
{
- {"declareLabel", "declare label", "ps", "guid,value"},
- {"declareEntity", "declare entity", "p", "guid"},
- {"declareEventClass", "declare event class", "p", "guid"},
- {"declareRelationship", "declare relationship", "Ippp", "relationshipType,relationshipGuid,headGuid,tailGuid"},
- {"declareEvent", "declare event", "@tp", "timestamp,threadId,eventGuid"}
+ { "0", "declareLabel", "declare label", "ps", "guid,value" },
+ { "1", "declareEntity", "declare entity", "p", "guid" },
+ { "2", "declareEventClass", "declare event class", "p", "guid" },
+ { "3", "declareRelationship", "declare relationship", "Ippp",
+ "relationshipType,relationshipGuid,headGuid,tailGuid" },
+ { "4", "declareEvent", "declare event", "@tp", "timestamp,threadId,eventGuid" }
};
- unsigned int messagesDataLength = 0u;
- std::vector<std::vector<std::vector<uint32_t>>> swTraceTimelineDirectoryMessages;
-
- for (const auto& timelineDirectoryMessage : timelineDirectoryMessages)
+ // Build the message declarations
+ std::vector<uint32_t> swTraceBuffer;
+ for (const auto& directoryComponent : timelineDirectoryMessages)
{
- messagesDataLength += uint32_t_size; // decl_id
-
- std::vector<std::vector<uint32_t>> swTraceStringsVector;
- for (const auto& label : timelineDirectoryMessage)
+ // decl_id
+ uint32_t declId = 0;
+ try
{
- std::vector<uint32_t> swTraceString;
- bool result = StringToSwTraceString<SwTraceCharPolicy>(label, swTraceString);
- if (!result)
- {
- return TimelinePacketStatus::Error;
- }
-
- messagesDataLength += boost::numeric_cast<unsigned int>(swTraceString.size()) * uint32_t_size;
- swTraceStringsVector.push_back(swTraceString);
+ declId = boost::numeric_cast<uint32_t>(std::stoul(directoryComponent[0]));
}
- swTraceTimelineDirectoryMessages.push_back(swTraceStringsVector);
+ catch (const std::exception&)
+ {
+ return TimelinePacketStatus::Error;
+ }
+ swTraceBuffer.push_back(declId);
+
+ bool result = true;
+ result &= ConvertDirectoryComponent<SwTraceNameCharPolicy>(directoryComponent[1], swTraceBuffer); // decl_name
+ result &= ConvertDirectoryComponent<SwTraceCharPolicy> (directoryComponent[2], swTraceBuffer); // ui_name
+ result &= ConvertDirectoryComponent<SwTraceTypeCharPolicy>(directoryComponent[3], swTraceBuffer); // arg_types
+ result &= ConvertDirectoryComponent<SwTraceCharPolicy> (directoryComponent[4], swTraceBuffer); // arg_names
+ if (!result)
+ {
+ return TimelinePacketStatus::Error;
+ }
}
+ unsigned int dataLength = 3 * uint8_t_size + // Stream header (3 bytes)
+ boost::numeric_cast<unsigned int>(swTraceBuffer.size()) *
+ uint32_t_size; // Trace directory (5 messages)
+
// Calculate the timeline directory binary packet size (in bytes)
unsigned int timelineDirectoryPacketSize = 2 * uint32_t_size + // Header (2 words)
- messagesDataLength; // 5 messages length
+ dataLength; // Payload
// Check whether the timeline directory binary packet fits in the given buffer
if (timelineDirectoryPacketSize > bufferSize)
@@ -731,8 +757,7 @@
}
// Create packet header
- uint32_t dataLength = boost::numeric_cast<uint32_t>(messagesDataLength);
- std::pair<uint32_t, uint32_t> packetHeader = CreateTimelinePacketHeader(1, 0, 0, 0, 0, dataLength);
+ auto packetHeader = CreateTimelinePacketHeader(1, 0, 0, 0, 0, boost::numeric_cast<uint32_t>(dataLength));
// Initialize the offset for writing in the buffer
unsigned int offset = 0;
@@ -743,23 +768,33 @@
WriteUint32(buffer, offset, packetHeader.second);
offset += uint32_t_size;
- WriteUint32(buffer, offset, static_cast<uint32_t >(swTraceTimelineDirectoryMessages.size()));
- offset += uint32_t_size;
-
- for (unsigned int i = 0u; i < swTraceTimelineDirectoryMessages.size(); ++i)
+ // Write the stream header
+ uint8_t streamVersion = 4;
+ uint8_t pointerBytes = boost::numeric_cast<uint8_t>(uint64_t_size); // All GUIDs are uint64_t
+ uint8_t threadIdBytes = boost::numeric_cast<uint8_t>(threadId_size);
+ switch (threadIdBytes)
{
- // Write the timeline binary packet payload to the buffer
- WriteUint32(buffer, offset, i); // decl_id
- offset += uint32_t_size;
+ case 4: // Typically Windows and Android
+ case 8: // Typically Linux
+ break; // Valid values
+ default:
+ return TimelinePacketStatus::Error; // Invalid value
+ }
+ WriteUint8(buffer, offset, streamVersion);
+ offset += uint8_t_size;
+ WriteUint8(buffer, offset, pointerBytes);
+ offset += uint8_t_size;
+ WriteUint8(buffer, offset, threadIdBytes);
+ offset += uint8_t_size;
- for (std::vector<uint32_t> swTraceString : swTraceTimelineDirectoryMessages[i])
- {
- for (uint32_t swTraceDeclStringWord : swTraceString)
- {
- WriteUint32(buffer, offset, swTraceDeclStringWord);
- offset += uint32_t_size;
- }
- }
+ // Write the SWTrace directory
+ uint32_t numberOfDeclarations = boost::numeric_cast<uint32_t>(timelineDirectoryMessages.size());
+ WriteUint32(buffer, offset, numberOfDeclarations); // Number of declarations
+ offset += uint32_t_size;
+ for (uint32_t i : swTraceBuffer)
+ {
+ WriteUint32(buffer, offset, i); // Message declarations
+ offset += uint32_t_size;
}
// Update the number of bytes written