blob: b589c468ce436d9b0740bfb1180210af7a3d7f52 [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
Michael Butler137ee992021-11-01 16:40:31 -070017#include "BurstUtils.h"
Michael Butler8fc48962021-01-08 17:21:27 -080018
19#include <android-base/logging.h>
Michael Butler76e491f2020-12-19 01:55:32 -080020#include <android-base/properties.h>
Michael Butler8fc48962021-01-08 17:21:27 -080021#include <android/hardware/neuralnetworks/1.0/types.h>
22#include <android/hardware/neuralnetworks/1.1/types.h>
23#include <android/hardware/neuralnetworks/1.2/types.h>
24#include <fmq/MessageQueue.h>
25#include <hidl/MQDescriptor.h>
Michael Butler76e491f2020-12-19 01:55:32 -080026#include <nnapi/Result.h>
27#include <nnapi/Types.h>
Michael Butlere8645c32021-10-15 18:42:32 -070028#include <nnapi/hal/1.0/ProtectCallback.h>
Michael Butler8fc48962021-01-08 17:21:27 -080029
30#include <atomic>
31#include <chrono>
32#include <memory>
33#include <thread>
34#include <tuple>
35#include <utility>
36#include <vector>
37
38namespace android::hardware::neuralnetworks::V1_2::utils {
39namespace {
40
41constexpr V1_2::Timing kNoTiming = {std::numeric_limits<uint64_t>::max(),
42 std::numeric_limits<uint64_t>::max()};
43
Michael Butler76e491f2020-12-19 01:55:32 -080044std::chrono::microseconds getPollingTimeWindow(const std::string& property) {
45 constexpr int32_t kDefaultPollingTimeWindow = 0;
46#ifdef NN_DEBUGGABLE
47 constexpr int32_t kMinPollingTimeWindow = 0;
48 const int32_t selectedPollingTimeWindow =
49 base::GetIntProperty(property, kDefaultPollingTimeWindow, kMinPollingTimeWindow);
50 return std::chrono::microseconds(selectedPollingTimeWindow);
51#else
52 (void)property;
53 return std::chrono::microseconds(kDefaultPollingTimeWindow);
54#endif // NN_DEBUGGABLE
55}
56
57} // namespace
58
59std::chrono::microseconds getBurstControllerPollingTimeWindow() {
60 return getPollingTimeWindow("debug.nn.burst-controller-polling-window");
61}
62
63std::chrono::microseconds getBurstServerPollingTimeWindow() {
64 return getPollingTimeWindow("debug.nn.burst-server-polling-window");
Michael Butler8fc48962021-01-08 17:21:27 -080065}
66
67// serialize a request into a packet
68std::vector<FmqRequestDatum> serialize(const V1_0::Request& request, V1_2::MeasureTiming measure,
69 const std::vector<int32_t>& slots) {
70 // count how many elements need to be sent for a request
Michael Butler76e491f2020-12-19 01:55:32 -080071 size_t count = 2 + request.inputs.size() + request.outputs.size() + slots.size();
Michael Butler8fc48962021-01-08 17:21:27 -080072 for (const auto& input : request.inputs) {
73 count += input.dimensions.size();
74 }
75 for (const auto& output : request.outputs) {
76 count += output.dimensions.size();
77 }
Michael Butler76e491f2020-12-19 01:55:32 -080078 CHECK_LE(count, std::numeric_limits<uint32_t>::max());
Michael Butler8fc48962021-01-08 17:21:27 -080079
80 // create buffer to temporarily store elements
81 std::vector<FmqRequestDatum> data;
82 data.reserve(count);
83
84 // package packetInfo
Michael Butler76e491f2020-12-19 01:55:32 -080085 data.emplace_back();
86 data.back().packetInformation(
87 {.packetSize = static_cast<uint32_t>(count),
88 .numberOfInputOperands = static_cast<uint32_t>(request.inputs.size()),
89 .numberOfOutputOperands = static_cast<uint32_t>(request.outputs.size()),
90 .numberOfPools = static_cast<uint32_t>(slots.size())});
Michael Butler8fc48962021-01-08 17:21:27 -080091
92 // package input data
93 for (const auto& input : request.inputs) {
94 // package operand information
Michael Butler76e491f2020-12-19 01:55:32 -080095 data.emplace_back();
96 data.back().inputOperandInformation(
97 {.hasNoValue = input.hasNoValue,
98 .location = input.location,
99 .numberOfDimensions = static_cast<uint32_t>(input.dimensions.size())});
Michael Butler8fc48962021-01-08 17:21:27 -0800100
101 // package operand dimensions
102 for (uint32_t dimension : input.dimensions) {
Michael Butler76e491f2020-12-19 01:55:32 -0800103 data.emplace_back();
104 data.back().inputOperandDimensionValue(dimension);
Michael Butler8fc48962021-01-08 17:21:27 -0800105 }
106 }
107
108 // package output data
109 for (const auto& output : request.outputs) {
110 // package operand information
Michael Butler76e491f2020-12-19 01:55:32 -0800111 data.emplace_back();
112 data.back().outputOperandInformation(
113 {.hasNoValue = output.hasNoValue,
114 .location = output.location,
115 .numberOfDimensions = static_cast<uint32_t>(output.dimensions.size())});
Michael Butler8fc48962021-01-08 17:21:27 -0800116
117 // package operand dimensions
118 for (uint32_t dimension : output.dimensions) {
Michael Butler76e491f2020-12-19 01:55:32 -0800119 data.emplace_back();
120 data.back().outputOperandDimensionValue(dimension);
Michael Butler8fc48962021-01-08 17:21:27 -0800121 }
122 }
123
124 // package pool identifier
125 for (int32_t slot : slots) {
Michael Butler76e491f2020-12-19 01:55:32 -0800126 data.emplace_back();
127 data.back().poolIdentifier(slot);
Michael Butler8fc48962021-01-08 17:21:27 -0800128 }
129
130 // package measureTiming
Michael Butler76e491f2020-12-19 01:55:32 -0800131 data.emplace_back();
132 data.back().measureTiming(measure);
133
134 CHECK_EQ(data.size(), count);
Michael Butler8fc48962021-01-08 17:21:27 -0800135
136 // return packet
137 return data;
138}
139
140// serialize result
141std::vector<FmqResultDatum> serialize(V1_0::ErrorStatus errorStatus,
142 const std::vector<V1_2::OutputShape>& outputShapes,
143 V1_2::Timing timing) {
144 // count how many elements need to be sent for a request
145 size_t count = 2 + outputShapes.size();
146 for (const auto& outputShape : outputShapes) {
147 count += outputShape.dimensions.size();
148 }
149
150 // create buffer to temporarily store elements
151 std::vector<FmqResultDatum> data;
152 data.reserve(count);
153
154 // package packetInfo
Michael Butler76e491f2020-12-19 01:55:32 -0800155 data.emplace_back();
156 data.back().packetInformation({.packetSize = static_cast<uint32_t>(count),
157 .errorStatus = errorStatus,
158 .numberOfOperands = static_cast<uint32_t>(outputShapes.size())});
Michael Butler8fc48962021-01-08 17:21:27 -0800159
160 // package output shape data
161 for (const auto& operand : outputShapes) {
162 // package operand information
Michael Butler76e491f2020-12-19 01:55:32 -0800163 data.emplace_back();
164 data.back().operandInformation(
165 {.isSufficient = operand.isSufficient,
166 .numberOfDimensions = static_cast<uint32_t>(operand.dimensions.size())});
Michael Butler8fc48962021-01-08 17:21:27 -0800167
168 // package operand dimensions
169 for (uint32_t dimension : operand.dimensions) {
Michael Butler76e491f2020-12-19 01:55:32 -0800170 data.emplace_back();
171 data.back().operandDimensionValue(dimension);
Michael Butler8fc48962021-01-08 17:21:27 -0800172 }
173 }
174
175 // package executionTiming
Michael Butler76e491f2020-12-19 01:55:32 -0800176 data.emplace_back();
177 data.back().executionTiming(timing);
178
179 CHECK_EQ(data.size(), count);
Michael Butler8fc48962021-01-08 17:21:27 -0800180
181 // return result
182 return data;
183}
184
185// deserialize request
Michael Butler76e491f2020-12-19 01:55:32 -0800186nn::Result<std::tuple<V1_0::Request, std::vector<int32_t>, V1_2::MeasureTiming>> deserialize(
Michael Butler8fc48962021-01-08 17:21:27 -0800187 const std::vector<FmqRequestDatum>& data) {
188 using discriminator = FmqRequestDatum::hidl_discriminator;
189
190 size_t index = 0;
191
192 // validate packet information
193 if (data.size() == 0 || data[index].getDiscriminator() != discriminator::packetInformation) {
Michael Butler76e491f2020-12-19 01:55:32 -0800194 return NN_ERROR() << "FMQ Request packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800195 }
196
197 // unpackage packet information
198 const FmqRequestDatum::PacketInformation& packetInfo = data[index].packetInformation();
199 index++;
200 const uint32_t packetSize = packetInfo.packetSize;
201 const uint32_t numberOfInputOperands = packetInfo.numberOfInputOperands;
202 const uint32_t numberOfOutputOperands = packetInfo.numberOfOutputOperands;
203 const uint32_t numberOfPools = packetInfo.numberOfPools;
204
205 // verify packet size
206 if (data.size() != packetSize) {
Michael Butler76e491f2020-12-19 01:55:32 -0800207 return NN_ERROR() << "FMQ Request packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800208 }
209
210 // unpackage input operands
211 std::vector<V1_0::RequestArgument> inputs;
212 inputs.reserve(numberOfInputOperands);
213 for (size_t operand = 0; operand < numberOfInputOperands; ++operand) {
214 // validate input operand information
215 if (data[index].getDiscriminator() != discriminator::inputOperandInformation) {
Michael Butler76e491f2020-12-19 01:55:32 -0800216 return NN_ERROR() << "FMQ Request packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800217 }
218
219 // unpackage operand information
220 const FmqRequestDatum::OperandInformation& operandInfo =
221 data[index].inputOperandInformation();
222 index++;
223 const bool hasNoValue = operandInfo.hasNoValue;
224 const V1_0::DataLocation location = operandInfo.location;
225 const uint32_t numberOfDimensions = operandInfo.numberOfDimensions;
226
227 // unpackage operand dimensions
228 std::vector<uint32_t> dimensions;
229 dimensions.reserve(numberOfDimensions);
230 for (size_t i = 0; i < numberOfDimensions; ++i) {
231 // validate dimension
232 if (data[index].getDiscriminator() != discriminator::inputOperandDimensionValue) {
Michael Butler76e491f2020-12-19 01:55:32 -0800233 return NN_ERROR() << "FMQ Request packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800234 }
235
236 // unpackage dimension
237 const uint32_t dimension = data[index].inputOperandDimensionValue();
238 index++;
239
240 // store result
241 dimensions.push_back(dimension);
242 }
243
244 // store result
245 inputs.push_back(
Michael Butler76e491f2020-12-19 01:55:32 -0800246 {.hasNoValue = hasNoValue, .location = location, .dimensions = dimensions});
Michael Butler8fc48962021-01-08 17:21:27 -0800247 }
248
249 // unpackage output operands
250 std::vector<V1_0::RequestArgument> outputs;
251 outputs.reserve(numberOfOutputOperands);
252 for (size_t operand = 0; operand < numberOfOutputOperands; ++operand) {
253 // validate output operand information
254 if (data[index].getDiscriminator() != discriminator::outputOperandInformation) {
Michael Butler76e491f2020-12-19 01:55:32 -0800255 return NN_ERROR() << "FMQ Request packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800256 }
257
258 // unpackage operand information
259 const FmqRequestDatum::OperandInformation& operandInfo =
260 data[index].outputOperandInformation();
261 index++;
262 const bool hasNoValue = operandInfo.hasNoValue;
263 const V1_0::DataLocation location = operandInfo.location;
264 const uint32_t numberOfDimensions = operandInfo.numberOfDimensions;
265
266 // unpackage operand dimensions
267 std::vector<uint32_t> dimensions;
268 dimensions.reserve(numberOfDimensions);
269 for (size_t i = 0; i < numberOfDimensions; ++i) {
270 // validate dimension
271 if (data[index].getDiscriminator() != discriminator::outputOperandDimensionValue) {
Michael Butler76e491f2020-12-19 01:55:32 -0800272 return NN_ERROR() << "FMQ Request packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800273 }
274
275 // unpackage dimension
276 const uint32_t dimension = data[index].outputOperandDimensionValue();
277 index++;
278
279 // store result
280 dimensions.push_back(dimension);
281 }
282
283 // store result
284 outputs.push_back(
Michael Butler76e491f2020-12-19 01:55:32 -0800285 {.hasNoValue = hasNoValue, .location = location, .dimensions = dimensions});
Michael Butler8fc48962021-01-08 17:21:27 -0800286 }
287
288 // unpackage pools
289 std::vector<int32_t> slots;
290 slots.reserve(numberOfPools);
291 for (size_t pool = 0; pool < numberOfPools; ++pool) {
292 // validate input operand information
293 if (data[index].getDiscriminator() != discriminator::poolIdentifier) {
Michael Butler76e491f2020-12-19 01:55:32 -0800294 return NN_ERROR() << "FMQ Request packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800295 }
296
297 // unpackage operand information
298 const int32_t poolId = data[index].poolIdentifier();
299 index++;
300
301 // store result
302 slots.push_back(poolId);
303 }
304
305 // validate measureTiming
306 if (data[index].getDiscriminator() != discriminator::measureTiming) {
Michael Butler76e491f2020-12-19 01:55:32 -0800307 return NN_ERROR() << "FMQ Request packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800308 }
309
310 // unpackage measureTiming
311 const V1_2::MeasureTiming measure = data[index].measureTiming();
312 index++;
313
314 // validate packet information
315 if (index != packetSize) {
Michael Butler76e491f2020-12-19 01:55:32 -0800316 return NN_ERROR() << "FMQ Result packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800317 }
318
319 // return request
Michael Butler76e491f2020-12-19 01:55:32 -0800320 V1_0::Request request = {.inputs = inputs, .outputs = outputs, .pools = {}};
Michael Butler8fc48962021-01-08 17:21:27 -0800321 return std::make_tuple(std::move(request), std::move(slots), measure);
322}
323
324// deserialize a packet into the result
Michael Butler76e491f2020-12-19 01:55:32 -0800325nn::Result<std::tuple<V1_0::ErrorStatus, std::vector<V1_2::OutputShape>, V1_2::Timing>> deserialize(
326 const std::vector<FmqResultDatum>& data) {
Michael Butler8fc48962021-01-08 17:21:27 -0800327 using discriminator = FmqResultDatum::hidl_discriminator;
Michael Butler8fc48962021-01-08 17:21:27 -0800328 size_t index = 0;
329
330 // validate packet information
331 if (data.size() == 0 || data[index].getDiscriminator() != discriminator::packetInformation) {
Michael Butler76e491f2020-12-19 01:55:32 -0800332 return NN_ERROR() << "FMQ Result packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800333 }
334
335 // unpackage packet information
336 const FmqResultDatum::PacketInformation& packetInfo = data[index].packetInformation();
337 index++;
338 const uint32_t packetSize = packetInfo.packetSize;
339 const V1_0::ErrorStatus errorStatus = packetInfo.errorStatus;
340 const uint32_t numberOfOperands = packetInfo.numberOfOperands;
341
342 // verify packet size
343 if (data.size() != packetSize) {
Michael Butler76e491f2020-12-19 01:55:32 -0800344 return NN_ERROR() << "FMQ Result packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800345 }
346
347 // unpackage operands
Michael Butler76e491f2020-12-19 01:55:32 -0800348 std::vector<V1_2::OutputShape> outputShapes;
349 outputShapes.reserve(numberOfOperands);
Michael Butler8fc48962021-01-08 17:21:27 -0800350 for (size_t operand = 0; operand < numberOfOperands; ++operand) {
351 // validate operand information
352 if (data[index].getDiscriminator() != discriminator::operandInformation) {
Michael Butler76e491f2020-12-19 01:55:32 -0800353 return NN_ERROR() << "FMQ Result packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800354 }
355
356 // unpackage operand information
357 const FmqResultDatum::OperandInformation& operandInfo = data[index].operandInformation();
358 index++;
359 const bool isSufficient = operandInfo.isSufficient;
360 const uint32_t numberOfDimensions = operandInfo.numberOfDimensions;
361
362 // unpackage operand dimensions
363 std::vector<uint32_t> dimensions;
364 dimensions.reserve(numberOfDimensions);
365 for (size_t i = 0; i < numberOfDimensions; ++i) {
366 // validate dimension
367 if (data[index].getDiscriminator() != discriminator::operandDimensionValue) {
Michael Butler76e491f2020-12-19 01:55:32 -0800368 return NN_ERROR() << "FMQ Result packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800369 }
370
371 // unpackage dimension
372 const uint32_t dimension = data[index].operandDimensionValue();
373 index++;
374
375 // store result
376 dimensions.push_back(dimension);
377 }
378
379 // store result
Michael Butler76e491f2020-12-19 01:55:32 -0800380 outputShapes.push_back({.dimensions = dimensions, .isSufficient = isSufficient});
Michael Butler8fc48962021-01-08 17:21:27 -0800381 }
382
383 // validate execution timing
384 if (data[index].getDiscriminator() != discriminator::executionTiming) {
Michael Butler76e491f2020-12-19 01:55:32 -0800385 return NN_ERROR() << "FMQ Result packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800386 }
387
388 // unpackage execution timing
389 const V1_2::Timing timing = data[index].executionTiming();
390 index++;
391
392 // validate packet information
393 if (index != packetSize) {
Michael Butler76e491f2020-12-19 01:55:32 -0800394 return NN_ERROR() << "FMQ Result packet ill-formed";
Michael Butler8fc48962021-01-08 17:21:27 -0800395 }
396
397 // return result
398 return std::make_tuple(errorStatus, std::move(outputShapes), timing);
399}
400
Michael Butler8fc48962021-01-08 17:21:27 -0800401// RequestChannelSender methods
402
Michael Butler76e491f2020-12-19 01:55:32 -0800403nn::GeneralResult<
404 std::pair<std::unique_ptr<RequestChannelSender>, const MQDescriptorSync<FmqRequestDatum>*>>
Michael Butler8fc48962021-01-08 17:21:27 -0800405RequestChannelSender::create(size_t channelLength) {
Michael Butler76e491f2020-12-19 01:55:32 -0800406 auto requestChannelSender =
407 std::make_unique<RequestChannelSender>(PrivateConstructorTag{}, channelLength);
408 if (!requestChannelSender->mFmqRequestChannel.isValid()) {
409 return NN_ERROR() << "Unable to create RequestChannelSender";
Michael Butler8fc48962021-01-08 17:21:27 -0800410 }
411
Michael Butler76e491f2020-12-19 01:55:32 -0800412 const MQDescriptorSync<FmqRequestDatum>* descriptor =
413 requestChannelSender->mFmqRequestChannel.getDesc();
414 return std::make_pair(std::move(requestChannelSender), descriptor);
Michael Butler8fc48962021-01-08 17:21:27 -0800415}
416
Michael Butler76e491f2020-12-19 01:55:32 -0800417RequestChannelSender::RequestChannelSender(PrivateConstructorTag /*tag*/, size_t channelLength)
418 : mFmqRequestChannel(channelLength, /*configureEventFlagWord=*/true) {}
Michael Butler8fc48962021-01-08 17:21:27 -0800419
Michael Butler76e491f2020-12-19 01:55:32 -0800420nn::Result<void> RequestChannelSender::send(const V1_0::Request& request,
421 V1_2::MeasureTiming measure,
422 const std::vector<int32_t>& slots) {
Michael Butler8fc48962021-01-08 17:21:27 -0800423 const std::vector<FmqRequestDatum> serialized = serialize(request, measure, slots);
424 return sendPacket(serialized);
425}
426
Michael Butler76e491f2020-12-19 01:55:32 -0800427nn::Result<void> RequestChannelSender::sendPacket(const std::vector<FmqRequestDatum>& packet) {
Michael Butler8fc48962021-01-08 17:21:27 -0800428 if (!mValid) {
Michael Butler76e491f2020-12-19 01:55:32 -0800429 return NN_ERROR() << "FMQ object is invalid";
Michael Butler8fc48962021-01-08 17:21:27 -0800430 }
431
Michael Butler76e491f2020-12-19 01:55:32 -0800432 if (packet.size() > mFmqRequestChannel.availableToWrite()) {
433 return NN_ERROR()
434 << "RequestChannelSender::sendPacket -- packet size exceeds size available in FMQ";
Michael Butler8fc48962021-01-08 17:21:27 -0800435 }
436
Michael Butler76e491f2020-12-19 01:55:32 -0800437 // Always send the packet with "blocking" because this signals the futex and unblocks the
438 // consumer if it is waiting on the futex.
439 const bool success = mFmqRequestChannel.writeBlocking(packet.data(), packet.size());
440 if (!success) {
441 return NN_ERROR()
442 << "RequestChannelSender::sendPacket -- FMQ's writeBlocking returned an error";
443 }
444
445 return {};
Michael Butler8fc48962021-01-08 17:21:27 -0800446}
447
Michael Butler76e491f2020-12-19 01:55:32 -0800448void RequestChannelSender::notifyAsDeadObject() {
Michael Butler8fc48962021-01-08 17:21:27 -0800449 mValid = false;
450}
451
452// RequestChannelReceiver methods
453
Michael Butler76e491f2020-12-19 01:55:32 -0800454nn::GeneralResult<std::unique_ptr<RequestChannelReceiver>> RequestChannelReceiver::create(
455 const MQDescriptorSync<FmqRequestDatum>& requestChannel,
456 std::chrono::microseconds pollingTimeWindow) {
457 auto requestChannelReceiver = std::make_unique<RequestChannelReceiver>(
458 PrivateConstructorTag{}, requestChannel, pollingTimeWindow);
Michael Butler8fc48962021-01-08 17:21:27 -0800459
Michael Butler76e491f2020-12-19 01:55:32 -0800460 if (!requestChannelReceiver->mFmqRequestChannel.isValid()) {
461 return NN_ERROR() << "Unable to create RequestChannelReceiver";
Michael Butler8fc48962021-01-08 17:21:27 -0800462 }
Michael Butler76e491f2020-12-19 01:55:32 -0800463 if (requestChannelReceiver->mFmqRequestChannel.getEventFlagWord() == nullptr) {
464 return NN_ERROR()
465 << "RequestChannelReceiver::create was passed an MQDescriptor without an EventFlag";
Michael Butler8fc48962021-01-08 17:21:27 -0800466 }
467
Michael Butler76e491f2020-12-19 01:55:32 -0800468 return requestChannelReceiver;
Michael Butler8fc48962021-01-08 17:21:27 -0800469}
470
Michael Butler76e491f2020-12-19 01:55:32 -0800471RequestChannelReceiver::RequestChannelReceiver(
472 PrivateConstructorTag /*tag*/, const MQDescriptorSync<FmqRequestDatum>& requestChannel,
473 std::chrono::microseconds pollingTimeWindow)
474 : mFmqRequestChannel(requestChannel), kPollingTimeWindow(pollingTimeWindow) {}
Michael Butler8fc48962021-01-08 17:21:27 -0800475
Michael Butler76e491f2020-12-19 01:55:32 -0800476nn::Result<std::tuple<V1_0::Request, std::vector<int32_t>, V1_2::MeasureTiming>>
Michael Butler8fc48962021-01-08 17:21:27 -0800477RequestChannelReceiver::getBlocking() {
Michael Butler76e491f2020-12-19 01:55:32 -0800478 const auto packet = NN_TRY(getPacketBlocking());
479 return deserialize(packet);
Michael Butler8fc48962021-01-08 17:21:27 -0800480}
481
482void RequestChannelReceiver::invalidate() {
483 mTeardown = true;
484
485 // force unblock
Michael Butler76e491f2020-12-19 01:55:32 -0800486 // ExecutionBurstServer is by default waiting on a request packet. If the client process
487 // destroys its burst object, the server may still be waiting on the futex. This force unblock
488 // wakes up any thread waiting on the futex.
489 const auto data = serialize(V1_0::Request{}, V1_2::MeasureTiming::NO, {});
490 mFmqRequestChannel.writeBlocking(data.data(), data.size());
Michael Butler8fc48962021-01-08 17:21:27 -0800491}
492
Michael Butler76e491f2020-12-19 01:55:32 -0800493nn::Result<std::vector<FmqRequestDatum>> RequestChannelReceiver::getPacketBlocking() {
Michael Butler8fc48962021-01-08 17:21:27 -0800494 if (mTeardown) {
Michael Butler76e491f2020-12-19 01:55:32 -0800495 return NN_ERROR() << "FMQ object is being torn down";
Michael Butler8fc48962021-01-08 17:21:27 -0800496 }
497
Michael Butler76e491f2020-12-19 01:55:32 -0800498 // First spend time polling if results are available in FMQ instead of waiting on the futex.
499 // Polling is more responsive (yielding lower latencies), but can take up more power, so only
500 // poll for a limited period of time.
Michael Butler8fc48962021-01-08 17:21:27 -0800501
502 auto& getCurrentTime = std::chrono::high_resolution_clock::now;
503 const auto timeToStopPolling = getCurrentTime() + kPollingTimeWindow;
504
505 while (getCurrentTime() < timeToStopPolling) {
506 // if class is being torn down, immediately return
507 if (mTeardown.load(std::memory_order_relaxed)) {
Michael Butler76e491f2020-12-19 01:55:32 -0800508 return NN_ERROR() << "FMQ object is being torn down";
Michael Butler8fc48962021-01-08 17:21:27 -0800509 }
510
Michael Butler76e491f2020-12-19 01:55:32 -0800511 // Check if data is available. If it is, immediately retrieve it and return.
512 const size_t available = mFmqRequestChannel.availableToRead();
Michael Butler8fc48962021-01-08 17:21:27 -0800513 if (available > 0) {
Michael Butler8fc48962021-01-08 17:21:27 -0800514 std::vector<FmqRequestDatum> packet(available);
Michael Butler76e491f2020-12-19 01:55:32 -0800515 const bool success = mFmqRequestChannel.readBlocking(packet.data(), available);
Michael Butler8fc48962021-01-08 17:21:27 -0800516 if (!success) {
Michael Butler76e491f2020-12-19 01:55:32 -0800517 return NN_ERROR() << "Error receiving packet";
Michael Butler8fc48962021-01-08 17:21:27 -0800518 }
Michael Butler76e491f2020-12-19 01:55:32 -0800519 return packet;
Michael Butler8fc48962021-01-08 17:21:27 -0800520 }
Michael Butler0252d5f2021-03-30 20:13:49 -0700521
522 std::this_thread::yield();
Michael Butler8fc48962021-01-08 17:21:27 -0800523 }
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 }
Michael Butler0252d5f2021-03-30 20:13:49 -0700668
669 std::this_thread::yield();
Michael Butler8fc48962021-01-08 17:21:27 -0800670 }
671
Michael Butler76e491f2020-12-19 01:55:32 -0800672 // If we get to this point, we either stopped polling because it was taking too long or polling
673 // was not allowed. Instead, perform a blocking call which uses a futex to save power.
Michael Butler8fc48962021-01-08 17:21:27 -0800674
675 // wait for result packet and read first element of result packet
676 FmqResultDatum datum;
Michael Butler76e491f2020-12-19 01:55:32 -0800677 bool success = mFmqResultChannel.readBlocking(&datum, 1);
Michael Butler8fc48962021-01-08 17:21:27 -0800678
679 // retrieve remaining elements
Michael Butler76e491f2020-12-19 01:55:32 -0800680 // NOTE: all of the data is already available at this point, so there's no need to do a blocking
681 // wait to wait for more data. This is known because in FMQ, all writes are published (made
682 // available) atomically. Currently, the producer always publishes the entire packet in one
683 // function call, so if the first element of the packet is available, the remaining elements are
684 // also available.
685 const size_t count = mFmqResultChannel.availableToRead();
Michael Butler8fc48962021-01-08 17:21:27 -0800686 std::vector<FmqResultDatum> packet(count + 1);
687 std::memcpy(&packet.front(), &datum, sizeof(datum));
Michael Butler76e491f2020-12-19 01:55:32 -0800688 success &= mFmqResultChannel.read(packet.data() + 1, count);
Michael Butler8fc48962021-01-08 17:21:27 -0800689
690 if (!mValid) {
Michael Butler76e491f2020-12-19 01:55:32 -0800691 return NN_ERROR() << "FMQ object is invalid";
Michael Butler8fc48962021-01-08 17:21:27 -0800692 }
693
694 // ensure packet was successfully received
695 if (!success) {
Michael Butler76e491f2020-12-19 01:55:32 -0800696 return NN_ERROR() << "Error receiving packet";
Michael Butler8fc48962021-01-08 17:21:27 -0800697 }
698
Michael Butler76e491f2020-12-19 01:55:32 -0800699 return packet;
Michael Butler8fc48962021-01-08 17:21:27 -0800700}
701
702} // namespace android::hardware::neuralnetworks::V1_2::utils