summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-prod (mdb) <android-build-team-robot@google.com>2020-09-24 00:01:39 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2020-09-24 00:01:39 +0000
commit435500ac9c9dcc01a298e329d6a527d3d18a0790 (patch)
treee96ba1bdf1adeccc9f3513555d33f8787fa36067
parent1dac19fba40aa3aa30f58f0282262219eee1b2fb (diff)
parentae88e9212933a2eb34b336f37307775fced0973e (diff)
downloadml-simpleperf-release.tar.gz
Merge "Snap for 6859336 from f3a14c00046f3497f8a573794974dc2a5be6f35c to simpleperf-release" into simpleperf-releasesimpleperf-release
-rw-r--r--nn/apex/manifest.json2
-rw-r--r--nn/common/Android.bp31
-rw-r--r--nn/common/Types.cpp124
-rw-r--r--nn/common/include/nnapi/OperandTypes.h45
-rw-r--r--nn/common/include/nnapi/OperationTypes.h130
-rw-r--r--nn/common/include/nnapi/Types.h297
6 files changed, 628 insertions, 1 deletions
diff --git a/nn/apex/manifest.json b/nn/apex/manifest.json
index 963ef8717..570b57d9f 100644
--- a/nn/apex/manifest.json
+++ b/nn/apex/manifest.json
@@ -1,4 +1,4 @@
{
"name": "com.android.neuralnetworks",
- "version": 300000000
+ "version": 300900700
}
diff --git a/nn/common/Android.bp b/nn/common/Android.bp
index c484fd15f..65d993247 100644
--- a/nn/common/Android.bp
+++ b/nn/common/Android.bp
@@ -229,6 +229,37 @@ cc_library_static {
}
cc_defaults {
+ name: "neuralnetworks_utils_defaults",
+ host_supported: true,
+ vendor_available: true,
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+}
+
+cc_library_static {
+ name: "neuralnetworks_types",
+ defaults: ["neuralnetworks_utils_defaults"],
+ srcs: [
+ "Types.cpp",
+ ],
+ local_include_dirs: ["include/nnapi"],
+ export_include_dirs: ["include"],
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libutils",
+ ],
+ export_shared_lib_headers: [
+ "libbase",
+ "libcutils",
+ "libutils",
+ ],
+}
+
+cc_defaults {
name: "NeuralNetworksTest_common",
defaults: ["neuralnetworks_float16"],
shared_libs: [
diff --git a/nn/common/Types.cpp b/nn/common/Types.cpp
new file mode 100644
index 000000000..a49a8dc35
--- /dev/null
+++ b/nn/common/Types.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Types.h"
+
+#include <android-base/logging.h>
+
+#include <algorithm>
+#include <cstddef>
+#include <iterator>
+#include <limits>
+#include <optional>
+#include <utility>
+#include <vector>
+
+#include "OperandTypes.h"
+#include "OperationTypes.h"
+
+namespace android::nn {
+namespace {
+
+constexpr size_t safeDivideRoundedUp(size_t numerator, size_t denominator) {
+ CHECK_NE(denominator, 0u);
+ CHECK_LE(numerator, std::numeric_limits<size_t>::max() - denominator);
+ return (numerator + denominator - 1) / denominator;
+}
+
+constexpr size_t safeMultiply(size_t a, size_t b) {
+ if (b == 0) {
+ return 0;
+ }
+ CHECK_LE(a, std::numeric_limits<size_t>::max() / b);
+ return a * b;
+}
+
+std::vector<AlignedData> allocateAligned(const uint8_t* data, size_t length) {
+ constexpr size_t kElementSize = sizeof(AlignedData);
+ const size_t numberElements = safeDivideRoundedUp(length, kElementSize);
+ std::vector<AlignedData> output(numberElements);
+ std::memcpy(output.data(), data, length);
+ return output;
+}
+
+} // anonymous namespace
+
+Model::OperandValues::OperandValues() {
+ constexpr size_t kNumberBytes = 4 * 1024;
+ constexpr size_t kElementSize = sizeof(AlignedData);
+ constexpr size_t kNumberElements = safeDivideRoundedUp(kNumberBytes, kElementSize);
+ mData.reserve(kNumberElements);
+}
+
+Model::OperandValues::OperandValues(const uint8_t* data, size_t length)
+ : mData(allocateAligned(data, length)) {}
+
+DataLocation Model::OperandValues::append(const uint8_t* data, size_t length) {
+ const size_t offset = size();
+ auto contents = allocateAligned(data, length);
+ mData.insert(mData.end(), contents.begin(), contents.end());
+ CHECK_LE(offset, std::numeric_limits<uint32_t>::max());
+ CHECK_LE(length, std::numeric_limits<uint32_t>::max());
+ return {.offset = static_cast<uint32_t>(offset), .length = static_cast<uint32_t>(length)};
+}
+
+const uint8_t* Model::OperandValues::data() const {
+ return reinterpret_cast<const uint8_t*>(mData.data());
+}
+
+size_t Model::OperandValues::size() const {
+ return safeMultiply(mData.size(), sizeof(AlignedData));
+}
+
+Capabilities::OperandPerformanceTable::OperandPerformanceTable(
+ std::vector<OperandPerformance> operandPerformances)
+ : mSorted(std::move(operandPerformances)) {}
+
+std::optional<Capabilities::OperandPerformanceTable> Capabilities::OperandPerformanceTable::create(
+ std::vector<OperandPerformance> operandPerformances) {
+ const auto notUnique = [](const auto& lhs, const auto& rhs) { return !(lhs.type < rhs.type); };
+ const bool isUnique = std::adjacent_find(operandPerformances.begin(), operandPerformances.end(),
+ notUnique) == operandPerformances.end();
+ if (!isUnique) {
+ LOG(ERROR) << "Failed to create OperandPerformanceTable: Input must be sorted by key (in "
+ "ascending order), and there must be no duplicate keys";
+ return std::nullopt;
+ }
+
+ return Capabilities::OperandPerformanceTable(std::move(operandPerformances));
+}
+
+Capabilities::PerformanceInfo Capabilities::OperandPerformanceTable::lookup(
+ OperandType operandType) const {
+ // Search for operand type in the sorted collection.
+ constexpr auto cmp = [](const auto& performance, auto type) { return performance.type < type; };
+ const auto it = std::lower_bound(mSorted.begin(), mSorted.end(), operandType, cmp);
+
+ // If the operand type is found, return its corresponding info.
+ if (it != mSorted.end() && it->type == operandType) {
+ return it->info;
+ }
+
+ // If no performance info is defined, use the default value (float's max).
+ return Capabilities::PerformanceInfo{};
+}
+
+const std::vector<Capabilities::OperandPerformance>&
+Capabilities::OperandPerformanceTable::asVector() const {
+ return mSorted;
+}
+
+} // namespace android::nn
diff --git a/nn/common/include/nnapi/OperandTypes.h b/nn/common/include/nnapi/OperandTypes.h
new file mode 100644
index 000000000..641ffb658
--- /dev/null
+++ b/nn/common/include/nnapi/OperandTypes.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_FRAMEWORKS_ML_NN_COMMON_NNAPI_OPERAND_TYPES_H
+#define ANDROID_FRAMEWORKS_ML_NN_COMMON_NNAPI_OPERAND_TYPES_H
+
+namespace android::nn {
+
+enum class OperandType {
+ FLOAT32 = 0,
+ INT32 = 1,
+ UINT32 = 2,
+ TENSOR_FLOAT32 = 3,
+ TENSOR_INT32 = 4,
+ TENSOR_QUANT8_ASYMM = 5,
+ BOOL = 6,
+ TENSOR_QUANT16_SYMM = 7,
+ TENSOR_FLOAT16 = 8,
+ TENSOR_BOOL8 = 9,
+ FLOAT16 = 10,
+ TENSOR_QUANT8_SYMM_PER_CHANNEL = 11,
+ TENSOR_QUANT16_ASYMM = 12,
+ TENSOR_QUANT8_SYMM = 13,
+ TENSOR_QUANT8_ASYMM_SIGNED = 14,
+ SUBGRAPH = 15,
+ OEM = 10000,
+ TENSOR_OEM_BYTE = 10001,
+};
+
+} // namespace android::nn
+
+#endif // ANDROID_FRAMEWORKS_ML_NN_COMMON_NNAPI_OPERAND_TYPES_H
diff --git a/nn/common/include/nnapi/OperationTypes.h b/nn/common/include/nnapi/OperationTypes.h
new file mode 100644
index 000000000..5d8c59405
--- /dev/null
+++ b/nn/common/include/nnapi/OperationTypes.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_FRAMEWORKS_ML_NN_COMMON_NNAPI_OPERATION_TYPES_H
+#define ANDROID_FRAMEWORKS_ML_NN_COMMON_NNAPI_OPERATION_TYPES_H
+
+namespace android::nn {
+
+enum class OperationType {
+ ADD = 0,
+ AVERAGE_POOL_2D = 1,
+ CONCATENATION = 2,
+ CONV_2D = 3,
+ DEPTHWISE_CONV_2D = 4,
+ DEPTH_TO_SPACE = 5,
+ DEQUANTIZE = 6,
+ EMBEDDING_LOOKUP = 7,
+ FLOOR = 8,
+ FULLY_CONNECTED = 9,
+ HASHTABLE_LOOKUP = 10,
+ L2_NORMALIZATION = 11,
+ L2_POOL_2D = 12,
+ LOCAL_RESPONSE_NORMALIZATION = 13,
+ LOGISTIC = 14,
+ LSH_PROJECTION = 15,
+ LSTM = 16,
+ MAX_POOL_2D = 17,
+ MUL = 18,
+ RELU = 19,
+ RELU1 = 20,
+ RELU6 = 21,
+ RESHAPE = 22,
+ RESIZE_BILINEAR = 23,
+ RNN = 24,
+ SOFTMAX = 25,
+ SPACE_TO_DEPTH = 26,
+ SVDF = 27,
+ TANH = 28,
+ BATCH_TO_SPACE_ND = 29,
+ DIV = 30,
+ MEAN = 31,
+ PAD = 32,
+ SPACE_TO_BATCH_ND = 33,
+ SQUEEZE = 34,
+ STRIDED_SLICE = 35,
+ SUB = 36,
+ TRANSPOSE = 37,
+ ABS = 38,
+ ARGMAX = 39,
+ ARGMIN = 40,
+ AXIS_ALIGNED_BBOX_TRANSFORM = 41,
+ BIDIRECTIONAL_SEQUENCE_LSTM = 42,
+ BIDIRECTIONAL_SEQUENCE_RNN = 43,
+ BOX_WITH_NMS_LIMIT = 44,
+ CAST = 45,
+ CHANNEL_SHUFFLE = 46,
+ DETECTION_POSTPROCESSING = 47,
+ EQUAL = 48,
+ EXP = 49,
+ EXPAND_DIMS = 50,
+ GATHER = 51,
+ GENERATE_PROPOSALS = 52,
+ GREATER = 53,
+ GREATER_EQUAL = 54,
+ GROUPED_CONV_2D = 55,
+ HEATMAP_MAX_KEYPOINT = 56,
+ INSTANCE_NORMALIZATION = 57,
+ LESS = 58,
+ LESS_EQUAL = 59,
+ LOG = 60,
+ LOGICAL_AND = 61,
+ LOGICAL_NOT = 62,
+ LOGICAL_OR = 63,
+ LOG_SOFTMAX = 64,
+ MAXIMUM = 65,
+ MINIMUM = 66,
+ NEG = 67,
+ NOT_EQUAL = 68,
+ PAD_V2 = 69,
+ POW = 70,
+ PRELU = 71,
+ QUANTIZE = 72,
+ QUANTIZED_16BIT_LSTM = 73,
+ RANDOM_MULTINOMIAL = 74,
+ REDUCE_ALL = 75,
+ REDUCE_ANY = 76,
+ REDUCE_MAX = 77,
+ REDUCE_MIN = 78,
+ REDUCE_PROD = 79,
+ REDUCE_SUM = 80,
+ ROI_ALIGN = 81,
+ ROI_POOLING = 82,
+ RSQRT = 83,
+ SELECT = 84,
+ SIN = 85,
+ SLICE = 86,
+ SPLIT = 87,
+ SQRT = 88,
+ TILE = 89,
+ TOPK_V2 = 90,
+ TRANSPOSE_CONV_2D = 91,
+ UNIDIRECTIONAL_SEQUENCE_LSTM = 92,
+ UNIDIRECTIONAL_SEQUENCE_RNN = 93,
+ RESIZE_NEAREST_NEIGHBOR = 94,
+ QUANTIZED_LSTM = 95,
+ IF = 96,
+ WHILE = 97,
+ ELU = 98,
+ HARD_SWISH = 99,
+ FILL = 100,
+ RANK = 101,
+ OEM_OPERATION = 10000,
+};
+
+} // namespace android::nn
+
+#endif // ANDROID_FRAMEWORKS_ML_NN_COMMON_NNAPI_OPERATION_TYPES_H
diff --git a/nn/common/include/nnapi/Types.h b/nn/common/include/nnapi/Types.h
new file mode 100644
index 000000000..0536a2e2b
--- /dev/null
+++ b/nn/common/include/nnapi/Types.h
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_FRAMEWORKS_ML_NN_COMMON_NNAPI_TYPES_H
+#define ANDROID_FRAMEWORKS_ML_NN_COMMON_NNAPI_TYPES_H
+
+#include <utils/NativeHandle.h>
+#include <utils/StrongPointer.h>
+
+#include <array>
+#include <chrono>
+#include <limits>
+#include <memory>
+#include <optional>
+#include <string>
+#include <type_traits>
+#include <variant>
+#include <vector>
+
+#include "nnapi/OperandTypes.h"
+#include "nnapi/OperationTypes.h"
+
+namespace android::nn {
+
+// Forward declarations
+
+class IBuffer;
+class IDevice;
+class IPreparedModel;
+
+// Default values
+
+constexpr uint64_t kNoTiming = std::numeric_limits<uint64_t>::max();
+constexpr float kDefaultExecTime = std::numeric_limits<float>::max();
+constexpr float kDefaultPowerUsage = std::numeric_limits<float>::max();
+constexpr uint32_t kByteSizeOfCacheToken = 32;
+constexpr uint32_t kMaxNumberOfCacheFiles = 32;
+constexpr uint8_t kExtensionTypeBits = 16;
+constexpr uint8_t kExtensionPrefixBits = 16;
+
+// Aliases
+
+using AlignedData = std::max_align_t;
+using SharedBuffer = std::shared_ptr<const IBuffer>;
+using SharedDevice = std::shared_ptr<const IDevice>;
+using PreparedModel = std::shared_ptr<const IPreparedModel>;
+
+// Canonical types
+
+enum class DeviceStatus {
+ AVAILABLE = 0,
+ BUSY = 1,
+ OFFLINE = 2,
+ UNKNOWN = 3,
+};
+
+enum class ExecutionPreference {
+ LOW_POWER = 0,
+ FAST_SINGLE_ANSWER = 1,
+ SUSTAINED_SPEED = 2,
+ DEFAULT = FAST_SINGLE_ANSWER,
+};
+
+enum class DeviceType {
+ UNKNOWN = 0,
+ OTHER = 1,
+ CPU = 2,
+ GPU = 3,
+ ACCELERATOR = 4,
+};
+
+enum class MeasureTiming {
+ NO = 0,
+ YES = 1,
+};
+
+enum class Priority {
+ LOW = 0,
+ MEDIUM = 1,
+ HIGH = 2,
+ DEFAULT = MEDIUM,
+};
+
+// TODO: Should more errors from NeuralNetworks.h be incorporated? The left name shows errors that
+// appear in NeuralNetworks.h but not in the HAL, and the right column shows what these values could
+// map to:
+// * OUT_OF_MEMORY ==> GENERAL_FAILURE / RESOURCE_EXHAUSTED_*
+// * INCOMPLETE ==> GENERAL_FAILURE
+// * UNEXPECTED_NULL ==> INVALID_ARGUMENT
+// * UNMAPPABLE ==> GENERAL_FAILURE
+// * BAD_STATE ==> INVALID_ARGUMENT
+enum class ErrorStatus {
+ NONE = 0,
+ DEVICE_UNAVAILABLE = 1,
+ GENERAL_FAILURE = 2,
+ OUTPUT_INSUFFICIENT_SIZE = 3,
+ INVALID_ARGUMENT = 4,
+ MISSED_DEADLINE_TRANSIENT = 5,
+ MISSED_DEADLINE_PERSISTENT = 6,
+ RESOURCE_EXHAUSTED_TRANSIENT = 7,
+ RESOURCE_EXHAUSTED_PERSISTENT = 8,
+ DEAD_OBJECT = 10000,
+};
+
+using Dimension = uint32_t;
+using Dimensions = std::vector<Dimension>;
+
+using CacheToken = std::array<uint8_t, kByteSizeOfCacheToken>;
+
+struct OutputShape {
+ std::vector<uint32_t> dimensions;
+ bool isSufficient = false;
+};
+
+struct Timing {
+ uint64_t timeOnDevice = kNoTiming;
+ uint64_t timeInDriver = kNoTiming;
+};
+
+struct Capabilities {
+ struct PerformanceInfo {
+ float execTime = kDefaultExecTime;
+ float powerUsage = kDefaultPowerUsage;
+ };
+ struct OperandPerformance {
+ OperandType type{};
+ PerformanceInfo info;
+ };
+ class OperandPerformanceTable {
+ public:
+ static std::optional<OperandPerformanceTable> create(
+ std::vector<OperandPerformance> operandPerformances);
+
+ PerformanceInfo lookup(OperandType type) const;
+ const std::vector<OperandPerformance>& asVector() const;
+
+ private:
+ explicit OperandPerformanceTable(std::vector<OperandPerformance> operandPerformances);
+ std::vector<OperandPerformance> mSorted;
+ };
+
+ PerformanceInfo relaxedFloat32toFloat16PerformanceScalar;
+ PerformanceInfo relaxedFloat32toFloat16PerformanceTensor;
+ OperandPerformanceTable operandPerformance;
+ PerformanceInfo ifPerformance;
+ PerformanceInfo whilePerformance;
+};
+
+struct Extension {
+ struct OperandTypeInformation {
+ uint16_t type = 0;
+ bool isTensor = false;
+ uint32_t byteSize = 0;
+ };
+
+ std::string name;
+ std::vector<OperandTypeInformation> operandTypes;
+};
+
+struct Operation {
+ OperationType type{};
+ std::vector<uint32_t> inputs;
+ std::vector<uint32_t> outputs;
+};
+
+struct DataLocation {
+ std::variant<const void*, void*> pointer;
+ uint32_t poolIndex = 0;
+ uint32_t offset = 0;
+ uint32_t length = 0;
+};
+
+struct Operand {
+ enum class LifeTime {
+ TEMPORARY_VARIABLE = 0,
+ SUBGRAPH_INPUT = 1,
+ SUBGRAPH_OUTPUT = 2,
+ CONSTANT_COPY = 3,
+ CONSTANT_REFERENCE = 4,
+ NO_VALUE = 5,
+ SUBGRAPH = 6,
+ POINTER = 7,
+ };
+ using NoParams = std::monostate;
+ struct SymmPerChannelQuantParams {
+ std::vector<float> scales;
+ uint32_t channelDim = 0;
+ };
+ using ExtensionParams = std::vector<uint8_t>;
+ using ExtraParams = std::variant<NoParams, SymmPerChannelQuantParams, ExtensionParams>;
+
+ OperandType type{};
+ Dimensions dimensions;
+ float scale = 0.0f;
+ int32_t zeroPoint = 0;
+ LifeTime lifetime{};
+ DataLocation location;
+ ExtraParams extraParams;
+};
+
+using NativeHandle = ::android::sp<::android::NativeHandle>;
+
+struct Memory {
+ NativeHandle handle;
+ size_t size = 0;
+ std::string name;
+};
+
+struct Model {
+ struct Subgraph {
+ std::vector<Operand> operands;
+ std::vector<Operation> operations;
+ std::vector<uint32_t> inputIndexes;
+ std::vector<uint32_t> outputIndexes;
+ };
+ class OperandValues {
+ public:
+ OperandValues();
+ OperandValues(const uint8_t* data, size_t length);
+
+ DataLocation append(const uint8_t* data, size_t length);
+
+ const uint8_t* data() const;
+ size_t size() const;
+
+ private:
+ std::vector<AlignedData> mData;
+ };
+ struct ExtensionNameAndPrefix {
+ std::string name;
+ uint16_t prefix = 0;
+ };
+
+ Subgraph main;
+ std::vector<Subgraph> referenced;
+ OperandValues operandValues;
+ std::vector<Memory> pools;
+ bool relaxComputationFloat32toFloat16 = false;
+ std::vector<ExtensionNameAndPrefix> extensionNameToPrefix;
+};
+
+struct BufferDesc {
+ Dimensions dimensions;
+};
+
+struct BufferRole {
+ uint32_t modelIndex = 0;
+ uint32_t ioIndex = 0;
+ float frequency = 0.0f;
+};
+
+struct Request {
+ struct Argument {
+ enum class LifeTime {
+ POOL = 0,
+ NO_VALUE = 1,
+ POINTER = 2,
+ };
+
+ LifeTime lifetime{};
+ DataLocation location;
+ Dimensions dimensions;
+ };
+ enum class MemoryDomainToken : uint32_t {};
+ using MemoryPool = std::variant<Memory, MemoryDomainToken, SharedBuffer>;
+
+ std::vector<Argument> inputs;
+ std::vector<Argument> outputs;
+ std::vector<MemoryPool> pools;
+};
+
+using Clock = std::chrono::steady_clock;
+
+using TimePoint = std::chrono::time_point<Clock, std::chrono::nanoseconds>;
+using OptionalTimePoint = std::optional<TimePoint>;
+
+using TimeoutDuration = std::chrono::nanoseconds;
+using OptionalTimeoutDuration = std::optional<TimeoutDuration>;
+
+enum class Version { ANDROID_OC_MR1, ANDROID_P, ANDROID_Q, ANDROID_R, CURRENT_RUNTIME, INVALID };
+
+} // namespace android::nn
+
+#endif // ANDROID_FRAMEWORKS_ML_NN_COMMON_NNAPI_TYPES_H