blob: ca3a52c17bebbead73f07e5aad2e880c609d7b6d [file] [log] [blame]
Michael Butler8fc48962021-01-08 17:21:27 -08001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "ExecutionBurstUtils"
18
19#include "ExecutionBurstUtils.h"
20
21#include <android-base/logging.h>
Michael Butler76e491f2020-12-19 01:55:32 -080022#include <android-base/properties.h>
Michael Butler8fc48962021-01-08 17:21:27 -080023#include <android/hardware/neuralnetworks/1.0/types.h>
24#include <android/hardware/neuralnetworks/1.1/types.h>
25#include <android/hardware/neuralnetworks/1.2/types.h>
26#include <fmq/MessageQueue.h>
27#include <hidl/MQDescriptor.h>
Michael Butler76e491f2020-12-19 01:55:32 -080028#include <nnapi/Result.h>
29#include <nnapi/Types.h>
30#include <nnapi/hal/ProtectCallback.h>
Michael Butler8fc48962021-01-08 17:21:27 -080031
32#include <atomic>
33#include <chrono>
34#include <memory>
35#include <thread>
36#include <tuple>
37#include <utility>
38#include <vector>
39
40namespace android::hardware::neuralnetworks::V1_2::utils {
41namespace {
42
43constexpr V1_2::Timing kNoTiming = {std::numeric_limits<uint64_t>::max(),
44 std::numeric_limits<uint64_t>::max()};
45
Michael Butler76e491f2020-12-19 01:55:32 -080046std::chrono::microseconds getPollingTimeWindow(const std::string& property) {
47 constexpr int32_t kDefaultPollingTimeWindow = 0;
48#ifdef NN_DEBUGGABLE
49 constexpr int32_t kMinPollingTimeWindow = 0;
50 const int32_t selectedPollingTimeWindow =
51 base::GetIntProperty(property, kDefaultPollingTimeWindow, kMinPollingTimeWindow);
52 return std::chrono::microseconds(selectedPollingTimeWindow);
53#else
54 (void)property;
55 return std::chrono::microseconds(kDefaultPollingTimeWindow);
56#endif // NN_DEBUGGABLE
57}
58
59} // namespace
60
61std::chrono::microseconds getBurstControllerPollingTimeWindow() {
62 return getPollingTimeWindow("debug.nn.burst-controller-polling-window");
63}
64
65std::chrono::microseconds getBurstServerPollingTimeWindow() {
66 return getPollingTimeWindow("debug.nn.burst-server-polling-window");
Michael Butler8fc48962021-01-08 17:21:27 -080067}
68
69// serialize a request into a packet
70std::vector<FmqRequestDatum> serialize(const V1_0::Request& request, V1_2::MeasureTiming measure,
71 const std::vector<int32_t>& slots) {
72 // count how many elements need to be sent for a request
Michael Butler76e491f2020-12-19 01:55:32 -080073 size_t count = 2 + request.inputs.size() + request.outputs.size() + slots.size();
Michael Butler8fc48962021-01-08 17:21:27 -080074 for (const auto& input : request.inputs) {
75 count += input.dimensions.size();
76 }
77 for (const auto& output : request.outputs) {
78 count += output.dimensions.size();
79 }
Michael Butler76e491f2020-12-19 01:55:32 -080080 CHECK_LE(count, std::numeric_limits<uint32_t>::max());
Michael Butler8fc48962021-01-08 17:21:27 -080081
82 // create buffer to temporarily store elements
83 std::vector<FmqRequestDatum> data;
84 data.reserve(count);
85
86 // package packetInfo
Michael Butler76e491f2020-12-19 01:55:32 -080087 data.emplace_back();
88 data.back().packetInformation(
89 {.packetSize = static_cast<uint32_t>(count),
90 .numberOfInputOperands = static_cast<uint32_t>(request.inputs.size()),
91 .numberOfOutputOperands = static_cast<uint32_t>(request.outputs.size()),
92 .numberOfPools = static_cast<uint32_t>(slots.size())});
Michael Butler8fc48962021-01-08 17:21:27 -080093
94 // package input data
95 for (const auto& input : request.inputs) {
96 // package operand information
Michael Butler76e491f2020-12-19 01:55:32 -080097 data.emplace_back();
98 data.back().inputOperandInformation(
99 {.hasNoValue = input.hasNoValue,
100 .location = input.location,
101 .numberOfDimensions = static_cast<uint32_t>(input.dimensions.size())});
Michael Butler8fc48962021-01-08 17:21:27 -0800102
103 // package operand dimensions
104 for (uint32_t dimension : input.dimensions) {
Michael Butler76e491f2020-12-19 01:55:32 -0800105 data.emplace_back();
106 data.back().inputOperandDimensionValue(dimension);
Michael Butler8fc48962021-01-08 17:21:27 -0800107 }
108 }
109
110 // package output data
111 for (const auto& output : request.outputs) {
112 // package operand information
Michael Butler76e491f2020-12-19 01:55:32 -0800113 data.emplace_back();
114 data.back().outputOperandInformation(
115 {.hasNoValue = output.hasNoValue,
116 .location = output.location,
117 .numberOfDimensions = static_cast<uint32_t>(output.dimensions.size())});
Michael Butler8fc48962021-01-08 17:21:27 -0800118
119 // package operand dimensions
120 for (uint32_t dimension : output.dimensions) {
Michael Butler76e491f2020-12-19 01:55:32 -0800121 data.emplace_back();
122 data.back().outputOperandDimensionValue(dimension);
Michael Butler8fc48962021-01-08 17:21:27 -0800123 }
124 }
125
126 // package pool identifier
127 for (int32_t slot : slots) {
Michael Butler76e491f2020-12-19 01:55:32 -0800128 data.emplace_back();
129 data.back().poolIdentifier(slot);
Michael Butler8fc48962021-01-08 17:21:27 -0800130 }
131
132 // package measureTiming
Michael Butler76e491f2020-12-19 01:55:32 -0800133 data.emplace_back();
134 data.back().measureTiming(measure);
135
136 CHECK_EQ(data.size(), count);
Michael Butler8fc48962021-01-08 17:21:27 -0800137
138 // return packet
139 return data;
140}
141
142// serialize result
143std::vector<FmqResultDatum> serialize(V1_0::ErrorStatus errorStatus,
144 const std::vector<V1_2::OutputShape>& outputShapes,
145 V1_2::Timing timing) {
146 // count how many elements need to be sent for a request
147 size_t count = 2 + outputShapes.size();
148 for (const auto& outputShape : outputShapes) {
149 count += outputShape.dimensions.size();
150 }
151
152 // create buffer to temporarily store elements
153 std::vector<FmqResultDatum> data;
154 data.reserve(count);
155
156 // package packetInfo
Michael Butler76e491f2020-12-19 01:55:32 -0800157 data.emplace_back();
158 data.back().packetInformation({.packetSize = static_cast<uint32_t>(count),
159 .errorStatus = errorStatus,
160 .numberOfOperands = static_cast<uint32_t>(outputShapes.size())});
Michael Butler8fc48962021-01-08 17:21:27 -0800161
162 // package output shape data
163 for (const auto& operand : outputShapes) {
164 // package operand information
Michael Butler76e491f2020-12-19 01:55:32 -0800165 data.emplace_back();
166 data.back().operandInformation(
167 {.isSufficient = operand.isSufficient,
168 .numberOfDimensions = static_cast<uint32_t>(operand.dimensions.size())});
Michael Butler8fc48962021-01-08 17:21:27 -0800169
170 // package operand dimensions
171 for (uint32_t dimension : operand.dimensions) {
Michael Butler76e491f2020-12-19 01:55:32 -0800172 data.emplace_back();
173 data.back().operandDimensionValue(dimension);
Michael Butler8fc48962021-01-08 17:21:27 -0800174 }
175 }
176
177 // package executionTiming
Michael Butler76e491f2020-12-19 01:55:32 -0800178 data.emplace_back();
179 data.back().executionTiming(timing);
180
181 CHECK_EQ(data.size(), count);
Michael Butler8fc48962021-01-08 17:21:27 -0800182
183 // return result
184 return data;
185}
186
187// deserialize request
Michael Butler76e491f2020-12-19 01:55:32 -0800188nn::Result<std::tuple<V1_0::Request, std::vector<int32_t>, V1_2::MeasureTiming>> deserialize(
Michael Butler8fc48962021-01-08 17:21:27 -0800189 const std::vector<FmqRequestDatum>& data) {
190 using discriminator = FmqRequestDatum::hidl_discriminator;
191
192 size_t index = 0;
193
194 // validate packet information
195 if (data.size() == 0 || data[index].getDiscriminator() != discriminator::packetInformation) {
Michael Butler76e491f2020-12-19 01:55:32 -0800196 return NN_ERROR() << "FMQ Request packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800197 }
198
199 // unpackage packet information
200 const FmqRequestDatum::PacketInformation& packetInfo = data[index].packetInformation();
201 index++;
202 const uint32_t packetSize = packetInfo.packetSize;
203 const uint32_t numberOfInputOperands = packetInfo.numberOfInputOperands;
204 const uint32_t numberOfOutputOperands = packetInfo.numberOfOutputOperands;
205 const uint32_t numberOfPools = packetInfo.numberOfPools;
206
207 // verify packet size
208 if (data.size() != packetSize) {
Michael Butler76e491f2020-12-19 01:55:32 -0800209 return NN_ERROR() << "FMQ Request packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800210 }
211
212 // unpackage input operands
213 std::vector<V1_0::RequestArgument> inputs;
214 inputs.reserve(numberOfInputOperands);
215 for (size_t operand = 0; operand < numberOfInputOperands; ++operand) {
216 // validate input operand information
217 if (data[index].getDiscriminator() != discriminator::inputOperandInformation) {
Michael Butler76e491f2020-12-19 01:55:32 -0800218 return NN_ERROR() << "FMQ Request packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800219 }
220
221 // unpackage operand information
222 const FmqRequestDatum::OperandInformation& operandInfo =
223 data[index].inputOperandInformation();
224 index++;
225 const bool hasNoValue = operandInfo.hasNoValue;
226 const V1_0::DataLocation location = operandInfo.location;
227 const uint32_t numberOfDimensions = operandInfo.numberOfDimensions;
228
229 // unpackage operand dimensions
230 std::vector<uint32_t> dimensions;
231 dimensions.reserve(numberOfDimensions);
232 for (size_t i = 0; i < numberOfDimensions; ++i) {
233 // validate dimension
234 if (data[index].getDiscriminator() != discriminator::inputOperandDimensionValue) {
Michael Butler76e491f2020-12-19 01:55:32 -0800235 return NN_ERROR() << "FMQ Request packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800236 }
237
238 // unpackage dimension
239 const uint32_t dimension = data[index].inputOperandDimensionValue();
240 index++;
241
242 // store result
243 dimensions.push_back(dimension);
244 }
245
246 // store result
247 inputs.push_back(
Michael Butler76e491f2020-12-19 01:55:32 -0800248 {.hasNoValue = hasNoValue, .location = location, .dimensions = dimensions});
Michael Butler8fc48962021-01-08 17:21:27 -0800249 }
250
251 // unpackage output operands
252 std::vector<V1_0::RequestArgument> outputs;
253 outputs.reserve(numberOfOutputOperands);
254 for (size_t operand = 0; operand < numberOfOutputOperands; ++operand) {
255 // validate output operand information
256 if (data[index].getDiscriminator() != discriminator::outputOperandInformation) {
Michael Butler76e491f2020-12-19 01:55:32 -0800257 return NN_ERROR() << "FMQ Request packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800258 }
259
260 // unpackage operand information
261 const FmqRequestDatum::OperandInformation& operandInfo =
262 data[index].outputOperandInformation();
263 index++;
264 const bool hasNoValue = operandInfo.hasNoValue;
265 const V1_0::DataLocation location = operandInfo.location;
266 const uint32_t numberOfDimensions = operandInfo.numberOfDimensions;
267
268 // unpackage operand dimensions
269 std::vector<uint32_t> dimensions;
270 dimensions.reserve(numberOfDimensions);
271 for (size_t i = 0; i < numberOfDimensions; ++i) {
272 // validate dimension
273 if (data[index].getDiscriminator() != discriminator::outputOperandDimensionValue) {
Michael Butler76e491f2020-12-19 01:55:32 -0800274 return NN_ERROR() << "FMQ Request packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800275 }
276
277 // unpackage dimension
278 const uint32_t dimension = data[index].outputOperandDimensionValue();
279 index++;
280
281 // store result
282 dimensions.push_back(dimension);
283 }
284
285 // store result
286 outputs.push_back(
Michael Butler76e491f2020-12-19 01:55:32 -0800287 {.hasNoValue = hasNoValue, .location = location, .dimensions = dimensions});
Michael Butler8fc48962021-01-08 17:21:27 -0800288 }
289
290 // unpackage pools
291 std::vector<int32_t> slots;
292 slots.reserve(numberOfPools);
293 for (size_t pool = 0; pool < numberOfPools; ++pool) {
294 // validate input operand information
295 if (data[index].getDiscriminator() != discriminator::poolIdentifier) {
Michael Butler76e491f2020-12-19 01:55:32 -0800296 return NN_ERROR() << "FMQ Request packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800297 }
298
299 // unpackage operand information
300 const int32_t poolId = data[index].poolIdentifier();
301 index++;
302
303 // store result
304 slots.push_back(poolId);
305 }
306
307 // validate measureTiming
308 if (data[index].getDiscriminator() != discriminator::measureTiming) {
Michael Butler76e491f2020-12-19 01:55:32 -0800309 return NN_ERROR() << "FMQ Request packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800310 }
311
312 // unpackage measureTiming
313 const V1_2::MeasureTiming measure = data[index].measureTiming();
314 index++;
315
316 // validate packet information
317 if (index != packetSize) {
Michael Butler76e491f2020-12-19 01:55:32 -0800318 return NN_ERROR() << "FMQ Result packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800319 }
320
321 // return request
Michael Butler76e491f2020-12-19 01:55:32 -0800322 V1_0::Request request = {.inputs = inputs, .outputs = outputs, .pools = {}};
Michael Butler8fc48962021-01-08 17:21:27 -0800323 return std::make_tuple(std::move(request), std::move(slots), measure);
324}
325
326// deserialize a packet into the result
Michael Butler76e491f2020-12-19 01:55:32 -0800327nn::Result<std::tuple<V1_0::ErrorStatus, std::vector<V1_2::OutputShape>, V1_2::Timing>> deserialize(
328 const std::vector<FmqResultDatum>& data) {
Michael Butler8fc48962021-01-08 17:21:27 -0800329 using discriminator = FmqResultDatum::hidl_discriminator;
Michael Butler8fc48962021-01-08 17:21:27 -0800330 size_t index = 0;
331
332 // validate packet information
333 if (data.size() == 0 || data[index].getDiscriminator() != discriminator::packetInformation) {
Michael Butler76e491f2020-12-19 01:55:32 -0800334 return NN_ERROR() << "FMQ Result packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800335 }
336
337 // unpackage packet information
338 const FmqResultDatum::PacketInformation& packetInfo = data[index].packetInformation();
339 index++;
340 const uint32_t packetSize = packetInfo.packetSize;
341 const V1_0::ErrorStatus errorStatus = packetInfo.errorStatus;
342 const uint32_t numberOfOperands = packetInfo.numberOfOperands;
343
344 // verify packet size
345 if (data.size() != packetSize) {
Michael Butler76e491f2020-12-19 01:55:32 -0800346 return NN_ERROR() << "FMQ Result packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800347 }
348
349 // unpackage operands
Michael Butler76e491f2020-12-19 01:55:32 -0800350 std::vector<V1_2::OutputShape> outputShapes;
351 outputShapes.reserve(numberOfOperands);
Michael Butler8fc48962021-01-08 17:21:27 -0800352 for (size_t operand = 0; operand < numberOfOperands; ++operand) {
353 // validate operand information
354 if (data[index].getDiscriminator() != discriminator::operandInformation) {
Michael Butler76e491f2020-12-19 01:55:32 -0800355 return NN_ERROR() << "FMQ Result packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800356 }
357
358 // unpackage operand information
359 const FmqResultDatum::OperandInformation& operandInfo = data[index].operandInformation();
360 index++;
361 const bool isSufficient = operandInfo.isSufficient;
362 const uint32_t numberOfDimensions = operandInfo.numberOfDimensions;
363
364 // unpackage operand dimensions
365 std::vector<uint32_t> dimensions;
366 dimensions.reserve(numberOfDimensions);
367 for (size_t i = 0; i < numberOfDimensions; ++i) {
368 // validate dimension
369 if (data[index].getDiscriminator() != discriminator::operandDimensionValue) {
Michael Butler76e491f2020-12-19 01:55:32 -0800370 return NN_ERROR() << "FMQ Result packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800371 }
372
373 // unpackage dimension
374 const uint32_t dimension = data[index].operandDimensionValue();
375 index++;
376
377 // store result
378 dimensions.push_back(dimension);
379 }
380
381 // store result
Michael Butler76e491f2020-12-19 01:55:32 -0800382 outputShapes.push_back({.dimensions = dimensions, .isSufficient = isSufficient});
Michael Butler8fc48962021-01-08 17:21:27 -0800383 }
384
385 // validate execution timing
386 if (data[index].getDiscriminator() != discriminator::executionTiming) {
Michael Butler76e491f2020-12-19 01:55:32 -0800387 return NN_ERROR() << "FMQ Result packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800388 }
389
390 // unpackage execution timing
391 const V1_2::Timing timing = data[index].executionTiming();
392 index++;
393
394 // validate packet information
395 if (index != packetSize) {
Michael Butler76e491f2020-12-19 01:55:32 -0800396 return NN_ERROR() << "FMQ Result packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800397 }
398
399 // return result
400 return std::make_tuple(errorStatus, std::move(outputShapes), timing);
401}
402
Michael Butler8fc48962021-01-08 17:21:27 -0800403// RequestChannelSender methods
404
Michael Butler76e491f2020-12-19 01:55:32 -0800405nn::GeneralResult<
406 std::pair<std::unique_ptr<RequestChannelSender>, const MQDescriptorSync<FmqRequestDatum>*>>
Michael Butler8fc48962021-01-08 17:21:27 -0800407RequestChannelSender::create(size_t channelLength) {
Michael Butler76e491f2020-12-19 01:55:32 -0800408 auto requestChannelSender =
409 std::make_unique<RequestChannelSender>(PrivateConstructorTag{}, channelLength);
410 if (!requestChannelSender->mFmqRequestChannel.isValid()) {
411 return NN_ERROR() << "Unable to create RequestChannelSender";
Michael Butler8fc48962021-01-08 17:21:27 -0800412 }
413
Michael Butler76e491f2020-12-19 01:55:32 -0800414 const MQDescriptorSync<FmqRequestDatum>* descriptor =
415 requestChannelSender->mFmqRequestChannel.getDesc();
416 return std::make_pair(std::move(requestChannelSender), descriptor);
Michael Butler8fc48962021-01-08 17:21:27 -0800417}
418
Michael Butler76e491f2020-12-19 01:55:32 -0800419RequestChannelSender::RequestChannelSender(PrivateConstructorTag /*tag*/, size_t channelLength)
420 : mFmqRequestChannel(channelLength, /*configureEventFlagWord=*/true) {}
Michael Butler8fc48962021-01-08 17:21:27 -0800421
Michael Butler76e491f2020-12-19 01:55:32 -0800422nn::Result<void> RequestChannelSender::send(const V1_0::Request& request,
423 V1_2::MeasureTiming measure,
424 const std::vector<int32_t>& slots) {
Michael Butler8fc48962021-01-08 17:21:27 -0800425 const std::vector<FmqRequestDatum> serialized = serialize(request, measure, slots);
426 return sendPacket(serialized);
427}
428
Michael Butler76e491f2020-12-19 01:55:32 -0800429nn::Result<void> RequestChannelSender::sendPacket(const std::vector<FmqRequestDatum>& packet) {
Michael Butler8fc48962021-01-08 17:21:27 -0800430 if (!mValid) {
Michael Butler76e491f2020-12-19 01:55:32 -0800431 return NN_ERROR() << "FMQ object is invalid";
Michael Butler8fc48962021-01-08 17:21:27 -0800432 }
433
Michael Butler76e491f2020-12-19 01:55:32 -0800434 if (packet.size() > mFmqRequestChannel.availableToWrite()) {
435 return NN_ERROR()
436 << "RequestChannelSender::sendPacket -- packet size exceeds size available in FMQ";
Michael Butler8fc48962021-01-08 17:21:27 -0800437 }
438
Michael Butler76e491f2020-12-19 01:55:32 -0800439 // Always send the packet with "blocking" because this signals the futex and unblocks the
440 // consumer if it is waiting on the futex.
441 const bool success = mFmqRequestChannel.writeBlocking(packet.data(), packet.size());
442 if (!success) {
443 return NN_ERROR()
444 << "RequestChannelSender::sendPacket -- FMQ's writeBlocking returned an error";
445 }
446
447 return {};
Michael Butler8fc48962021-01-08 17:21:27 -0800448}
449
Michael Butler76e491f2020-12-19 01:55:32 -0800450void RequestChannelSender::notifyAsDeadObject() {
Michael Butler8fc48962021-01-08 17:21:27 -0800451 mValid = false;
452}
453
454// RequestChannelReceiver methods
455
Michael Butler76e491f2020-12-19 01:55:32 -0800456nn::GeneralResult<std::unique_ptr<RequestChannelReceiver>> RequestChannelReceiver::create(
457 const MQDescriptorSync<FmqRequestDatum>& requestChannel,
458 std::chrono::microseconds pollingTimeWindow) {
459 auto requestChannelReceiver = std::make_unique<RequestChannelReceiver>(
460 PrivateConstructorTag{}, requestChannel, pollingTimeWindow);
Michael Butler8fc48962021-01-08 17:21:27 -0800461
Michael Butler76e491f2020-12-19 01:55:32 -0800462 if (!requestChannelReceiver->mFmqRequestChannel.isValid()) {
463 return NN_ERROR() << "Unable to create RequestChannelReceiver";
Michael Butler8fc48962021-01-08 17:21:27 -0800464 }
Michael Butler76e491f2020-12-19 01:55:32 -0800465 if (requestChannelReceiver->mFmqRequestChannel.getEventFlagWord() == nullptr) {
466 return NN_ERROR()
467 << "RequestChannelReceiver::create was passed an MQDescriptor without an EventFlag";
Michael Butler8fc48962021-01-08 17:21:27 -0800468 }
469
Michael Butler76e491f2020-12-19 01:55:32 -0800470 return requestChannelReceiver;
Michael Butler8fc48962021-01-08 17:21:27 -0800471}
472
Michael Butler76e491f2020-12-19 01:55:32 -0800473RequestChannelReceiver::RequestChannelReceiver(
474 PrivateConstructorTag /*tag*/, const MQDescriptorSync<FmqRequestDatum>& requestChannel,
475 std::chrono::microseconds pollingTimeWindow)
476 : mFmqRequestChannel(requestChannel), kPollingTimeWindow(pollingTimeWindow) {}
Michael Butler8fc48962021-01-08 17:21:27 -0800477
Michael Butler76e491f2020-12-19 01:55:32 -0800478nn::Result<std::tuple<V1_0::Request, std::vector<int32_t>, V1_2::MeasureTiming>>
Michael Butler8fc48962021-01-08 17:21:27 -0800479RequestChannelReceiver::getBlocking() {
Michael Butler76e491f2020-12-19 01:55:32 -0800480 const auto packet = NN_TRY(getPacketBlocking());
481 return deserialize(packet);
Michael Butler8fc48962021-01-08 17:21:27 -0800482}
483
484void RequestChannelReceiver::invalidate() {
485 mTeardown = true;
486
487 // force unblock
Michael Butler76e491f2020-12-19 01:55:32 -0800488 // ExecutionBurstServer is by default waiting on a request packet. If the client process
489 // destroys its burst object, the server may still be waiting on the futex. This force unblock
490 // wakes up any thread waiting on the futex.
491 const auto data = serialize(V1_0::Request{}, V1_2::MeasureTiming::NO, {});
492 mFmqRequestChannel.writeBlocking(data.data(), data.size());
Michael Butler8fc48962021-01-08 17:21:27 -0800493}
494
Michael Butler76e491f2020-12-19 01:55:32 -0800495nn::Result<std::vector<FmqRequestDatum>> RequestChannelReceiver::getPacketBlocking() {
Michael Butler8fc48962021-01-08 17:21:27 -0800496 if (mTeardown) {
Michael Butler76e491f2020-12-19 01:55:32 -0800497 return NN_ERROR() << "FMQ object is being torn down";
Michael Butler8fc48962021-01-08 17:21:27 -0800498 }
499
Michael Butler76e491f2020-12-19 01:55:32 -0800500 // First spend time polling if results are available in FMQ instead of waiting on the futex.
501 // Polling is more responsive (yielding lower latencies), but can take up more power, so only
502 // poll for a limited period of time.
Michael Butler8fc48962021-01-08 17:21:27 -0800503
504 auto& getCurrentTime = std::chrono::high_resolution_clock::now;
505 const auto timeToStopPolling = getCurrentTime() + kPollingTimeWindow;
506
507 while (getCurrentTime() < timeToStopPolling) {
508 // if class is being torn down, immediately return
509 if (mTeardown.load(std::memory_order_relaxed)) {
Michael Butler76e491f2020-12-19 01:55:32 -0800510 return NN_ERROR() << "FMQ object is being torn down";
Michael Butler8fc48962021-01-08 17:21:27 -0800511 }
512
Michael Butler76e491f2020-12-19 01:55:32 -0800513 // Check if data is available. If it is, immediately retrieve it and return.
514 const size_t available = mFmqRequestChannel.availableToRead();
Michael Butler8fc48962021-01-08 17:21:27 -0800515 if (available > 0) {
Michael Butler8fc48962021-01-08 17:21:27 -0800516 std::vector<FmqRequestDatum> packet(available);
Michael Butler76e491f2020-12-19 01:55:32 -0800517 const bool success = mFmqRequestChannel.readBlocking(packet.data(), available);
Michael Butler8fc48962021-01-08 17:21:27 -0800518 if (!success) {
Michael Butler76e491f2020-12-19 01:55:32 -0800519 return NN_ERROR() << "Error receiving packet";
Michael Butler8fc48962021-01-08 17:21:27 -0800520 }
Michael Butler76e491f2020-12-19 01:55:32 -0800521 return packet;
Michael Butler8fc48962021-01-08 17:21:27 -0800522 }
523 }
524
Michael Butler76e491f2020-12-19 01:55:32 -0800525 // If we get to this point, we either stopped polling because it was taking too long or polling
526 // was not allowed. Instead, perform a blocking call which uses a futex to save power.
Michael Butler8fc48962021-01-08 17:21:27 -0800527
528 // wait for request packet and read first element of request packet
529 FmqRequestDatum datum;
Michael Butler76e491f2020-12-19 01:55:32 -0800530 bool success = mFmqRequestChannel.readBlocking(&datum, 1);
Michael Butler8fc48962021-01-08 17:21:27 -0800531
532 // retrieve remaining elements
Michael Butler76e491f2020-12-19 01:55:32 -0800533 // NOTE: all of the data is already available at this point, so there's no need to do a blocking
534 // wait to wait for more data. This is known because in FMQ, all writes are published (made
535 // available) atomically. Currently, the producer always publishes the entire packet in one
536 // function call, so if the first element of the packet is available, the remaining elements are
537 // also available.
538 const size_t count = mFmqRequestChannel.availableToRead();
Michael Butler8fc48962021-01-08 17:21:27 -0800539 std::vector<FmqRequestDatum> packet(count + 1);
540 std::memcpy(&packet.front(), &datum, sizeof(datum));
Michael Butler76e491f2020-12-19 01:55:32 -0800541 success &= mFmqRequestChannel.read(packet.data() + 1, count);
Michael Butler8fc48962021-01-08 17:21:27 -0800542
543 // terminate loop
544 if (mTeardown) {
Michael Butler76e491f2020-12-19 01:55:32 -0800545 return NN_ERROR() << "FMQ object is being torn down";
Michael Butler8fc48962021-01-08 17:21:27 -0800546 }
547
548 // ensure packet was successfully received
549 if (!success) {
Michael Butler76e491f2020-12-19 01:55:32 -0800550 return NN_ERROR() << "Error receiving packet";
Michael Butler8fc48962021-01-08 17:21:27 -0800551 }
552
Michael Butler76e491f2020-12-19 01:55:32 -0800553 return packet;
Michael Butler8fc48962021-01-08 17:21:27 -0800554}
555
556// ResultChannelSender methods
557
Michael Butler76e491f2020-12-19 01:55:32 -0800558nn::GeneralResult<std::unique_ptr<ResultChannelSender>> ResultChannelSender::create(
559 const MQDescriptorSync<FmqResultDatum>& resultChannel) {
560 auto resultChannelSender =
561 std::make_unique<ResultChannelSender>(PrivateConstructorTag{}, resultChannel);
Michael Butler8fc48962021-01-08 17:21:27 -0800562
Michael Butler76e491f2020-12-19 01:55:32 -0800563 if (!resultChannelSender->mFmqResultChannel.isValid()) {
564 return NN_ERROR() << "Unable to create RequestChannelSender";
Michael Butler8fc48962021-01-08 17:21:27 -0800565 }
Michael Butler76e491f2020-12-19 01:55:32 -0800566 if (resultChannelSender->mFmqResultChannel.getEventFlagWord() == nullptr) {
567 return NN_ERROR()
568 << "ResultChannelSender::create was passed an MQDescriptor without an EventFlag";
Michael Butler8fc48962021-01-08 17:21:27 -0800569 }
570
Michael Butler76e491f2020-12-19 01:55:32 -0800571 return resultChannelSender;
Michael Butler8fc48962021-01-08 17:21:27 -0800572}
573
Michael Butler76e491f2020-12-19 01:55:32 -0800574ResultChannelSender::ResultChannelSender(PrivateConstructorTag /*tag*/,
575 const MQDescriptorSync<FmqResultDatum>& resultChannel)
576 : mFmqResultChannel(resultChannel) {}
Michael Butler8fc48962021-01-08 17:21:27 -0800577
Michael Butler76e491f2020-12-19 01:55:32 -0800578void ResultChannelSender::send(V1_0::ErrorStatus errorStatus,
Michael Butler8fc48962021-01-08 17:21:27 -0800579 const std::vector<V1_2::OutputShape>& outputShapes,
580 V1_2::Timing timing) {
581 const std::vector<FmqResultDatum> serialized = serialize(errorStatus, outputShapes, timing);
Michael Butler76e491f2020-12-19 01:55:32 -0800582 sendPacket(serialized);
Michael Butler8fc48962021-01-08 17:21:27 -0800583}
584
Michael Butler76e491f2020-12-19 01:55:32 -0800585void ResultChannelSender::sendPacket(const std::vector<FmqResultDatum>& packet) {
586 if (packet.size() > mFmqResultChannel.availableToWrite()) {
Michael Butler8fc48962021-01-08 17:21:27 -0800587 LOG(ERROR)
588 << "ResultChannelSender::sendPacket -- packet size exceeds size available in FMQ";
589 const std::vector<FmqResultDatum> errorPacket =
590 serialize(V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming);
591
Michael Butler76e491f2020-12-19 01:55:32 -0800592 // Always send the packet with "blocking" because this signals the futex and unblocks the
593 // consumer if it is waiting on the futex.
594 mFmqResultChannel.writeBlocking(errorPacket.data(), errorPacket.size());
595 } else {
596 // Always send the packet with "blocking" because this signals the futex and unblocks the
597 // consumer if it is waiting on the futex.
598 mFmqResultChannel.writeBlocking(packet.data(), packet.size());
Michael Butler8fc48962021-01-08 17:21:27 -0800599 }
Michael Butler8fc48962021-01-08 17:21:27 -0800600}
601
602// ResultChannelReceiver methods
603
Michael Butler76e491f2020-12-19 01:55:32 -0800604nn::GeneralResult<
605 std::pair<std::unique_ptr<ResultChannelReceiver>, const MQDescriptorSync<FmqResultDatum>*>>
Michael Butler8fc48962021-01-08 17:21:27 -0800606ResultChannelReceiver::create(size_t channelLength, std::chrono::microseconds pollingTimeWindow) {
Michael Butler76e491f2020-12-19 01:55:32 -0800607 auto resultChannelReceiver = std::make_unique<ResultChannelReceiver>(
608 PrivateConstructorTag{}, channelLength, pollingTimeWindow);
609 if (!resultChannelReceiver->mFmqResultChannel.isValid()) {
610 return NN_ERROR() << "Unable to create ResultChannelReceiver";
Michael Butler8fc48962021-01-08 17:21:27 -0800611 }
612
Michael Butler76e491f2020-12-19 01:55:32 -0800613 const MQDescriptorSync<FmqResultDatum>* descriptor =
614 resultChannelReceiver->mFmqResultChannel.getDesc();
615 return std::make_pair(std::move(resultChannelReceiver), descriptor);
Michael Butler8fc48962021-01-08 17:21:27 -0800616}
617
Michael Butler76e491f2020-12-19 01:55:32 -0800618ResultChannelReceiver::ResultChannelReceiver(PrivateConstructorTag /*tag*/, size_t channelLength,
Michael Butler8fc48962021-01-08 17:21:27 -0800619 std::chrono::microseconds pollingTimeWindow)
Michael Butler76e491f2020-12-19 01:55:32 -0800620 : mFmqResultChannel(channelLength, /*configureEventFlagWord=*/true),
621 kPollingTimeWindow(pollingTimeWindow) {}
Michael Butler8fc48962021-01-08 17:21:27 -0800622
Michael Butler76e491f2020-12-19 01:55:32 -0800623nn::Result<std::tuple<V1_0::ErrorStatus, std::vector<V1_2::OutputShape>, V1_2::Timing>>
Michael Butler8fc48962021-01-08 17:21:27 -0800624ResultChannelReceiver::getBlocking() {
Michael Butler76e491f2020-12-19 01:55:32 -0800625 const auto packet = NN_TRY(getPacketBlocking());
626 return deserialize(packet);
Michael Butler8fc48962021-01-08 17:21:27 -0800627}
628
Michael Butler76e491f2020-12-19 01:55:32 -0800629void ResultChannelReceiver::notifyAsDeadObject() {
Michael Butler8fc48962021-01-08 17:21:27 -0800630 mValid = false;
631
632 // force unblock
Michael Butler76e491f2020-12-19 01:55:32 -0800633 // ExecutionBurstController waits on a result packet after sending a request. If the driver
634 // containing ExecutionBurstServer crashes, the controller may be waiting on the futex. This
635 // force unblock wakes up any thread waiting on the futex.
636 const auto data = serialize(V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming);
637 mFmqResultChannel.writeBlocking(data.data(), data.size());
Michael Butler8fc48962021-01-08 17:21:27 -0800638}
639
Michael Butler76e491f2020-12-19 01:55:32 -0800640nn::Result<std::vector<FmqResultDatum>> ResultChannelReceiver::getPacketBlocking() {
Michael Butler8fc48962021-01-08 17:21:27 -0800641 if (!mValid) {
Michael Butler76e491f2020-12-19 01:55:32 -0800642 return NN_ERROR() << "FMQ object is invalid";
Michael Butler8fc48962021-01-08 17:21:27 -0800643 }
644
Michael Butler76e491f2020-12-19 01:55:32 -0800645 // First spend time polling if results are available in FMQ instead of waiting on the futex.
646 // Polling is more responsive (yielding lower latencies), but can take up more power, so only
647 // poll for a limited period of time.
Michael Butler8fc48962021-01-08 17:21:27 -0800648
649 auto& getCurrentTime = std::chrono::high_resolution_clock::now;
650 const auto timeToStopPolling = getCurrentTime() + kPollingTimeWindow;
651
652 while (getCurrentTime() < timeToStopPolling) {
653 // if class is being torn down, immediately return
654 if (!mValid.load(std::memory_order_relaxed)) {
Michael Butler76e491f2020-12-19 01:55:32 -0800655 return NN_ERROR() << "FMQ object is invalid";
Michael Butler8fc48962021-01-08 17:21:27 -0800656 }
657
Michael Butler76e491f2020-12-19 01:55:32 -0800658 // Check if data is available. If it is, immediately retrieve it and return.
659 const size_t available = mFmqResultChannel.availableToRead();
Michael Butler8fc48962021-01-08 17:21:27 -0800660 if (available > 0) {
661 std::vector<FmqResultDatum> packet(available);
Michael Butler76e491f2020-12-19 01:55:32 -0800662 const bool success = mFmqResultChannel.readBlocking(packet.data(), available);
Michael Butler8fc48962021-01-08 17:21:27 -0800663 if (!success) {
Michael Butler76e491f2020-12-19 01:55:32 -0800664 return NN_ERROR() << "Error receiving packet";
Michael Butler8fc48962021-01-08 17:21:27 -0800665 }
Michael Butler76e491f2020-12-19 01:55:32 -0800666 return packet;
Michael Butler8fc48962021-01-08 17:21:27 -0800667 }
668 }
669
Michael Butler76e491f2020-12-19 01:55:32 -0800670 // If we get to this point, we either stopped polling because it was taking too long or polling
671 // was not allowed. Instead, perform a blocking call which uses a futex to save power.
Michael Butler8fc48962021-01-08 17:21:27 -0800672
673 // wait for result packet and read first element of result packet
674 FmqResultDatum datum;
Michael Butler76e491f2020-12-19 01:55:32 -0800675 bool success = mFmqResultChannel.readBlocking(&datum, 1);
Michael Butler8fc48962021-01-08 17:21:27 -0800676
677 // retrieve remaining elements
Michael Butler76e491f2020-12-19 01:55:32 -0800678 // NOTE: all of the data is already available at this point, so there's no need to do a blocking
679 // wait to wait for more data. This is known because in FMQ, all writes are published (made
680 // available) atomically. Currently, the producer always publishes the entire packet in one
681 // function call, so if the first element of the packet is available, the remaining elements are
682 // also available.
683 const size_t count = mFmqResultChannel.availableToRead();
Michael Butler8fc48962021-01-08 17:21:27 -0800684 std::vector<FmqResultDatum> packet(count + 1);
685 std::memcpy(&packet.front(), &datum, sizeof(datum));
Michael Butler76e491f2020-12-19 01:55:32 -0800686 success &= mFmqResultChannel.read(packet.data() + 1, count);
Michael Butler8fc48962021-01-08 17:21:27 -0800687
688 if (!mValid) {
Michael Butler76e491f2020-12-19 01:55:32 -0800689 return NN_ERROR() << "FMQ object is invalid";
Michael Butler8fc48962021-01-08 17:21:27 -0800690 }
691
692 // ensure packet was successfully received
693 if (!success) {
Michael Butler76e491f2020-12-19 01:55:32 -0800694 return NN_ERROR() << "Error receiving packet";
Michael Butler8fc48962021-01-08 17:21:27 -0800695 }
696
Michael Butler76e491f2020-12-19 01:55:32 -0800697 return packet;
Michael Butler8fc48962021-01-08 17:21:27 -0800698}
699
700} // namespace android::hardware::neuralnetworks::V1_2::utils