blob: 4426d41f4dadcf932291ab09cdfdd12667ce1757 [file] [log] [blame]
Ferran Balaguer73882172019-09-02 16:39:42 +01001//
Jim Flynn6398a982020-05-27 17:05:21 +01002// Copyright © 2019 Arm Ltd and Contributors. All rights reserved.
Ferran Balaguer73882172019-09-02 16:39:42 +01003// SPDX-License-Identifier: MIT
4//
5
6#include "ProfilingUtils.hpp"
7
Jim Flynn6730fe92022-03-10 22:57:47 +00008#include <common/include/Assert.hpp>
Jim Flynnbbfe6032020-07-20 16:57:44 +01009#include <common/include/CommonProfilingUtils.hpp>
Jim Flynn9c85b412022-03-16 00:27:43 +000010#include <common/include/NumericCast.hpp>
Jim Flynnbbfe6032020-07-20 16:57:44 +010011#include <common/include/ProfilingException.hpp>
12#include <common/include/SwTrace.hpp>
Jim Flynn4e755a52020-03-29 17:48:26 +010013
Ferran Balaguer47d0fe92019-09-04 16:47:34 +010014#include <armnn/Version.hpp>
15
Jim Flynne195a042022-04-12 17:19:28 +010016#include <chrono>
Ferran Balaguer47d0fe92019-09-04 16:47:34 +010017#include <fstream>
Keith Davis3201eea2019-10-24 17:30:41 +010018#include <iostream>
Matteo Martincighab173e92019-09-05 12:02:04 +010019#include <limits>
Ferran Balaguer47d0fe92019-09-04 16:47:34 +010020
Cathal Corbett5aa9fd72022-02-25 15:33:28 +000021namespace arm
Ferran Balaguer73882172019-09-02 16:39:42 +010022{
23
Cathal Corbett5aa9fd72022-02-25 15:33:28 +000024namespace pipe
Ferran Balaguer73882172019-09-02 16:39:42 +010025{
26
Matteo Martincigh378bbfc2019-11-04 14:05:28 +000027void WriteBytes(const IPacketBufferPtr& packetBuffer, unsigned int offset, const void* value, unsigned int valueSize)
28{
Jim Flynn6730fe92022-03-10 22:57:47 +000029 ARM_PIPE_ASSERT(packetBuffer);
Matteo Martincigh378bbfc2019-11-04 14:05:28 +000030
31 WriteBytes(packetBuffer->GetWritableData(), offset, value, valueSize);
32}
33
Keith Davis3201eea2019-10-24 17:30:41 +010034uint32_t ConstructHeader(uint32_t packetFamily,
35 uint32_t packetId)
36{
Keith Davis33ed2212020-03-30 10:43:41 +010037 return (( packetFamily & 0x0000003F ) << 26 )|
Jim Flynn83d08a92020-07-09 13:48:16 +010038 (( packetId & 0x000003FF ) << 16 );
39}
40
41uint32_t ConstructHeader(uint32_t packetFamily, uint32_t packetClass, uint32_t packetType)
42{
43 return ((packetFamily & 0x0000003F) << 26) |
44 ((packetClass & 0x0000007F) << 19) |
45 ((packetType & 0x00000007) << 16);
Keith Davis3201eea2019-10-24 17:30:41 +010046}
47
48void WriteUint64(const std::unique_ptr<IPacketBuffer>& packetBuffer, unsigned int offset, uint64_t value)
Narumol Prangnawarat404b2752019-09-24 17:23:16 +010049{
Jim Flynn6730fe92022-03-10 22:57:47 +000050 ARM_PIPE_ASSERT(packetBuffer);
Narumol Prangnawarat404b2752019-09-24 17:23:16 +010051
52 WriteUint64(packetBuffer->GetWritableData(), offset, value);
53}
54
Matteo Martincigh2ffcc412019-11-05 11:47:40 +000055void WriteUint32(const IPacketBufferPtr& packetBuffer, unsigned int offset, uint32_t value)
Narumol Prangnawarat404b2752019-09-24 17:23:16 +010056{
Jim Flynn6730fe92022-03-10 22:57:47 +000057 ARM_PIPE_ASSERT(packetBuffer);
Narumol Prangnawarat404b2752019-09-24 17:23:16 +010058
59 WriteUint32(packetBuffer->GetWritableData(), offset, value);
60}
61
Matteo Martincigh2ffcc412019-11-05 11:47:40 +000062void WriteUint16(const IPacketBufferPtr& packetBuffer, unsigned int offset, uint16_t value)
Narumol Prangnawarat404b2752019-09-24 17:23:16 +010063{
Jim Flynn6730fe92022-03-10 22:57:47 +000064 ARM_PIPE_ASSERT(packetBuffer);
Narumol Prangnawarat404b2752019-09-24 17:23:16 +010065
66 WriteUint16(packetBuffer->GetWritableData(), offset, value);
67}
68
Matteo Martincigh34a407d2019-11-06 15:30:54 +000069void WriteUint8(const IPacketBufferPtr& packetBuffer, unsigned int offset, uint8_t value)
70{
Jim Flynn6730fe92022-03-10 22:57:47 +000071 ARM_PIPE_ASSERT(packetBuffer);
Matteo Martincigh34a407d2019-11-06 15:30:54 +000072
73 WriteUint8(packetBuffer->GetWritableData(), offset, value);
74}
75
Matteo Martincigh378bbfc2019-11-04 14:05:28 +000076void ReadBytes(const IPacketBufferPtr& packetBuffer, unsigned int offset, unsigned int valueSize, uint8_t outValue[])
77{
Jim Flynn6730fe92022-03-10 22:57:47 +000078 ARM_PIPE_ASSERT(packetBuffer);
Matteo Martincigh378bbfc2019-11-04 14:05:28 +000079
80 ReadBytes(packetBuffer->GetReadableData(), offset, valueSize, outValue);
81}
82
Matteo Martincigh2ffcc412019-11-05 11:47:40 +000083uint64_t ReadUint64(const IPacketBufferPtr& packetBuffer, unsigned int offset)
Narumol Prangnawarat404b2752019-09-24 17:23:16 +010084{
Jim Flynn6730fe92022-03-10 22:57:47 +000085 ARM_PIPE_ASSERT(packetBuffer);
Narumol Prangnawarat404b2752019-09-24 17:23:16 +010086
87 return ReadUint64(packetBuffer->GetReadableData(), offset);
88}
89
Matteo Martincigh2ffcc412019-11-05 11:47:40 +000090uint32_t ReadUint32(const IPacketBufferPtr& packetBuffer, unsigned int offset)
Narumol Prangnawarat404b2752019-09-24 17:23:16 +010091{
Jim Flynn6730fe92022-03-10 22:57:47 +000092 ARM_PIPE_ASSERT(packetBuffer);
Narumol Prangnawarat404b2752019-09-24 17:23:16 +010093
94 return ReadUint32(packetBuffer->GetReadableData(), offset);
95}
96
Matteo Martincigh2ffcc412019-11-05 11:47:40 +000097uint16_t ReadUint16(const IPacketBufferPtr& packetBuffer, unsigned int offset)
Narumol Prangnawarat404b2752019-09-24 17:23:16 +010098{
Jim Flynn6730fe92022-03-10 22:57:47 +000099 ARM_PIPE_ASSERT(packetBuffer);
Narumol Prangnawarat404b2752019-09-24 17:23:16 +0100100
101 return ReadUint16(packetBuffer->GetReadableData(), offset);
102}
103
Matteo Martincigh2ffcc412019-11-05 11:47:40 +0000104uint8_t ReadUint8(const IPacketBufferPtr& packetBuffer, unsigned int offset)
Narumol Prangnawarat404b2752019-09-24 17:23:16 +0100105{
Jim Flynn6730fe92022-03-10 22:57:47 +0000106 ARM_PIPE_ASSERT(packetBuffer);
Narumol Prangnawarat404b2752019-09-24 17:23:16 +0100107
108 return ReadUint8(packetBuffer->GetReadableData(), offset);
109}
110
Ferran Balaguer47d0fe92019-09-04 16:47:34 +0100111std::string GetProcessName()
112{
113 std::ifstream comm("/proc/self/comm");
114 std::string name;
115 getline(comm, name);
116 return name;
117}
118
Jan Eilers92fa15b2019-10-15 15:23:25 +0100119/// Creates a timeline packet header
120///
121/// \params
122/// packetFamiliy Timeline Packet Family
123/// packetClass Timeline Packet Class
124/// packetType Timeline Packet Type
125/// streamId Stream identifier
126/// seqeunceNumbered When non-zero the 4 bytes following the header is a u32 sequence number
Matteo Martincigh8844c2f2019-10-16 10:29:17 +0100127/// dataLength Unsigned 24-bit integer. Length of data, in bytes. Zero is permitted
Jan Eilers92fa15b2019-10-15 15:23:25 +0100128///
129/// \returns
130/// Pair of uint32_t containing word0 and word1 of the header
131std::pair<uint32_t, uint32_t> CreateTimelinePacketHeader(uint32_t packetFamily,
132 uint32_t packetClass,
133 uint32_t packetType,
134 uint32_t streamId,
135 uint32_t sequenceNumbered,
136 uint32_t dataLength)
137{
138 // Packet header word 0:
139 // 26:31 [6] packet_family: timeline Packet Family, value 0b000001
140 // 19:25 [7] packet_class: packet class
141 // 16:18 [3] packet_type: packet type
142 // 8:15 [8] reserved: all zeros
143 // 0:7 [8] stream_id: stream identifier
144 uint32_t packetHeaderWord0 = ((packetFamily & 0x0000003F) << 26) |
145 ((packetClass & 0x0000007F) << 19) |
146 ((packetType & 0x00000007) << 16) |
147 ((streamId & 0x00000007) << 0);
148
149 // Packet header word 1:
150 // 25:31 [7] reserved: all zeros
151 // 24 [1] sequence_numbered: when non-zero the 4 bytes following the header is a u32 sequence number
152 // 0:23 [24] data_length: unsigned 24-bit integer. Length of data, in bytes. Zero is permitted
153 uint32_t packetHeaderWord1 = ((sequenceNumbered & 0x00000001) << 24) |
154 ((dataLength & 0x00FFFFFF) << 0);
155
156 return std::make_pair(packetHeaderWord0, packetHeaderWord1);
157}
158
159/// Creates a packet header for the timeline messages:
160/// * declareLabel
161/// * declareEntity
162/// * declareEventClass
163/// * declareRelationship
164/// * declareEvent
165///
166/// \param
Matteo Martincigh8844c2f2019-10-16 10:29:17 +0100167/// dataLength The length of the message body in bytes
Jan Eilers92fa15b2019-10-15 15:23:25 +0100168///
169/// \returns
170/// Pair of uint32_t containing word0 and word1 of the header
171std::pair<uint32_t, uint32_t> CreateTimelineMessagePacketHeader(unsigned int dataLength)
172{
Matteo Martincigh8844c2f2019-10-16 10:29:17 +0100173 return CreateTimelinePacketHeader(1, // Packet family
174 0, // Packet class
175 1, // Packet type
176 0, // Stream id
177 0, // Sequence number
178 dataLength); // Data length
Jan Eilers92fa15b2019-10-15 15:23:25 +0100179}
180
Matteo Martincigh0aed4f92019-10-01 14:25:34 +0100181TimelinePacketStatus WriteTimelineLabelBinaryPacket(uint64_t profilingGuid,
182 const std::string& label,
183 unsigned char* buffer,
Keith Davis97da5e22020-03-05 16:25:28 +0000184 unsigned int remainingBufferSize,
Matteo Martincigh0aed4f92019-10-01 14:25:34 +0100185 unsigned int& numberOfBytesWritten)
186{
Matteo Martincigh8844c2f2019-10-16 10:29:17 +0100187 // Initialize the output value
Matteo Martincigh0aed4f92019-10-01 14:25:34 +0100188 numberOfBytesWritten = 0;
189
190 // Check that the given buffer is valid
Keith Davis97da5e22020-03-05 16:25:28 +0000191 if (buffer == nullptr || remainingBufferSize == 0)
Matteo Martincigh0aed4f92019-10-01 14:25:34 +0100192 {
193 return TimelinePacketStatus::BufferExhaustion;
194 }
195
196 // Utils
197 unsigned int uint32_t_size = sizeof(uint32_t);
198 unsigned int uint64_t_size = sizeof(uint64_t);
199
200 // Convert the label into a SWTrace string
201 std::vector<uint32_t> swTraceLabel;
Jim Flynnbbfe6032020-07-20 16:57:44 +0100202 bool result = arm::pipe::StringToSwTraceString<arm::pipe::SwTraceCharPolicy>(label, swTraceLabel);
Matteo Martincigh0aed4f92019-10-01 14:25:34 +0100203 if (!result)
204 {
205 return TimelinePacketStatus::Error;
206 }
207
208 // Calculate the size of the SWTrace string label (in bytes)
Jim Flynn75c14f42022-03-10 22:05:42 +0000209 unsigned int swTraceLabelSize = arm::pipe::numeric_cast<unsigned int>(swTraceLabel.size()) * uint32_t_size;
Matteo Martincigh0aed4f92019-10-01 14:25:34 +0100210
211 // Calculate the length of the data (in bytes)
Jan Eilersb884ea42019-10-16 09:54:15 +0100212 unsigned int timelineLabelPacketDataLength = uint32_t_size + // decl_Id
213 uint64_t_size + // Profiling GUID
Matteo Martincigh0aed4f92019-10-01 14:25:34 +0100214 swTraceLabelSize; // Label
215
Matteo Martincigh0aed4f92019-10-01 14:25:34 +0100216 // Check whether the timeline binary packet fits in the given buffer
Keith Davis97da5e22020-03-05 16:25:28 +0000217 if (timelineLabelPacketDataLength > remainingBufferSize)
Matteo Martincigh0aed4f92019-10-01 14:25:34 +0100218 {
219 return TimelinePacketStatus::BufferExhaustion;
220 }
221
Matteo Martincigh0aed4f92019-10-01 14:25:34 +0100222 // Initialize the offset for writing in the buffer
223 unsigned int offset = 0;
224
Jan Eilersb884ea42019-10-16 09:54:15 +0100225 // Write decl_Id to the buffer
226 WriteUint32(buffer, offset, 0u);
Matteo Martincigh0aed4f92019-10-01 14:25:34 +0100227 offset += uint32_t_size;
228
229 // Write the timeline binary packet payload to the buffer
230 WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
231 offset += uint64_t_size;
232 for (uint32_t swTraceLabelWord : swTraceLabel)
233 {
234 WriteUint32(buffer, offset, swTraceLabelWord); // Label
235 offset += uint32_t_size;
236 }
237
238 // Update the number of bytes written
Keith Davis97da5e22020-03-05 16:25:28 +0000239 numberOfBytesWritten = timelineLabelPacketDataLength;
Matteo Martincigh0aed4f92019-10-01 14:25:34 +0100240
241 return TimelinePacketStatus::Ok;
242}
243
Keith Davis97da5e22020-03-05 16:25:28 +0000244TimelinePacketStatus WriteTimelineEntityBinary(uint64_t profilingGuid,
245 unsigned char* buffer,
246 unsigned int remainingBufferSize,
247 unsigned int& numberOfBytesWritten)
David Monahanf21f6062019-10-07 15:11:15 +0100248{
Matteo Martincigh8844c2f2019-10-16 10:29:17 +0100249 // Initialize the output value
David Monahanf21f6062019-10-07 15:11:15 +0100250 numberOfBytesWritten = 0;
251
252 // Check that the given buffer is valid
Keith Davis97da5e22020-03-05 16:25:28 +0000253 if (buffer == nullptr || remainingBufferSize == 0)
David Monahanf21f6062019-10-07 15:11:15 +0100254 {
255 return TimelinePacketStatus::BufferExhaustion;
256 }
257
258 // Utils
259 unsigned int uint32_t_size = sizeof(uint32_t);
260 unsigned int uint64_t_size = sizeof(uint64_t);
261
262 // Calculate the length of the data (in bytes)
Keith Davis97da5e22020-03-05 16:25:28 +0000263 unsigned int timelineEntityDataLength = uint32_t_size + uint64_t_size; // decl_id + Profiling GUID
David Monahanf21f6062019-10-07 15:11:15 +0100264
265 // Check whether the timeline binary packet fits in the given buffer
Keith Davis97da5e22020-03-05 16:25:28 +0000266 if (timelineEntityDataLength > remainingBufferSize)
David Monahanf21f6062019-10-07 15:11:15 +0100267 {
268 return TimelinePacketStatus::BufferExhaustion;
269 }
270
David Monahanf21f6062019-10-07 15:11:15 +0100271 // Initialize the offset for writing in the buffer
272 unsigned int offset = 0;
273
Jan Eilersb884ea42019-10-16 09:54:15 +0100274 // Write the decl_Id to the buffer
275 WriteUint32(buffer, offset, 1u);
David Monahanf21f6062019-10-07 15:11:15 +0100276 offset += uint32_t_size;
277
278 // Write the timeline binary packet payload to the buffer
279 WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
280
281 // Update the number of bytes written
Keith Davis97da5e22020-03-05 16:25:28 +0000282 numberOfBytesWritten = timelineEntityDataLength;
David Monahanf21f6062019-10-07 15:11:15 +0100283
284 return TimelinePacketStatus::Ok;
285}
286
Keith Davis97da5e22020-03-05 16:25:28 +0000287TimelinePacketStatus WriteTimelineRelationshipBinary(ProfilingRelationshipType relationshipType,
288 uint64_t relationshipGuid,
289 uint64_t headGuid,
290 uint64_t tailGuid,
Finn Williams0a336dc2020-05-11 15:39:58 +0100291 uint64_t attributeGuid,
Keith Davis97da5e22020-03-05 16:25:28 +0000292 unsigned char* buffer,
293 unsigned int remainingBufferSize,
294 unsigned int& numberOfBytesWritten)
Narumol Prangnawarat7e5eec72019-10-16 12:16:26 +0100295{
296 // Initialize the output value
297 numberOfBytesWritten = 0;
298
299 // Check that the given buffer is valid
Keith Davis97da5e22020-03-05 16:25:28 +0000300 if (buffer == nullptr || remainingBufferSize == 0)
Narumol Prangnawarat7e5eec72019-10-16 12:16:26 +0100301 {
302 return TimelinePacketStatus::BufferExhaustion;
303 }
304
305 // Utils
306 unsigned int uint32_t_size = sizeof(uint32_t);
307 unsigned int uint64_t_size = sizeof(uint64_t);
308
309 // Calculate the length of the data (in bytes)
Keith Davis97da5e22020-03-05 16:25:28 +0000310 unsigned int timelineRelationshipDataLength = uint32_t_size * 2 + // decl_id + Relationship Type
Finn Williams0a336dc2020-05-11 15:39:58 +0100311 uint64_t_size * 4; // Relationship GUID + Head GUID +
312 // tail GUID + attributeGuid
Narumol Prangnawarat7e5eec72019-10-16 12:16:26 +0100313
Keith Davis97da5e22020-03-05 16:25:28 +0000314 // Check whether the timeline binary fits in the given buffer
315 if (timelineRelationshipDataLength > remainingBufferSize)
Narumol Prangnawarat7e5eec72019-10-16 12:16:26 +0100316 {
317 return TimelinePacketStatus::BufferExhaustion;
318 }
319
Narumol Prangnawarat7e5eec72019-10-16 12:16:26 +0100320 // Initialize the offset for writing in the buffer
321 unsigned int offset = 0;
322
Narumol Prangnawarat7e5eec72019-10-16 12:16:26 +0100323 uint32_t relationshipTypeUint = 0;
324
325 switch (relationshipType)
326 {
327 case ProfilingRelationshipType::RetentionLink:
328 relationshipTypeUint = 0;
329 break;
330 case ProfilingRelationshipType::ExecutionLink:
331 relationshipTypeUint = 1;
332 break;
333 case ProfilingRelationshipType::DataLink:
334 relationshipTypeUint = 2;
335 break;
336 case ProfilingRelationshipType::LabelLink:
337 relationshipTypeUint = 3;
338 break;
339 default:
Jim Flynnf9db3ef2022-03-08 21:23:44 +0000340 throw arm::pipe::InvalidArgumentException("Unknown relationship type given.");
Narumol Prangnawarat7e5eec72019-10-16 12:16:26 +0100341 }
342
Keith Davis97da5e22020-03-05 16:25:28 +0000343 // Write the timeline binary payload to the buffer
Narumol Prangnawarat7e5eec72019-10-16 12:16:26 +0100344 // decl_id of the timeline message
345 uint32_t declId = 3;
346 WriteUint32(buffer, offset, declId); // decl_id
347 offset += uint32_t_size;
348 WriteUint32(buffer, offset, relationshipTypeUint); // Relationship Type
349 offset += uint32_t_size;
350 WriteUint64(buffer, offset, relationshipGuid); // GUID of this relationship
351 offset += uint64_t_size;
352 WriteUint64(buffer, offset, headGuid); // head of relationship GUID
353 offset += uint64_t_size;
354 WriteUint64(buffer, offset, tailGuid); // tail of relationship GUID
Finn Williams0a336dc2020-05-11 15:39:58 +0100355 offset += uint64_t_size;
356 WriteUint64(buffer, offset, attributeGuid); // attribute of relationship GUID
357
Narumol Prangnawarat7e5eec72019-10-16 12:16:26 +0100358
359 // Update the number of bytes written
Keith Davis97da5e22020-03-05 16:25:28 +0000360 numberOfBytesWritten = timelineRelationshipDataLength;
Narumol Prangnawarat7e5eec72019-10-16 12:16:26 +0100361
362 return TimelinePacketStatus::Ok;
363}
364
Sadik Armagan784db772019-10-08 15:05:38 +0100365TimelinePacketStatus WriteTimelineMessageDirectoryPackage(unsigned char* buffer,
Keith Davis97da5e22020-03-05 16:25:28 +0000366 unsigned int remainingBufferSize,
Sadik Armagan784db772019-10-08 15:05:38 +0100367 unsigned int& numberOfBytesWritten)
368{
369 // Initialize the output value
370 numberOfBytesWritten = 0;
371
372 // Check that the given buffer is valid
Keith Davis97da5e22020-03-05 16:25:28 +0000373 if (buffer == nullptr || remainingBufferSize == 0)
Sadik Armagan784db772019-10-08 15:05:38 +0100374 {
375 return TimelinePacketStatus::BufferExhaustion;
376 }
377
378 // Utils
Matteo Martincigh34a407d2019-11-06 15:30:54 +0000379 unsigned int uint8_t_size = sizeof(uint8_t);
Sadik Armagan784db772019-10-08 15:05:38 +0100380 unsigned int uint32_t_size = sizeof(uint32_t);
Matteo Martincigh34a407d2019-11-06 15:30:54 +0000381 unsigned int uint64_t_size = sizeof(uint64_t);
Sadik Armagan784db772019-10-08 15:05:38 +0100382
Matteo Martincigh8844c2f2019-10-16 10:29:17 +0100383 // The payload/data of the packet consists of swtrace event definitions encoded according
Sadik Armagan784db772019-10-08 15:05:38 +0100384 // to the swtrace directory specification. The messages being the five defined below:
Matteo Martincigh34a407d2019-11-06 15:30:54 +0000385 //
386 // | decl_id | decl_name | ui_name | arg_types | arg_names |
Sadik Armagan784db772019-10-08 15:05:38 +0100387 // |-----------|---------------------|-----------------------|-------------|-------------------------------------|
388 // | 0 | declareLabel | declare label | ps | guid,value |
389 // | 1 | declareEntity | declare entity | p | guid |
Jim Flynn6398a982020-05-27 17:05:21 +0100390 // | 2 | declareEventClass | declare event class | pp | guid,nameGuid |
391 // | 3 | declareRelationship | declare relationship | Ipppp | relationshipType,relationshipGuid, |
392 // | | | | | headGuid,tailGuid,attributeGuid |
Sadik Armagan784db772019-10-08 15:05:38 +0100393 // | 4 | declareEvent | declare event | @tp | timestamp,threadId,eventGuid |
Matteo Martincigh8844c2f2019-10-16 10:29:17 +0100394 std::vector<std::vector<std::string>> timelineDirectoryMessages
395 {
Matteo Martincigh34a407d2019-11-06 15:30:54 +0000396 { "0", "declareLabel", "declare label", "ps", "guid,value" },
397 { "1", "declareEntity", "declare entity", "p", "guid" },
Jim Flynn6398a982020-05-27 17:05:21 +0100398 { "2", "declareEventClass", "declare event class", "pp", "guid,nameGuid" },
399 { "3", "declareRelationship", "declare relationship", "Ipppp",
400 "relationshipType,relationshipGuid,headGuid,tailGuid,attributeGuid" },
Matteo Martincigh34a407d2019-11-06 15:30:54 +0000401 { "4", "declareEvent", "declare event", "@tp", "timestamp,threadId,eventGuid" }
Matteo Martincigh8844c2f2019-10-16 10:29:17 +0100402 };
Sadik Armagan784db772019-10-08 15:05:38 +0100403
Matteo Martincigh34a407d2019-11-06 15:30:54 +0000404 // Build the message declarations
405 std::vector<uint32_t> swTraceBuffer;
406 for (const auto& directoryComponent : timelineDirectoryMessages)
Sadik Armagan784db772019-10-08 15:05:38 +0100407 {
Matteo Martincigh34a407d2019-11-06 15:30:54 +0000408 // decl_id
409 uint32_t declId = 0;
410 try
Sadik Armagan784db772019-10-08 15:05:38 +0100411 {
Jim Flynn75c14f42022-03-10 22:05:42 +0000412 declId = arm::pipe::numeric_cast<uint32_t>(std::stoul(directoryComponent[0]));
Sadik Armagan784db772019-10-08 15:05:38 +0100413 }
Matteo Martincigh34a407d2019-11-06 15:30:54 +0000414 catch (const std::exception&)
415 {
416 return TimelinePacketStatus::Error;
417 }
418 swTraceBuffer.push_back(declId);
419
420 bool result = true;
Jim Flynnbbfe6032020-07-20 16:57:44 +0100421 result &= arm::pipe::ConvertDirectoryComponent<arm::pipe::SwTraceNameCharPolicy>(
422 directoryComponent[1], swTraceBuffer); // decl_name
423 result &= arm::pipe::ConvertDirectoryComponent<arm::pipe::SwTraceCharPolicy> (
424 directoryComponent[2], swTraceBuffer); // ui_name
425 result &= arm::pipe::ConvertDirectoryComponent<arm::pipe::SwTraceTypeCharPolicy>(
426 directoryComponent[3], swTraceBuffer); // arg_types
427 result &= arm::pipe::ConvertDirectoryComponent<arm::pipe::SwTraceCharPolicy> (
428 directoryComponent[4], swTraceBuffer); // arg_names
Matteo Martincigh34a407d2019-11-06 15:30:54 +0000429 if (!result)
430 {
431 return TimelinePacketStatus::Error;
432 }
Sadik Armagan784db772019-10-08 15:05:38 +0100433 }
434
Matteo Martincigh34a407d2019-11-06 15:30:54 +0000435 unsigned int dataLength = 3 * uint8_t_size + // Stream header (3 bytes)
Jim Flynn75c14f42022-03-10 22:05:42 +0000436 arm::pipe::numeric_cast<unsigned int>(swTraceBuffer.size()) *
Matteo Martincigh34a407d2019-11-06 15:30:54 +0000437 uint32_t_size; // Trace directory (5 messages)
438
Sadik Armagan784db772019-10-08 15:05:38 +0100439 // Calculate the timeline directory binary packet size (in bytes)
440 unsigned int timelineDirectoryPacketSize = 2 * uint32_t_size + // Header (2 words)
Matteo Martincigh34a407d2019-11-06 15:30:54 +0000441 dataLength; // Payload
Sadik Armagan784db772019-10-08 15:05:38 +0100442
443 // Check whether the timeline directory binary packet fits in the given buffer
Keith Davis97da5e22020-03-05 16:25:28 +0000444 if (timelineDirectoryPacketSize > remainingBufferSize)
Sadik Armagan784db772019-10-08 15:05:38 +0100445 {
446 return TimelinePacketStatus::BufferExhaustion;
447 }
448
Jan Eilersb884ea42019-10-16 09:54:15 +0100449 // Create packet header
Jim Flynn75c14f42022-03-10 22:05:42 +0000450 auto packetHeader = CreateTimelinePacketHeader(1, 0, 0, 0, 0, arm::pipe::numeric_cast<uint32_t>(dataLength));
Sadik Armagan784db772019-10-08 15:05:38 +0100451
452 // Initialize the offset for writing in the buffer
453 unsigned int offset = 0;
454
455 // Write the timeline binary packet header to the buffer
Jan Eilersb884ea42019-10-16 09:54:15 +0100456 WriteUint32(buffer, offset, packetHeader.first);
Sadik Armagan784db772019-10-08 15:05:38 +0100457 offset += uint32_t_size;
Jan Eilersb884ea42019-10-16 09:54:15 +0100458 WriteUint32(buffer, offset, packetHeader.second);
Sadik Armagan784db772019-10-08 15:05:38 +0100459 offset += uint32_t_size;
460
Matteo Martincigh34a407d2019-11-06 15:30:54 +0000461 // Write the stream header
462 uint8_t streamVersion = 4;
Jim Flynn75c14f42022-03-10 22:05:42 +0000463 uint8_t pointerBytes = arm::pipe::numeric_cast<uint8_t>(uint64_t_size); // All GUIDs are uint64_t
464 uint8_t threadIdBytes = arm::pipe::numeric_cast<uint8_t>(ThreadIdSize);
Matteo Martincigh34a407d2019-11-06 15:30:54 +0000465 switch (threadIdBytes)
Sadik Armagan784db772019-10-08 15:05:38 +0100466 {
Matteo Martincigh34a407d2019-11-06 15:30:54 +0000467 case 4: // Typically Windows and Android
468 case 8: // Typically Linux
469 break; // Valid values
470 default:
471 return TimelinePacketStatus::Error; // Invalid value
472 }
473 WriteUint8(buffer, offset, streamVersion);
474 offset += uint8_t_size;
475 WriteUint8(buffer, offset, pointerBytes);
476 offset += uint8_t_size;
477 WriteUint8(buffer, offset, threadIdBytes);
478 offset += uint8_t_size;
Sadik Armagan784db772019-10-08 15:05:38 +0100479
Matteo Martincigh34a407d2019-11-06 15:30:54 +0000480 // Write the SWTrace directory
Jim Flynn75c14f42022-03-10 22:05:42 +0000481 uint32_t numberOfDeclarations = arm::pipe::numeric_cast<uint32_t>(timelineDirectoryMessages.size());
Matteo Martincigh34a407d2019-11-06 15:30:54 +0000482 WriteUint32(buffer, offset, numberOfDeclarations); // Number of declarations
483 offset += uint32_t_size;
484 for (uint32_t i : swTraceBuffer)
485 {
486 WriteUint32(buffer, offset, i); // Message declarations
487 offset += uint32_t_size;
Sadik Armagan784db772019-10-08 15:05:38 +0100488 }
489
490 // Update the number of bytes written
491 numberOfBytesWritten = timelineDirectoryPacketSize;
492
493 return TimelinePacketStatus::Ok;
494}
495
Keith Davis97da5e22020-03-05 16:25:28 +0000496TimelinePacketStatus WriteTimelineEventClassBinary(uint64_t profilingGuid,
Jim Flynn1892d212020-05-26 21:10:49 +0100497 uint64_t nameGuid,
Keith Davis97da5e22020-03-05 16:25:28 +0000498 unsigned char* buffer,
499 unsigned int remainingBufferSize,
500 unsigned int& numberOfBytesWritten)
Jan Eilers92fa15b2019-10-15 15:23:25 +0100501{
Matteo Martincigh8844c2f2019-10-16 10:29:17 +0100502 // Initialize the output value
Jan Eilers92fa15b2019-10-15 15:23:25 +0100503 numberOfBytesWritten = 0;
504
505 // Check that the given buffer is valid
Keith Davis97da5e22020-03-05 16:25:28 +0000506 if (buffer == nullptr || remainingBufferSize == 0)
Jan Eilers92fa15b2019-10-15 15:23:25 +0100507 {
508 return TimelinePacketStatus::BufferExhaustion;
509 }
510
511 // Utils
512 unsigned int uint32_t_size = sizeof(uint32_t);
513 unsigned int uint64_t_size = sizeof(uint64_t);
514
Matteo Martincigh8844c2f2019-10-16 10:29:17 +0100515 // decl_id of the timeline message
516 uint32_t declId = 2;
Jan Eilers92fa15b2019-10-15 15:23:25 +0100517
518 // Calculate the length of the data (in bytes)
Jim Flynn1892d212020-05-26 21:10:49 +0100519 unsigned int dataSize = uint32_t_size + (uint64_t_size * 2); // decl_id + Profiling GUID + Name GUID
Jan Eilers92fa15b2019-10-15 15:23:25 +0100520
Keith Davis97da5e22020-03-05 16:25:28 +0000521 // Check whether the timeline binary fits in the given buffer
522 if (dataSize > remainingBufferSize)
Jan Eilers92fa15b2019-10-15 15:23:25 +0100523 {
524 return TimelinePacketStatus::BufferExhaustion;
525 }
526
Jan Eilers92fa15b2019-10-15 15:23:25 +0100527 // Initialize the offset for writing in the buffer
528 unsigned int offset = 0;
529
Keith Davis97da5e22020-03-05 16:25:28 +0000530 // Write the timeline binary payload to the buffer
Matteo Martincigh8844c2f2019-10-16 10:29:17 +0100531 WriteUint32(buffer, offset, declId); // decl_id
Jan Eilers92fa15b2019-10-15 15:23:25 +0100532 offset += uint32_t_size;
533 WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
Jim Flynn1892d212020-05-26 21:10:49 +0100534 offset += uint64_t_size;
535 WriteUint64(buffer, offset, nameGuid); // Name GUID
Jan Eilers92fa15b2019-10-15 15:23:25 +0100536
537 // Update the number of bytes written
Keith Davis97da5e22020-03-05 16:25:28 +0000538 numberOfBytesWritten = dataSize;
Jan Eilers92fa15b2019-10-15 15:23:25 +0100539
540 return TimelinePacketStatus::Ok;
541}
542
Keith Davis97da5e22020-03-05 16:25:28 +0000543TimelinePacketStatus WriteTimelineEventBinary(uint64_t timestamp,
Jim Flynn1fdeb992020-07-09 07:28:37 +0100544 int threadId,
Keith Davis97da5e22020-03-05 16:25:28 +0000545 uint64_t profilingGuid,
546 unsigned char* buffer,
547 unsigned int remainingBufferSize,
548 unsigned int& numberOfBytesWritten)
Matteo Martincigh8844c2f2019-10-16 10:29:17 +0100549{
550 // Initialize the output value
551 numberOfBytesWritten = 0;
Matteo Martincigh8844c2f2019-10-16 10:29:17 +0100552 // Check that the given buffer is valid
Keith Davis97da5e22020-03-05 16:25:28 +0000553 if (buffer == nullptr || remainingBufferSize == 0)
Matteo Martincigh8844c2f2019-10-16 10:29:17 +0100554 {
555 return TimelinePacketStatus::BufferExhaustion;
556 }
557
558 // Utils
559 unsigned int uint32_t_size = sizeof(uint32_t);
560 unsigned int uint64_t_size = sizeof(uint64_t);
561
562 // decl_id of the timeline message
563 uint32_t declId = 4;
564
565 // Calculate the length of the data (in bytes)
Keith Davis97da5e22020-03-05 16:25:28 +0000566 unsigned int timelineEventDataLength = uint32_t_size + // decl_id
567 uint64_t_size + // Timestamp
Colm Donelan5bb3d8a2020-05-12 16:36:46 +0100568 ThreadIdSize + // Thread id
Keith Davis97da5e22020-03-05 16:25:28 +0000569 uint64_t_size; // Profiling GUID
Matteo Martincigh8844c2f2019-10-16 10:29:17 +0100570
571 // Check whether the timeline binary packet fits in the given buffer
Keith Davis97da5e22020-03-05 16:25:28 +0000572 if (timelineEventDataLength > remainingBufferSize)
Matteo Martincigh8844c2f2019-10-16 10:29:17 +0100573 {
574 return TimelinePacketStatus::BufferExhaustion;
575 }
576
Matteo Martincigh8844c2f2019-10-16 10:29:17 +0100577 // Initialize the offset for writing in the buffer
578 unsigned int offset = 0;
579
Keith Davis97da5e22020-03-05 16:25:28 +0000580 // Write the timeline binary payload to the buffer
Matteo Martincigh8844c2f2019-10-16 10:29:17 +0100581 WriteUint32(buffer, offset, declId); // decl_id
582 offset += uint32_t_size;
583 WriteUint64(buffer, offset, timestamp); // Timestamp
584 offset += uint64_t_size;
Colm Donelan5bb3d8a2020-05-12 16:36:46 +0100585 WriteBytes(buffer, offset, &threadId, ThreadIdSize); // Thread id
586 offset += ThreadIdSize;
Matteo Martincigh8844c2f2019-10-16 10:29:17 +0100587 WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
588 offset += uint64_t_size;
Matteo Martincigh8844c2f2019-10-16 10:29:17 +0100589 // Update the number of bytes written
Keith Davis97da5e22020-03-05 16:25:28 +0000590 numberOfBytesWritten = timelineEventDataLength;
Matteo Martincigh8844c2f2019-10-16 10:29:17 +0100591
592 return TimelinePacketStatus::Ok;
593}
594
Matteo Martincigh5dc816e2019-11-04 14:05:28 +0000595uint64_t GetTimestamp()
596{
Matteo Martincigh5dc816e2019-11-04 14:05:28 +0000597 using clock = std::chrono::steady_clock;
Matteo Martincigh5dc816e2019-11-04 14:05:28 +0000598
599 // Take a timestamp
Finn Williamsd9ba1a72020-04-16 15:32:28 +0100600 auto timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(clock::now().time_since_epoch());
Matteo Martincigh5dc816e2019-11-04 14:05:28 +0000601
Finn Williamsd9ba1a72020-04-16 15:32:28 +0100602 return static_cast<uint64_t>(timestamp.count());
Matteo Martincigh5dc816e2019-11-04 14:05:28 +0000603}
Keith Davis3201eea2019-10-24 17:30:41 +0100604
Jim Flynnbbfe6032020-07-20 16:57:44 +0100605arm::pipe::Packet ReceivePacket(const unsigned char* buffer, uint32_t length)
Jim Flynn4e755a52020-03-29 17:48:26 +0100606{
607 if (buffer == nullptr)
608 {
Jim Flynnbbfe6032020-07-20 16:57:44 +0100609 throw arm::pipe::ProfilingException("data buffer is nullptr");
Jim Flynn4e755a52020-03-29 17:48:26 +0100610 }
611 if (length < 8)
612 {
Jim Flynnbbfe6032020-07-20 16:57:44 +0100613 throw arm::pipe::ProfilingException("length of data buffer is less than 8");
Jim Flynn4e755a52020-03-29 17:48:26 +0100614 }
615
616 uint32_t metadataIdentifier = 0;
617 std::memcpy(&metadataIdentifier, buffer, sizeof(metadataIdentifier));
618
619 uint32_t dataLength = 0;
620 std::memcpy(&dataLength, buffer + 4u, sizeof(dataLength));
621
622 std::unique_ptr<unsigned char[]> packetData;
623 if (dataLength > 0)
624 {
625 packetData = std::make_unique<unsigned char[]>(dataLength);
626 std::memcpy(packetData.get(), buffer + 8u, dataLength);
627 }
628
Jim Flynnbbfe6032020-07-20 16:57:44 +0100629 return arm::pipe::Packet(metadataIdentifier, dataLength, packetData);
Jim Flynn4e755a52020-03-29 17:48:26 +0100630}
631
Cathal Corbett5aa9fd72022-02-25 15:33:28 +0000632} // namespace pipe
Ferran Balaguer73882172019-09-02 16:39:42 +0100633
Cathal Corbett5aa9fd72022-02-25 15:33:28 +0000634} // namespace arm
Matteo Martincigh378bbfc2019-11-04 14:05:28 +0000635
636namespace std
637{
638
Jim Flynn1fdeb992020-07-09 07:28:37 +0100639bool operator==(const std::vector<uint8_t>& left, int right)
Matteo Martincigh378bbfc2019-11-04 14:05:28 +0000640{
641 return std::memcmp(left.data(), &right, left.size()) == 0;
642}
643
644} // namespace std