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