blob: b32ae499116717fe088d70015ce9cedbc94267fd [file] [log] [blame]
Keith Davis3201eea2019-10-24 17:30:41 +01001//
2// Copyright © 2019 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include "FileOnlyProfilingConnection.hpp"
7#include "PacketVersionResolver.hpp"
8
9#include <armnn/Exceptions.hpp>
10
11#include <boost/numeric/conversion/cast.hpp>
12#include <iostream>
13#include <thread>
14
15namespace armnn
16{
17
18namespace profiling
19{
20
21FileOnlyProfilingConnection::~FileOnlyProfilingConnection()
22{
23 Close();
24}
25
26bool FileOnlyProfilingConnection::IsOpen() const
27{
28 // This type of connection is always open.
29 return true;
30}
31
32void FileOnlyProfilingConnection::Close()
33{
34 // Dump any unread packets out of the queue.
35 for (unsigned int i = 0; i < m_PacketQueue.size(); i++)
36 {
37 m_PacketQueue.pop();
38 }
39}
40
41bool FileOnlyProfilingConnection::WaitForStreamMeta(const unsigned char* buffer, uint32_t length)
42{
43 // The first word, stream_metadata_identifer, should always be 0.
44 if (ToUint32(buffer, TargetEndianness::BeWire) != 0)
45 {
46 Fail("Protocol error. The stream_metadata_identifer was not 0.");
47 }
48
49 // Before we interpret the length we need to read the pipe_magic word to determine endianness.
50 if (ToUint32(buffer + 8, TargetEndianness::BeWire) == PIPE_MAGIC)
51 {
52 m_Endianness = TargetEndianness::BeWire;
53 }
54 else if (ToUint32(buffer + 8, TargetEndianness::LeWire) == PIPE_MAGIC)
55 {
56 m_Endianness = TargetEndianness::LeWire;
57 }
58 else
59 {
60 Fail("Protocol read error. Unable to read PIPE_MAGIC value.");
61 }
62 return true;
63}
64
65void FileOnlyProfilingConnection::SendConnectionAck()
66{
67 if (!m_QuietOp)
68 {
69 std::cout << "Sending connection acknowledgement." << std::endl;
70 }
71 std::unique_ptr<unsigned char[]> uniqueNullPtr = nullptr;
72 m_PacketQueue.push(Packet(0x10000, 0, uniqueNullPtr));
73}
74
75bool FileOnlyProfilingConnection::SendCounterSelectionPacket()
76{
77 uint32_t uint16_t_size = sizeof(uint16_t);
78 uint32_t uint32_t_size = sizeof(uint32_t);
79
80 uint32_t offset = 0;
81 uint32_t bodySize = uint32_t_size + boost::numeric_cast<uint32_t>(m_IdList.size()) * uint16_t_size;
82
83 auto uniqueData = std::make_unique<unsigned char[]>(bodySize);
84 unsigned char* data = reinterpret_cast<unsigned char*>(uniqueData.get());
85
86 // Copy capturePeriod
87 WriteUint32(data, offset, m_Options.m_CapturePeriod);
88
89 // Copy m_IdList
90 offset += uint32_t_size;
91 for (const uint16_t& id : m_IdList)
92 {
93 WriteUint16(data, offset, id);
94 offset += uint16_t_size;
95 }
96
97 m_PacketQueue.push(Packet(0x40000, bodySize, uniqueData));
98
99 return true;
100}
101
102bool FileOnlyProfilingConnection::WritePacket(const unsigned char* buffer, uint32_t length)
103{
104 BOOST_ASSERT(buffer);
105
106 // Read Header and determine case
107 uint32_t outgoingHeaderAsWords[2];
108 PackageActivity packageActivity = GetPackageActivity(buffer, outgoingHeaderAsWords);
109
110 switch (packageActivity)
111 {
112 case PackageActivity::StreamMetaData:
113 {
114 if (!WaitForStreamMeta(buffer, length))
115 {
116 return EXIT_FAILURE;
117 }
118
119 SendConnectionAck();
120 break;
121 }
122 case PackageActivity::CounterDirectory:
123 {
124 std::unique_ptr<unsigned char[]> uniqueCounterData = std::make_unique<unsigned char[]>(length - 8);
125
126 std::memcpy(uniqueCounterData.get(), buffer + 8, length - 8);
127
128 Packet directoryPacket(outgoingHeaderAsWords[0], length - 8, uniqueCounterData);
129
130 armnn::profiling::PacketVersionResolver packetVersionResolver;
131 DirectoryCaptureCommandHandler directoryCaptureCommandHandler(
132 0, 2, packetVersionResolver.ResolvePacketVersion(0, 2).GetEncodedValue());
133 directoryCaptureCommandHandler.operator()(directoryPacket);
134 const ICounterDirectory& counterDirectory = directoryCaptureCommandHandler.GetCounterDirectory();
135 for (auto& category : counterDirectory.GetCategories())
136 {
137 // Remember we need to translate the Uid's from our CounterDirectory instance to the parent one.
138 std::vector<uint16_t> translatedCounters;
139 for (auto const& copyUid : category->m_Counters)
140 {
141 translatedCounters.emplace_back(directoryCaptureCommandHandler.TranslateUIDCopyToOriginal(copyUid));
142 }
143 m_IdList.insert(std::end(m_IdList), std::begin(translatedCounters), std::end(translatedCounters));
144 }
145 SendCounterSelectionPacket();
146 break;
147 }
148 default:
149 {
150 break;
151 }
152 }
153 return true;
154}
155
156Packet FileOnlyProfilingConnection::ReadPacket(uint32_t timeout)
157{
158 uint16_t loopCount = 10;
159 uint32_t timeoutFraction = timeout / loopCount;
160 while (m_PacketQueue.empty())
161 {
162 std::this_thread::sleep_for(std::chrono::milliseconds(timeoutFraction));
163 --loopCount;
164 if ((loopCount) == 0)
165 {
166 throw armnn::TimeoutException("Thread has timed out as per requested time limit");
167 }
168 }
169 Packet returnedPacket = std::move(m_PacketQueue.front());
170 m_PacketQueue.pop();
171 return returnedPacket;
172}
173
174PackageActivity FileOnlyProfilingConnection::GetPackageActivity(const unsigned char* buffer, uint32_t headerAsWords[2])
175{
176 headerAsWords[0] = ToUint32(buffer, m_Endianness);
177 headerAsWords[1] = ToUint32(buffer + 4, m_Endianness);
178 if (headerAsWords[0] == 0x20000) // Packet family = 0 Packet Id = 2
179 {
180 return PackageActivity::CounterDirectory;
181 }
182 else if (headerAsWords[0] == 0) // Packet family = 0 Packet Id = 0
183 {
184 return PackageActivity::StreamMetaData;
185 }
186 else
187 {
188 return PackageActivity::Unknown;
189 }
190}
191
192uint32_t FileOnlyProfilingConnection::ToUint32(const unsigned char* data, TargetEndianness endianness)
193{
194 // Extract the first 4 bytes starting at data and push them into a 32bit integer based on the
195 // specified endianness.
196 if (endianness == TargetEndianness::BeWire)
197 {
198 return static_cast<uint32_t>(data[0]) << 24 | static_cast<uint32_t>(data[1]) << 16 |
199 static_cast<uint32_t>(data[2]) << 8 | static_cast<uint32_t>(data[3]);
200 }
201 else
202 {
203 return static_cast<uint32_t>(data[3]) << 24 | static_cast<uint32_t>(data[2]) << 16 |
204 static_cast<uint32_t>(data[1]) << 8 | static_cast<uint32_t>(data[0]);
205 }
206}
207
208void FileOnlyProfilingConnection::Fail(const std::string& errorMessage)
209{
210 Close();
211 throw RuntimeException(errorMessage);
212}
213
214} // namespace profiling
215
216} // namespace armnn