chore: import upstream snapshot with attribution
cffconvert / validate (push) Has been skipped
License Check / license-check (push) Failing after 2s

This commit is contained in:
wehub-resource-sync
2026-07-13 12:14:16 +08:00
commit 8a852e4b4e
36502 changed files with 9277225 additions and 0 deletions
@@ -0,0 +1,248 @@
# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
#
# 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.
# ==============================================================================
load("@flatbuffers//:build_defs.bzl", "flatbuffer_android_library", "flatbuffer_cc_library", "flatbuffer_java_library")
load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_cc//cc:cc_test.bzl", "cc_test")
load("@xla//third_party/rules_python/python:py_binary.bzl", "py_binary")
load("//tensorflow/core/platform:build_config_root.bzl", "tf_gpu_tests_tags")
load("//tensorflow/lite:special_rules.bzl", "gpu_compatibility_without_gl_deps_internal_visibility_allowlist", "tflite_extra_gles_deps", "tflite_portable_test_suite")
package(
# copybara:uncomment default_applicable_licenses = ["//tensorflow:LICENSE"],
default_visibility = [
"//visibility:public",
],
licenses = ["notice"],
)
flatbuffer_cc_library(
name = "database_fbs",
srcs = ["database.fbs"],
)
exports_files(srcs = ["database.fbs"])
flatbuffer_java_library(
name = "database_fbs_java",
srcs = ["database.fbs"],
package_prefix = "org.tensorflow",
)
flatbuffer_android_library(
name = "database_fbs_android",
srcs = ["database.fbs"],
package_prefix = "org.tensorflow",
)
cc_library(
name = "canonicalize_value",
srcs = ["canonicalize_value.cc"],
hdrs = ["canonicalize_value.h"],
deps = [
":devicedb",
"@com_google_absl//absl/algorithm:container",
"@com_google_absl//absl/strings",
"@com_googlesource_code_re2//:re2",
],
)
cc_test(
name = "canonicalize_value_test",
srcs = ["canonicalize_value_test.cc"],
deps = [
":canonicalize_value",
":devicedb",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "devicedb",
srcs = [
"devicedb.cc",
],
hdrs = [
"devicedb.h",
"variables.h",
],
deps = [
":database_fbs",
],
)
cc_binary(
name = "json_to_fb",
srcs = ["json_to_fb.cc"],
deps = [
"//tensorflow/lite/tools:command_line_flags",
"@flatbuffers",
],
)
genrule(
name = "devicedb-sample_bin",
srcs = [
"database.fbs",
"devicedb-sample.json",
],
outs = ["devicedb-sample.bin"],
cmd = """
$(location :json_to_fb) \
--fbs=$(location :database.fbs) \
--json_input=$(location :devicedb-sample.json) \
--fb_output=$(@)
""",
tools = [":json_to_fb"],
)
py_binary(
name = "convert_binary_to_cc_source",
srcs = ["convert_binary_to_cc_source.py"],
strict_deps = True,
visibility = ["//visibility:public"],
)
genrule(
name = "devicedb-sample_cc",
srcs = ["devicedb-sample.bin"],
outs = [
"devicedb-sample.cc",
"devicedb-sample.h",
],
# convert_file_to_c_source for some reason doesn't define the global with
# 'extern', which is needed for global const variables in C++.
cmd = """
$(location :convert_binary_to_cc_source) \
--input_binary_file $(location :devicedb-sample.bin) \
--output_header_file $(location :devicedb-sample.h) \
--output_source_file $(location :devicedb-sample.cc) \
--array_variable_name g_tflite_acceleration_devicedb_sample_binary
""",
tools = [":convert_binary_to_cc_source"],
)
cc_library(
name = "devicedb_sample",
srcs = ["devicedb-sample.cc"],
hdrs = [
"devicedb-sample.h",
"variables.h",
],
deps = [":database_fbs"],
)
cc_test(
name = "devicedb_test",
srcs = [
"devicedb_test.cc",
],
deps = [
":database_fbs",
":devicedb",
":devicedb_sample",
"//tensorflow/lite/testing:util",
"@com_google_googletest//:gtest_main",
"@flatbuffers",
],
)
exports_files([
"database.fbs",
"gpu_compatibility.bin",
])
genrule(
name = "gpu_compatibility_binary",
srcs = ["gpu_compatibility.bin"],
outs = [
"gpu_compatibility_binary.h",
"gpu_compatibility_binary.cc",
],
# convert_file_to_c_source for some reason doesn't define the global with
# 'extern', which is needed for global const variables in C++.
cmd = """
$(location :convert_binary_to_cc_source) \
--input_binary_file $(location :gpu_compatibility.bin) \
--output_header_file $(location :gpu_compatibility_binary.h) \
--output_source_file $(location :gpu_compatibility_binary.cc) \
--array_variable_name g_tflite_acceleration_gpu_compatibility_binary
""",
tools = [":convert_binary_to_cc_source"],
)
cc_library(
name = "android_info",
srcs = ["android_info.cc"],
hdrs = ["android_info.h"],
deps = [
"@com_google_absl//absl/status",
],
)
cc_library(
name = "gpu_compatibility_binary_embed",
srcs = [":gpu_compatibility_binary.cc"],
hdrs = [":gpu_compatibility_binary.h"],
)
cc_library(
name = "gpu_compatibility",
hdrs = ["gpu_compatibility.h"],
deps = [
":android_info",
":database_fbs",
":devicedb_sample",
":gpu_compatibility_without_gl_deps",
"//tensorflow/lite/delegates/gpu:delegate_options",
"//tensorflow/lite/delegates/gpu/common:gpu_info",
"@com_google_absl//absl/strings:string_view",
] + tflite_extra_gles_deps(),
)
cc_library(
name = "gpu_compatibility_without_gl_deps",
srcs = ["gpu_compatibility.cc"],
hdrs = ["gpu_compatibility.h"],
visibility = gpu_compatibility_without_gl_deps_internal_visibility_allowlist(),
deps = [
":android_info",
":canonicalize_value",
":database_fbs",
":devicedb",
":gpu_compatibility_binary_embed",
"//tensorflow/lite/delegates/gpu:delegate_options",
"//tensorflow/lite/delegates/gpu/common:gpu_info",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/strings",
"@flatbuffers",
],
)
cc_test(
name = "gpu_compatibility_test",
srcs = ["gpu_compatibility_test.cc"],
tags = tf_gpu_tests_tags() + [
"no_cuda_asan", # TODO(b/181032551).
],
deps = [
":devicedb_sample",
":gpu_compatibility",
"@com_google_googletest//:gtest_main",
],
)
tflite_portable_test_suite()
@@ -0,0 +1,13 @@
# GPU delegate compatibility database
This package provides data and code for deciding if the GPU delegate is
supported on a specific Android device.
## Customizing the database
- Convert from checked-in flatbuffer to json by running `flatc -t --raw-binary
--strict-json database.fbs -- gpu_compatibility.bin`
- Edit the json
- Convert from json to flatbuffer `flatc -b database.fbs --
gpu_compatibility.json`
- Rebuild ../../../java:tensorflow-lite-gpu
@@ -0,0 +1,92 @@
/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
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 "tensorflow/lite/experimental/acceleration/compatibility/android_info.h"
#include <iostream>
#include <string>
#include "absl/status/status.h"
#ifdef __ANDROID__
#include <sys/system_properties.h>
#endif // __ANDROID__
namespace {
std::string GetPropertyValue(const std::string& property) {
#ifdef __ANDROID__
char value[PROP_VALUE_MAX];
__system_property_get(property.c_str(), value);
return std::string(value);
#else // !__ANDROID__
return std::string();
#endif // __ANDROID__
}
} // namespace
namespace tflite {
namespace acceleration {
absl::Status RequestAndroidInfo(AndroidInfo* info_out) {
if (!info_out) {
return absl::InvalidArgumentError("info_out may not be null");
}
info_out->android_sdk_version = GetPropertyValue("ro.build.version.sdk");
info_out->device = GetPropertyValue("ro.product.device");
info_out->model = GetPropertyValue("ro.product.model");
info_out->manufacturer = GetPropertyValue("ro.product.manufacturer");
#ifdef __ANDROID__
// Based on
// https://github.com/flutter/plugins/blob/master/packages/device_info/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/MethodCallHandlerImpl.java
// + QUMA detection (system properties return empty) and qemu detection
// (ro.kernel.qemu).
std::string brand = GetPropertyValue("ro.product.brand");
const std::string& device = info_out->device;
std::string fingerprint = GetPropertyValue("ro.build.fingerprint");
std::string hardware = GetPropertyValue("ro.hardware");
const std::string& model = info_out->model;
const std::string& manufacturer = info_out->manufacturer;
std::string product = GetPropertyValue("ro.build.product");
std::string ro_kernel_qemu = GetPropertyValue("ro.kernel.qemu");
info_out->is_emulator =
((brand.find("generic") == 0 && device.find("generic") == 0) || // NOLINT
fingerprint.find("generic") == 0 || // NOLINT
fingerprint.find("unknown") == 0 || // NOLINT
hardware.find("goldfish") != std::string::npos || // NOLINT
hardware.find("ranchu") != std::string::npos || // NOLINT
model.find("google_sdk") != std::string::npos || // NOLINT
model.find("Emulator") != std::string::npos || // NOLINT
model.find("Android SDK built for x86") != // NOLINT
std::string::npos || // NOLINT
model.find("Android SDK built for arm64") != // NOLINT
std::string::npos || // NOLINT
manufacturer.find("Genymotion") != std::string::npos || // NOLINT
product.find("sdk_google") != std::string::npos || // NOLINT
product.find("google_sdk") != std::string::npos || // NOLINT
product.find("sdk") != std::string::npos || // NOLINT
product.find("sdk_x86") != std::string::npos || // NOLINT
product.find("vbox86p") != std::string::npos || // NOLINT
product.find("emulator") != std::string::npos || // NOLINT
product.find("simulator") != std::string::npos || // NOLINT
ro_kernel_qemu == "1" || // NOLINT
info_out->android_sdk_version.empty()); // NOLINT
#else
info_out->is_emulator = false;
#endif
return absl::OkStatus();
}
} // namespace acceleration
} // namespace tflite
@@ -0,0 +1,45 @@
/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
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 TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_COMPATIBILITY_ANDROID_INFO_H_
#define TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_COMPATIBILITY_ANDROID_INFO_H_
#include <string>
#include "absl/status/status.h"
namespace tflite {
namespace acceleration {
// Information about and Android device, used for determining compatibility
// status.
struct AndroidInfo {
// Property ro.build.version.sdk
std::string android_sdk_version;
// Property ro.product.model
std::string model;
// Property ro.product.device
std::string device;
// Property ro.product.manufacturer
std::string manufacturer;
// Whether code is running on an emulator.
bool is_emulator;
};
absl::Status RequestAndroidInfo(AndroidInfo* info_out);
} // namespace acceleration
} // namespace tflite
#endif // TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_COMPATIBILITY_ANDROID_INFO_H_
@@ -0,0 +1,58 @@
/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
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 "tensorflow/lite/experimental/acceleration/compatibility/canonicalize_value.h"
#include <iterator>
#include <string>
#include "absl/algorithm/container.h"
#include "absl/strings/ascii.h"
#include "absl/strings/string_view.h"
#include "re2/re2.h"
#include "tensorflow/lite/experimental/acceleration/compatibility/variables.h"
namespace tflite::acceleration {
namespace {
inline char ascii_normalise(const unsigned char c) {
if (c == ' ' || c == '-') {
return '_';
}
return absl::ascii_tolower(c);
}
} // namespace
std::string CanonicalizeValue(absl::string_view value) {
std::string output;
absl::c_transform(value, std::back_inserter(output),
tflite::acceleration::ascii_normalise);
return output;
}
std::string CanonicalizeValueWithKey(absl::string_view key,
absl::string_view value) {
std::string output = CanonicalizeValue(value);
std::string gpu_output;
static constexpr LazyRE2 kAngleOnVulkan = {
R"(^(angle_\(samsung_xclipse_[0-9]*\)_on_vulkan))"};
return key == kGPUModel &&
RE2::PartialMatch(output, *kAngleOnVulkan, &gpu_output)
? gpu_output
: output;
}
} // namespace tflite::acceleration
@@ -0,0 +1,33 @@
/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
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 TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_COMPATIBILITY_CANONICALIZE_VALUE_H_
#define TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_COMPATIBILITY_CANONICALIZE_VALUE_H_
#include <string>
#include "absl/strings/string_view.h"
namespace tflite::acceleration {
// Normalises the given ASCII input by converting all alphabets to lower case
// and replacing ' ' and '-' with '_'.
std::string CanonicalizeValue(absl::string_view value);
// Applies the above normalisation plus key specific normalisation.
std::string CanonicalizeValueWithKey(absl::string_view key,
absl::string_view value);
} // namespace tflite::acceleration
#endif // TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_COMPATIBILITY_CANONICALIZE_VALUE_H_
@@ -0,0 +1,51 @@
/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
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 "tensorflow/lite/experimental/acceleration/compatibility/canonicalize_value.h"
#include <string>
#include <gtest/gtest.h>
#include "tensorflow/lite/experimental/acceleration/compatibility/variables.h"
namespace tflite::acceleration {
namespace {
TEST(CanonicalizeValue, CharactersAreLowercased) {
EXPECT_EQ(CanonicalizeValue("hElLo"), "hello");
}
TEST(CanonicalizeValue, HyphensAreReplaced) {
EXPECT_EQ(CanonicalizeValue("-"), "_");
}
TEST(CanonicalizeValue, SpacesAreReplaced) {
EXPECT_EQ(CanonicalizeValue(" "), "_");
}
TEST(CanonicalizeValue, OtherSpecialCharactersAreUnaffected) {
for (unsigned char c = 0; c < 65; ++c) {
if (c == ' ' || c == '-') continue;
std::string s = {1, static_cast<char>(c)};
EXPECT_EQ(CanonicalizeValue(s), s);
}
}
TEST(CanonicalizeValue, SamsungXclipseGpuNormalized) {
EXPECT_EQ(CanonicalizeValueWithKey(
kGPUModel, "ANGLE (Samsung Xclipse 920) on Vulkan 1.1.179"),
"angle_(samsung_xclipse_920)_on_vulkan");
}
} // namespace
} // namespace tflite::acceleration
@@ -0,0 +1,190 @@
# Copyright 2020 The TensorFlow Authors. All Rights Reserved.
#
# 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.
# ==============================================================================
"""Simple script to convert binary file to C++ source code for embedding."""
# This is a version of //tensorflow/lite/python/convert_file_to_c_source.py
# with minimal dependencies to reduce build times. See b/158254039.
import argparse
import datetime
import sys
# Cribbed from //tensorflow/lite/python/util.py
# Changed:
# - Alignment from 4 to 16 for generality (16 can be required for SIMD)
# - Added 'extern' to source for building on C++ target platforms
# - Changed comments to refer to this script, and C++ rather than C
def _convert_bytes_to_cc_source(data,
array_name,
max_line_width=80,
include_guard=None,
include_path=None,
use_tensorflow_license=False):
"""Returns strings representing a C++ constant array containing `data`.
Args:
data: Byte array that will be converted into a C++ constant.
array_name: String to use as the variable name for the constant array.
max_line_width: The longest line length, for formatting purposes.
include_guard: Name to use for the include guard macro definition.
include_path: Optional path to include in the source file.
use_tensorflow_license: Whether to include the standard TensorFlow Apache2
license in the generated files.
Returns:
Text that can be compiled as a C++ source file to link in the data as a
literal array of values.
Text that can be used as a C++ header file to reference the literal array.
"""
starting_pad = " "
array_lines = []
array_line = starting_pad
for value in bytearray(data):
if (len(array_line) + 4) > max_line_width:
array_lines.append(array_line + "\n")
array_line = starting_pad
array_line += " 0x%02x," % value
if len(array_line) > len(starting_pad):
array_lines.append(array_line + "\n")
array_values = "".join(array_lines)
if include_guard is None:
include_guard = "TENSORFLOW_LITE_UTIL_" + array_name.upper() + "_DATA_H_"
if include_path is not None:
include_line = "#include \"{include_path}\"\n".format(
include_path=include_path)
else:
include_line = ""
if use_tensorflow_license:
license_text = """
/* Copyright {year} The TensorFlow Authors. All Rights Reserved.
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.
==============================================================================*/
""".format(year=datetime.date.today().year)
else:
license_text = ""
source_template = """{license_text}
// This is a binary file that has been converted into a C++ data array using the
// //tensorflow/lite/experimental/acceleration/compatibility/convert_binary_to_cc_source.py
// script. This form is useful for compiling into a binary to simplify
// deployment on mobile devices
{include_line}
// We need to keep the data array aligned on some architectures.
#ifdef __has_attribute
#define HAVE_ATTRIBUTE(x) __has_attribute(x)
#else
#define HAVE_ATTRIBUTE(x) 0
#endif
#if HAVE_ATTRIBUTE(aligned) || (defined(__GNUC__) && !defined(__clang__))
#define DATA_ALIGN_ATTRIBUTE __attribute__((aligned(16)))
#else
#define DATA_ALIGN_ATTRIBUTE
#endif
extern const unsigned char {array_name}[] DATA_ALIGN_ATTRIBUTE = {{
{array_values}}};
extern const int {array_name}_len = {array_length};
"""
source_text = source_template.format(
array_name=array_name,
array_length=len(data),
array_values=array_values,
license_text=license_text,
include_line=include_line)
header_template = """
{license_text}
// This is a binary file that has been converted into a C++ data array using the
// //tensorflow/lite/experimental/acceleration/compatibility/convert_binary_to_cc_source.py
// script. This form is useful for compiling into a binary to simplify
// deployment on mobile devices
#ifndef {include_guard}
#define {include_guard}
extern const unsigned char {array_name}[];
extern const int {array_name}_len;
#endif // {include_guard}
"""
header_text = header_template.format(
array_name=array_name,
include_guard=include_guard,
license_text=license_text)
return source_text, header_text
def main():
parser = argparse.ArgumentParser(
description=("Binary to C++ source converter"))
parser.add_argument(
"--input_binary_file",
type=str,
help="Full filepath of input binary.",
required=True)
parser.add_argument(
"--output_header_file",
type=str,
help="Full filepath of output header.",
required=True)
parser.add_argument(
"--array_variable_name",
type=str,
help="Full filepath of output source.",
required=True)
parser.add_argument(
"--output_source_file",
type=str,
help="Name of global variable that will contain the binary data.",
required=True)
flags, _ = parser.parse_known_args(args=sys.argv[1:])
with open(flags.input_binary_file, "rb") as input_handle:
input_data = input_handle.read()
source, header = _convert_bytes_to_cc_source(
data=input_data,
array_name=flags.array_variable_name,
use_tensorflow_license=True)
with open(flags.output_source_file, "w") as source_handle:
source_handle.write(source)
with open(flags.output_header_file, "w") as header_handle:
header_handle.write(header)
if __name__ == "__main__":
main()
@@ -0,0 +1,59 @@
// Copyright 2020 The TensorFlow Authors. All Rights Reserved.
//
// 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.
namespace tflite.acceleration;
enum Comparison : byte {
EQUAL = 0,
MINIMUM = 1,
MAXIMUM = 2,
}
// Mapping from available device features to compatibility decisions. Basic usage is to:
// 1) Map easily available device data (like Android version,
// Manufacturer, Device) to things like SoC vendor, SoC model.
// 2) Map complete device data to delegate-specific features and support status
// 3) Map delegate-specific features to delegate configuration.
//
// The structure describes a decision tree, with multiple matching branches.
// The branches are applied depth-first.
table DeviceDatabase {
root:[DeviceDecisionTreeNode];
}
table DeviceDecisionTreeNode {
// The variables are strings, as we have multiple clients that want to
// introduce their own fields. Known variables are listed in variables.h.
variable:string (shared);
comparison:Comparison;
items:[DeviceDecisionTreeEdge];
}
table DeviceDecisionTreeEdge {
// Under which variable value does this item match.
value:string (key, shared);
// Which child branches should also be consulted and used to override this
// node.
children:[DeviceDecisionTreeNode];
// What information can be derived about this device.
derived_properties:[DerivedProperty];
}
// Derived variable value to combine with detected variables.
table DerivedProperty {
variable:string (shared);
value:string (shared);
}
root_type DeviceDatabase;
@@ -0,0 +1,190 @@
{
"root": [
{
"variable": "tflite.device_model",
"items": [
{
"value": "m712c",
"derived_properties": [
{
"variable": "tflite.soc_model",
"value": "exynos_7872"
}
]
},
{
"value": "sc_02l",
"derived_properties": [
{
"variable": "tflite.soc_model",
"value": "exynos_7885"
}
]
}
]
},
{
"variable": "tflite.device_model",
"items": [
{
"value": "shiraz_ag_2011",
"children": [
{
"variable": "tflite.android_sdk_version",
"items": [
{
"value": "28",
"derived_properties": [
{
"variable": "tflite.gpu.status",
"value": "UNSUPPORTED"
}
]
}
],
"comparison": "MAXIMUM"
}
]
}
]
},
{
"variable": "tflite.opengl_es_version",
"items": [
{
"value": "3.1",
"children": [
{
"variable": "tflite.soc_model",
"items": [
{
"value": "exynos_7872",
"children": [
{
"variable": "tflite.android_sdk_version",
"items": [
{
"value": "24",
"derived_properties": [
{
"variable": "tflite.gpu.status",
"value": "SUPPORTED"
}
]
}
],
"comparison": "MINIMUM"
}
]
},
{
"value": "exynos_7883",
"children": [
{
"variable": "tflite.android_sdk_version",
"items": [
{
"value": "28",
"derived_properties": [
{
"variable": "tflite.gpu.status",
"value": "SUPPORTED"
}
]
}
],
"comparison": "MINIMUM"
}
]
}
]
}
]
}
]
},
{
"variable": "tflite.android_sdk_version",
"items": [
{
"value": "21",
"children": [
{
"variable": "tflite.device_model",
"items": [
{
"value": "huawei_gra_l09",
"children": [
{
"variable": "tflite.device_name",
"items": [
{
"value": "hwgra",
"derived_properties": [
{
"variable": "tflite.gpu.status",
"value": "SUPPORTED"
}
]
}
]
}
]
}
]
}
]
},
{
"value": "24",
"children": [
{
"variable": "tflite.device_model",
"items": [
{
"value": "sm_j810f",
"children": [
{
"variable": "tflite.device_name",
"items": [
{
"value": "j8y18lte",
"derived_properties": [
{
"variable": "tflite.gpu.status",
"value": "UNSUPPORTED"
}
]
}
]
}
]
},
{
"value": "sm_j810m",
"children": [
{
"variable": "tflite.device_name",
"items": [
{
"value": "j8y18lte",
"derived_properties": [
{
"variable": "tflite.gpu.status",
"value": "SUPPORTED"
}
]
}
]
}
]
}
]
}
]
}
]
}
]
}
@@ -0,0 +1,93 @@
/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
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 "tensorflow/lite/experimental/acceleration/compatibility/devicedb.h"
#include <map>
#include <string>
#include <vector>
#include "tensorflow/lite/experimental/acceleration/compatibility/database_generated.h"
namespace tflite {
namespace acceleration {
namespace {
std::vector<const DeviceDecisionTreeEdge*> Find(
const DeviceDecisionTreeNode* root, const std::string& value) {
std::vector<const DeviceDecisionTreeEdge*> found;
if (root->comparison() == Comparison_EQUAL) {
// Exact match.
const DeviceDecisionTreeEdge* possible =
root->items()->LookupByKey(value.c_str());
if (possible) {
found.push_back(possible);
}
} else {
// Minimum/Maximum: value should be at least / at most item's value.
for (const DeviceDecisionTreeEdge* item : *(root->items())) {
if ((root->comparison() == Comparison_MINIMUM)
? value >= item->value()->str()
: value <= item->value()->str()) {
found.push_back(item);
}
}
}
return found;
}
void UpdateVariablesFromDeviceDecisionTreeEdges(
std::map<std::string, std::string>* variable_values,
const DeviceDecisionTreeEdge& item) {
if (item.derived_properties()) {
for (const DerivedProperty* p : *(item.derived_properties())) {
(*variable_values)[p->variable()->str()] = p->value()->str();
}
}
}
void Follow(const DeviceDecisionTreeNode* root,
std::map<std::string, std::string>* variable_values) {
if (!root->variable()) {
return;
}
auto possible_value = variable_values->find(root->variable()->str());
if (possible_value == variable_values->end()) {
return;
}
std::vector<const DeviceDecisionTreeEdge*> edges =
Find(root, possible_value->second);
for (const DeviceDecisionTreeEdge* edge : edges) {
UpdateVariablesFromDeviceDecisionTreeEdges(variable_values, *edge);
if (edge->children()) {
for (const DeviceDecisionTreeNode* root : *(edge->children())) {
Follow(root, variable_values);
}
}
}
}
} // namespace
void UpdateVariablesFromDatabase(
std::map<std::string, std::string>* variable_values,
const DeviceDatabase& database) {
if (!database.root()) return;
for (const DeviceDecisionTreeNode* root : *(database.root())) {
Follow(root, variable_values);
}
}
} // namespace acceleration
} // namespace tflite
@@ -0,0 +1,38 @@
/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
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 TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_COMPATIBILITY_DEVICEDB_H_
#define TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_COMPATIBILITY_DEVICEDB_H_
#include <map>
#include <string>
#include "tensorflow/lite/experimental/acceleration/compatibility/database_generated.h"
namespace tflite {
namespace acceleration {
// Use the variables in `variable_values` to evaluate the decision tree in
// `database` and update the `variable_values` based on derived properties in
// the decision tree.
//
// See database.fbs for a description of the decision tree.
void UpdateVariablesFromDatabase(
std::map<std::string, std::string>* variable_values,
const DeviceDatabase& database);
} // namespace acceleration
} // namespace tflite
#endif // TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_COMPATIBILITY_DEVICEDB_H_
@@ -0,0 +1,159 @@
/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
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 "tensorflow/lite/experimental/acceleration/compatibility/devicedb.h"
#include <map>
#include <string>
#include <gtest/gtest.h>
#include "flatbuffers/flatbuffers.h" // from @flatbuffers
#include "tensorflow/lite/experimental/acceleration/compatibility/devicedb-sample.h"
#include "tensorflow/lite/experimental/acceleration/compatibility/variables.h"
#include "tensorflow/lite/testing/util.h"
namespace tflite {
namespace acceleration {
namespace {
class DeviceDbTest : public ::testing::Test {
protected:
void LoadSample() {
device_db_ = flatbuffers::GetRoot<DeviceDatabase>(
g_tflite_acceleration_devicedb_sample_binary);
}
const DeviceDatabase* device_db_ = nullptr;
};
TEST_F(DeviceDbTest, Load) {
LoadSample();
ASSERT_TRUE(device_db_);
ASSERT_TRUE(device_db_->root());
EXPECT_EQ(device_db_->root()->size(), 4);
}
TEST_F(DeviceDbTest, SocLookup) {
LoadSample();
ASSERT_TRUE(device_db_);
std::map<std::string, std::string> variables;
// Find first device mapping.
variables[kDeviceModel] = "m712c";
UpdateVariablesFromDatabase(&variables, *device_db_);
EXPECT_EQ(variables[kSoCModel], "exynos_7872");
// Find second device mapping.
variables.clear();
variables[kDeviceModel] = "sc_02l";
UpdateVariablesFromDatabase(&variables, *device_db_);
EXPECT_EQ(variables[kSoCModel], "exynos_7885");
// Make sure no results are returned without a match.
variables.clear();
variables[kDeviceModel] = "nosuch";
UpdateVariablesFromDatabase(&variables, *device_db_);
EXPECT_EQ(variables.find(kSoCModel), variables.end());
}
TEST_F(DeviceDbTest, StatusLookupWithSoC) {
LoadSample();
ASSERT_TRUE(device_db_);
std::map<std::string, std::string> variables;
// Find exact match.
variables[kOpenGLESVersion] = "3.1";
variables[kSoCModel] = "exynos_7872";
variables[kAndroidSdkVersion] = "24";
UpdateVariablesFromDatabase(&variables, *device_db_);
EXPECT_EQ(variables[gpu::kStatus], gpu::kStatusSupported);
// Ensure no results without a match.
variables[kOpenGLESVersion] = "3.0";
variables.erase(variables.find(gpu::kStatus));
UpdateVariablesFromDatabase(&variables, *device_db_);
EXPECT_EQ(variables.find(gpu::kStatus), variables.end());
// Find no results with too low an android version.
variables.clear();
variables[kOpenGLESVersion] = "3.1";
variables[kSoCModel] = "exynos_7883";
variables[kAndroidSdkVersion] = "24";
UpdateVariablesFromDatabase(&variables, *device_db_);
EXPECT_EQ(variables.find(gpu::kStatus), variables.end());
// Find a match with android version above minimum.
variables[kAndroidSdkVersion] = "29";
UpdateVariablesFromDatabase(&variables, *device_db_);
EXPECT_EQ(variables[gpu::kStatus], gpu::kStatusSupported);
}
TEST_F(DeviceDbTest, StatusLookupWithDevice) {
LoadSample();
ASSERT_TRUE(device_db_);
std::map<std::string, std::string> variables;
// Find unsupported device (same model, different device).
variables[kAndroidSdkVersion] = "24";
variables[kDeviceModel] = "sm_j810f";
variables[kDeviceName] = "j8y18lte";
UpdateVariablesFromDatabase(&variables, *device_db_);
EXPECT_EQ(variables[gpu::kStatus], gpu::kStatusUnsupported);
// Find supported device (same model, different device).
variables.clear();
variables[kAndroidSdkVersion] = "24";
variables[kDeviceModel] = "sm_j810m";
variables[kDeviceName] = "j8y18lte";
UpdateVariablesFromDatabase(&variables, *device_db_);
EXPECT_EQ(variables[gpu::kStatus], gpu::kStatusSupported);
}
TEST_F(DeviceDbTest, StatusLookupBasedOnDerivedProperties) {
LoadSample();
ASSERT_TRUE(device_db_);
std::map<std::string, std::string> variables;
// Find status based on SoC derived from model.
variables[kOpenGLESVersion] = "3.1";
variables[kAndroidSdkVersion] = "24";
variables[kDeviceModel] = "m712c";
UpdateVariablesFromDatabase(&variables, *device_db_);
EXPECT_EQ(variables[gpu::kStatus], gpu::kStatusSupported);
}
TEST_F(DeviceDbTest, StatusLookupWithMaximumComparison) {
LoadSample();
ASSERT_TRUE(device_db_);
std::map<std::string, std::string> variables;
variables[kDeviceModel] = "shiraz_ag_2011";
// Value exactly equals the maximum, expecting match
variables[kAndroidSdkVersion] = "28";
UpdateVariablesFromDatabase(&variables, *device_db_);
EXPECT_EQ(variables[gpu::kStatus], gpu::kStatusUnsupported);
// Value below the maximum, expecting match
variables[kAndroidSdkVersion] = "27";
variables.erase(variables.find(gpu::kStatus));
UpdateVariablesFromDatabase(&variables, *device_db_);
EXPECT_EQ(variables[gpu::kStatus], gpu::kStatusUnsupported);
// Value above the maximum, expecting no match
variables[kAndroidSdkVersion] = "29";
variables.erase(variables.find(gpu::kStatus));
UpdateVariablesFromDatabase(&variables, *device_db_);
EXPECT_EQ(variables.find(gpu::kStatus), variables.end());
}
} // namespace
} // namespace acceleration
} // namespace tflite
@@ -0,0 +1,179 @@
/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
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 "tensorflow/lite/experimental/acceleration/compatibility/gpu_compatibility.h"
#include <cstdint>
#include <cstdio>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include "absl/strings/string_view.h"
#include "flatbuffers/flatbuffers.h" // from @flatbuffers
#include "tensorflow/lite/experimental/acceleration/compatibility/canonicalize_value.h"
#include "tensorflow/lite/experimental/acceleration/compatibility/database_generated.h"
#include "tensorflow/lite/experimental/acceleration/compatibility/devicedb.h"
#include "tensorflow/lite/experimental/acceleration/compatibility/gpu_compatibility_binary.h"
#include "tensorflow/lite/experimental/acceleration/compatibility/variables.h"
namespace tflite {
namespace acceleration {
namespace {
void CanonicalizeValues(std::map<std::string, std::string>* variable_values) {
for (auto& i : *variable_values) {
i.second = CanonicalizeValueWithKey(i.first, i.second);
}
}
} // namespace
GPUCompatibilityList::GPUCompatibilityList(
const unsigned char* compatibility_list_flatbuffer) {
if (!compatibility_list_flatbuffer) return;
database_ =
flatbuffers::GetRoot<DeviceDatabase>(compatibility_list_flatbuffer);
}
GPUCompatibilityList::GPUCompatibilityList(
std::string compatibility_list_flatbuffer)
: fbcontent_(std::move(compatibility_list_flatbuffer)) {
database_ = flatbuffers::GetRoot<DeviceDatabase>(fbcontent_.data());
}
std::unique_ptr<GPUCompatibilityList> GPUCompatibilityList::Create() {
return Create(g_tflite_acceleration_gpu_compatibility_binary,
g_tflite_acceleration_gpu_compatibility_binary_len);
}
std::unique_ptr<GPUCompatibilityList> GPUCompatibilityList::Create(
const unsigned char* compatibility_list_flatbuffer, size_t length) {
if (!compatibility_list_flatbuffer ||
!IsValidFlatbuffer(compatibility_list_flatbuffer, length)) {
return nullptr;
}
return std::unique_ptr<GPUCompatibilityList>(
new GPUCompatibilityList(compatibility_list_flatbuffer));
}
std::unique_ptr<GPUCompatibilityList> GPUCompatibilityList::Create(
std::string compatibility_list_flatbuffer) {
if (!IsValidFlatbuffer(reinterpret_cast<const unsigned char*>(
compatibility_list_flatbuffer.data()),
compatibility_list_flatbuffer.size())) {
return nullptr;
}
return std::unique_ptr<GPUCompatibilityList>(
new GPUCompatibilityList(std::move(compatibility_list_flatbuffer)));
}
std::map<std::string, std::string> GPUCompatibilityList::CalculateVariables(
const AndroidInfo& android_info,
const ::tflite::gpu::GpuInfo& gpu_info) const {
std::map<std::string, std::string> variables =
InfosToMap(android_info, gpu_info);
CanonicalizeValues(&variables);
if (!database_) return variables;
UpdateVariablesFromDatabase(&variables, *database_);
return variables;
}
bool GPUCompatibilityList::Includes(
const AndroidInfo& android_info,
const ::tflite::gpu::GpuInfo& gpu_info) const {
auto variables = CalculateVariables(android_info, gpu_info);
return variables[gpu::kStatus] == std::string(gpu::kStatusSupported);
}
gpu::CompatibilityStatus GPUCompatibilityList::GetStatus(
const AndroidInfo& android_info,
const ::tflite::gpu::GpuInfo& gpu_info) const {
std::map<std::string, std::string> variables =
InfosToMap(android_info, gpu_info);
return GetStatus(variables);
}
gpu::CompatibilityStatus GPUCompatibilityList::GetStatus(
std::map<std::string, std::string>& variables) const {
CanonicalizeValues(&variables);
if (!database_) return gpu::CompatibilityStatus::kUnknown;
UpdateVariablesFromDatabase(&variables, *database_);
return StringToCompatibilityStatus(variables[gpu::kStatus]);
}
TfLiteGpuDelegateOptionsV2 GPUCompatibilityList::GetBestOptionsFor(
const AndroidInfo& /* android_info */,
const ::tflite::gpu::GpuInfo& /* gpu_info */) const {
// This method is for forwards-compatibility: the list may later include
// information about which backend to choose (OpenGL/OpenCL/Vulkan) or other
// options.
return TfLiteGpuDelegateOptionsV2Default();
}
// static
bool GPUCompatibilityList::IsValidFlatbuffer(const unsigned char* data,
size_t len) {
// Verify opensource db.
flatbuffers::Verifier verifier(reinterpret_cast<const uint8_t*>(data), len);
return tflite::acceleration::VerifyDeviceDatabaseBuffer(verifier);
}
std::map<std::string, std::string> GPUCompatibilityList::InfosToMap(
const AndroidInfo& android_info,
const ::tflite::gpu::GpuInfo& gpu_info) const {
std::map<std::string, std::string> variables;
variables[kAndroidSdkVersion] = android_info.android_sdk_version;
variables[kDeviceModel] = android_info.model;
variables[kDeviceName] = android_info.device;
variables[kManufacturer] = android_info.manufacturer;
const auto& gl_info = gpu_info.opengl_info;
variables[kGPUModel] = gl_info.renderer_name;
char buffer[128];
snprintf(buffer, 128 - 1, "%d.%d", gl_info.major_version,
gl_info.minor_version);
variables[kOpenGLESVersion] = std::string(buffer);
return variables;
}
// static
std::string GPUCompatibilityList::CompatibilityStatusToString(
gpu::CompatibilityStatus status) {
switch (status) {
case gpu::CompatibilityStatus::kSupported:
return gpu::kStatusSupported;
case gpu::CompatibilityStatus::kUnsupported:
return gpu::kStatusUnsupported;
case gpu::CompatibilityStatus::kUnknown:
return gpu::kStatusUnknown;
}
}
// static
gpu::CompatibilityStatus GPUCompatibilityList::StringToCompatibilityStatus(
absl::string_view status) {
if (status == gpu::kStatusSupported) {
return gpu::CompatibilityStatus::kSupported;
} else if (status == gpu::kStatusUnsupported) {
return gpu::CompatibilityStatus::kUnsupported;
}
return gpu::CompatibilityStatus::kUnknown;
}
} // namespace acceleration
} // namespace tflite
@@ -0,0 +1,145 @@
/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
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 TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_COMPATIBILITY_GPU_COMPATIBILITY_H_
#define TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_COMPATIBILITY_GPU_COMPATIBILITY_H_
#include <cstddef>
#include <map>
#include <memory>
#include <string>
#include "absl/strings/string_view.h"
#include "tensorflow/lite/delegates/gpu/common/gpu_info.h"
#include "tensorflow/lite/delegates/gpu/delegate_options.h"
#include "tensorflow/lite/experimental/acceleration/compatibility/android_info.h"
#include "tensorflow/lite/experimental/acceleration/compatibility/database_generated.h"
#include "tensorflow/lite/experimental/acceleration/compatibility/variables.h"
namespace tflite {
namespace acceleration {
// This class provides information on GPU delegate support.
//
// The GPU delegate is supported on a subset of Android devices, depending on
// Android version, OpenGL ES version, GPU chipset etc. The support is based on
// measure stability, correctness and peformance. For more detail see README.md.
//
// Example usage:
// tflite::Interpreter* interpreter = ... ;
// tflite::acceleration::AndroidInfo android_info;
// tflite::gpu::GpuInfo gpu_info;
// EXPECT_OK(tflite::acceleration::RequestAndroidInfo(&android_info));
// EXPECT_OK(tflite::gpu::gl::EglEnvironment::NewEglEnvironment(&env));
// EXPECT_OK(tflite::gpu::gl::RequestGpuInfo(&tflite_gpu_info));
// tflite::acceleration::GPUCompatibilityList list;
// TfLiteDelegate* gpu_delegate = nullptr;
// TfLiteGpuDelegateOptions gpu_options;
// if (list.Includes(android_info, gpu_info)) {
// gpu_options = list.BestOptionsFor(android_info, gpu_info);
// gpu_delegate = TfLiteGpuDelegateCreate(&gpu_options);
// EXPECT_EQ(interpreter->ModifyGraphWithDelegate(gpu_delegate), TfLiteOk);
// } else {
// // Fallback path.
// }
class GPUCompatibilityList {
public:
// Construct list from bundled data. Returns a unique_ptr to a nullptr if
// creation fails.
static std::unique_ptr<GPUCompatibilityList> Create();
// Constructs list from the given flatbuffer data. Returns a unique_ptr to a
// nullptr is the given flatbuffer is empty or invalid.
// The flatbuffer pointer must remain valid during the usage of the
// compatibility list, it is the caller's responsibility to make sure of that.
// To have the compatibility list own the flatbuffer, use the alternative
// Create() method below.
static std::unique_ptr<GPUCompatibilityList> Create(
const unsigned char* compatibility_list_flatbuffer, size_t length);
// Constructs list from the given flatbuffer data. Returns a unique_ptr to a
// nullptr is the given flatbuffer is empty or invalid.
// The passed flatbuffer will be owned by the compatibility list object, so
// this method can be used safely with local temporary strings.
static std::unique_ptr<GPUCompatibilityList> Create(
std::string compatibility_list_flatbuffer);
// Returns true if the provided device specs are supported by the database.
bool Includes(const AndroidInfo& android_info,
const ::tflite::gpu::GpuInfo& gpu_info) const;
// Returns the compatibility status as an enum (unknown/supported/unsupported)
gpu::CompatibilityStatus GetStatus(
const AndroidInfo& android_info,
const ::tflite::gpu::GpuInfo& gpu_info) const;
// Returns the compatibility status as an enum (unknown/supported/unsupported)
// of the provided device specified as a map of variables (properties).
// Map keys should all be from here:
// tensorflow/lite/experimental/acceleration/compatibility/variables.h
gpu::CompatibilityStatus GetStatus(
std::map<std::string, std::string>& variables) const;
// Returns the best TfLiteGpuDelegateOptionsV2 for the provided device specs
// based on the database. The output can be modified as desired before passing
// to delegate creation.
TfLiteGpuDelegateOptionsV2 GetBestOptionsFor(
const AndroidInfo& android_info,
const ::tflite::gpu::GpuInfo& gpu_info) const;
// Convert android_info and gpu_info into a set of variables used for querying
// the list, and update variables from list data. See variables.h
// and devicedb.h for more information.
std::map<std::string, std::string> CalculateVariables(
const AndroidInfo& android_info,
const ::tflite::gpu::GpuInfo& gpu_info) const;
GPUCompatibilityList(const GPUCompatibilityList&) = delete;
GPUCompatibilityList& operator=(const GPUCompatibilityList&) = delete;
// Checks if the provided byte array represents a valid compatibility list
static bool IsValidFlatbuffer(const unsigned char* data, size_t len);
std::map<std::string, std::string> InfosToMap(
const AndroidInfo& android_info,
const ::tflite::gpu::GpuInfo& gpu_info) const;
// Converts the compatibility status enum value to the corresponding status
// string.
static std::string CompatibilityStatusToString(
gpu::CompatibilityStatus status);
// Converts the status string to the corresponding compatibility status enum
// value.
static gpu::CompatibilityStatus StringToCompatibilityStatus(
absl::string_view status);
protected:
const DeviceDatabase* database_;
// Optional container of the flatbuffer content, to support ownership of the
// flatbuffer by the compatibility list object itself.
std::string fbcontent_;
private:
explicit GPUCompatibilityList(
const unsigned char* compatibility_list_flatbuffer);
explicit GPUCompatibilityList(std::string compatibility_list_flatbuffer);
};
} // namespace acceleration
} // namespace tflite
#endif // TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_COMPATIBILITY_GPU_COMPATIBILITY_H_
@@ -0,0 +1,183 @@
/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
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 "tensorflow/lite/experimental/acceleration/compatibility/gpu_compatibility.h"
#include <algorithm>
#include <map>
#include <memory>
#include <string>
#include <gtest/gtest.h>
#include "tensorflow/lite/experimental/acceleration/compatibility/devicedb-sample.h"
#include "tensorflow/lite/experimental/acceleration/compatibility/variables.h"
namespace {
class GPUCompatibilityTest : public ::testing::Test {
protected:
GPUCompatibilityTest() {
list_ = tflite::acceleration::GPUCompatibilityList::Create(
g_tflite_acceleration_devicedb_sample_binary,
g_tflite_acceleration_devicedb_sample_binary_len);
}
std::unique_ptr<tflite::acceleration::GPUCompatibilityList> list_;
};
TEST_F(GPUCompatibilityTest, ReturnsUnsupportedStatus) {
ASSERT_TRUE(list_ != nullptr);
std::map<std::string, std::string> variables = {
{tflite::acceleration::kAndroidSdkVersion, "28"},
{tflite::acceleration::kDeviceModel, "shiraz-ag-2011"},
};
EXPECT_EQ(list_->GetStatus(variables),
tflite::acceleration::gpu::CompatibilityStatus::kUnsupported);
}
TEST_F(GPUCompatibilityTest, ReturnsSupportedStatus) {
ASSERT_TRUE(list_ != nullptr);
std::map<std::string, std::string> variables = {
{tflite::acceleration::kAndroidSdkVersion, "24"},
{tflite::acceleration::kDeviceModel, "M712C"},
{tflite::acceleration::kOpenGLESVersion, "3.1"},
};
EXPECT_EQ(list_->GetStatus(variables),
tflite::acceleration::gpu::CompatibilityStatus::kSupported);
}
TEST_F(GPUCompatibilityTest, ReturnsUnknownStatus) {
ASSERT_TRUE(list_ != nullptr);
std::map<std::string, std::string> variables = {
{tflite::acceleration::kAndroidSdkVersion, "26"},
{tflite::acceleration::kDeviceModel, "mag2016"},
{tflite::acceleration::kOpenGLESVersion, "3.1"},
};
EXPECT_EQ(list_->GetStatus(variables),
tflite::acceleration::gpu::CompatibilityStatus::kUnknown);
}
TEST_F(GPUCompatibilityTest, ReturnsSupportedForFullMatch) {
ASSERT_TRUE(list_ != nullptr);
tflite::acceleration::AndroidInfo android_info = {.android_sdk_version = "24",
.model = "m712c"};
tflite::gpu::GpuInfo tflite_gpu_info;
tflite_gpu_info.opengl_info.major_version = 3;
tflite_gpu_info.opengl_info.minor_version = 1;
EXPECT_TRUE(list_->Includes(android_info, tflite_gpu_info));
}
TEST_F(GPUCompatibilityTest, ReturnsUnsupportedForFullMatch) {
ASSERT_TRUE(list_ != nullptr);
tflite::acceleration::AndroidInfo android_info = {.android_sdk_version = "28",
.model = "SM-G960F",
.device = "starlte",
.manufacturer = "Samsung"};
tflite::gpu::GpuInfo tflite_gpu_info;
tflite_gpu_info.opengl_info.renderer_name = "Mali-G72";
tflite_gpu_info.opengl_info.major_version = 3;
tflite_gpu_info.opengl_info.minor_version = 2;
EXPECT_FALSE(list_->Includes(android_info, tflite_gpu_info));
}
TEST_F(GPUCompatibilityTest, ReturnsDefaultOptions) {
ASSERT_TRUE(list_ != nullptr);
tflite::acceleration::AndroidInfo android_info;
tflite::gpu::GpuInfo tflite_gpu_info;
auto default_options = TfLiteGpuDelegateOptionsV2Default();
auto best_options = list_->GetBestOptionsFor(android_info, tflite_gpu_info);
EXPECT_EQ(best_options.is_precision_loss_allowed,
default_options.is_precision_loss_allowed);
EXPECT_EQ(best_options.inference_preference,
default_options.inference_preference);
EXPECT_EQ(best_options.inference_priority1,
default_options.inference_priority1);
EXPECT_EQ(best_options.inference_priority2,
default_options.inference_priority2);
EXPECT_EQ(best_options.inference_priority3,
default_options.inference_priority3);
EXPECT_EQ(best_options.experimental_flags,
default_options.experimental_flags);
EXPECT_EQ(best_options.max_delegated_partitions,
default_options.max_delegated_partitions);
}
TEST(GPUCompatibility, RecogniseValidCompatibilityListFlatbuffer) {
EXPECT_TRUE(tflite::acceleration::GPUCompatibilityList::IsValidFlatbuffer(
g_tflite_acceleration_devicedb_sample_binary,
g_tflite_acceleration_devicedb_sample_binary_len));
}
TEST(GPUCompatibility, RecogniseInvalidCompatibilityListFlatbuffer) {
unsigned char invalid_buffer[100];
std::fill(invalid_buffer, invalid_buffer + 100, ' ');
EXPECT_FALSE(tflite::acceleration::GPUCompatibilityList::IsValidFlatbuffer(
invalid_buffer, 100));
}
TEST(GPUCompatibility, CreationWithInvalidCompatibilityListFlatbuffer) {
unsigned char invalid_buffer[10];
std::fill(invalid_buffer, invalid_buffer + 10, ' ');
std::unique_ptr<tflite::acceleration::GPUCompatibilityList> list =
tflite::acceleration::GPUCompatibilityList::Create(invalid_buffer, 10);
EXPECT_EQ(list, nullptr);
}
TEST(GPUCompatibility, CreationWithNullCompatibilityListFlatbuffer) {
std::unique_ptr<tflite::acceleration::GPUCompatibilityList> list =
tflite::acceleration::GPUCompatibilityList::Create(nullptr, 0);
EXPECT_EQ(list, nullptr);
}
TEST(GPUCompatibility, ConvertCompatibilityStatusToStringCorrectly) {
EXPECT_EQ(
tflite::acceleration::GPUCompatibilityList::CompatibilityStatusToString(
tflite::acceleration::gpu::CompatibilityStatus::kSupported),
tflite::acceleration::gpu::kStatusSupported);
EXPECT_EQ(
tflite::acceleration::GPUCompatibilityList::CompatibilityStatusToString(
tflite::acceleration::gpu::CompatibilityStatus::kUnsupported),
tflite::acceleration::gpu::kStatusUnsupported);
EXPECT_EQ(
tflite::acceleration::GPUCompatibilityList::CompatibilityStatusToString(
tflite::acceleration::gpu::CompatibilityStatus::kUnknown),
tflite::acceleration::gpu::kStatusUnknown);
}
TEST(GPUCompatibility, ConvertStringToCompatibilityStatusCorrectly) {
EXPECT_EQ(
tflite::acceleration::GPUCompatibilityList::StringToCompatibilityStatus(
tflite::acceleration::gpu::kStatusSupported),
tflite::acceleration::gpu::CompatibilityStatus::kSupported);
EXPECT_EQ(
tflite::acceleration::GPUCompatibilityList::StringToCompatibilityStatus(
tflite::acceleration::gpu::kStatusUnsupported),
tflite::acceleration::gpu::CompatibilityStatus::kUnsupported);
EXPECT_EQ(
tflite::acceleration::GPUCompatibilityList::StringToCompatibilityStatus(
tflite::acceleration::gpu::kStatusUnknown),
tflite::acceleration::gpu::CompatibilityStatus::kUnknown);
}
} // namespace
@@ -0,0 +1,93 @@
/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
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.
==============================================================================*/
// Simple program to convert from JSON to binary flatbuffers for given schema.
//
// Used for creating the binary version of a compatibility list.
//
// The flatc command line is not available in all build environments.
#include <cstdint>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include "flatbuffers/flatbuffers.h" // from @flatbuffers
#include "flatbuffers/idl.h" // from @flatbuffers
#include "flatbuffers/reflection.h" // from @flatbuffers
#include "flatbuffers/reflection_generated.h" // from @flatbuffers
#include "flatbuffers/util.h" // from @flatbuffers
#include "tensorflow/lite/tools/command_line_flags.h"
int main(int argc, char** argv) {
std::string json_path, fbs_path, fb_path;
std::vector<tflite::Flag> flags = {
tflite::Flag::CreateFlag("json_input", &json_path,
"Path to input json file."),
tflite::Flag::CreateFlag("fbs", &fbs_path,
"Path to flatbuffer schema to use."),
tflite::Flag::CreateFlag("fb_output", &fb_path,
"Path to a output binary flatbuffer."),
};
const bool parse_result =
tflite::Flags::Parse(&argc, const_cast<const char**>(argv), flags);
if (!parse_result || json_path.empty() || fbs_path.empty() ||
fb_path.empty()) {
std::cerr << tflite::Flags::Usage(argv[0], flags);
return 1;
}
std::string json_contents;
if (!flatbuffers::LoadFile(json_path.c_str(), false, &json_contents)) {
std::cerr << "Unable to load file " << json_path << std::endl;
return 2;
}
std::string fbs_contents;
if (!flatbuffers::LoadFile(fbs_path.c_str(), false, &fbs_contents)) {
std::cerr << "Unable to load file " << fbs_path << std::endl;
return 3;
}
const char* include_directories[] = {nullptr};
flatbuffers::Parser schema_parser;
if (!schema_parser.Parse(fbs_contents.c_str(), include_directories)) {
std::cerr << "Unable to parse schema " << schema_parser.error_ << std::endl;
return 4;
}
schema_parser.Serialize();
auto schema =
reflection::GetSchema(schema_parser.builder_.GetBufferPointer());
auto root_table = schema->root_table();
flatbuffers::Parser parser;
parser.Deserialize(schema_parser.builder_.GetBufferPointer(),
schema_parser.builder_.GetSize());
if (!parser.Parse(json_contents.c_str(), include_directories,
json_path.c_str())) {
std::cerr << "Unable to parse json " << parser.error_ << std::endl;
return 5;
}
// Use CopyTable() to deduplicate the strings.
const uint8_t* buffer = parser.builder_.GetBufferPointer();
flatbuffers::FlatBufferBuilder fbb;
auto root_offset = flatbuffers::CopyTable(
fbb, *schema, *root_table, *flatbuffers::GetAnyRoot(buffer), true);
fbb.Finish(root_offset);
std::string binary(reinterpret_cast<const char*>(fbb.GetBufferPointer()),
fbb.GetSize());
std::ofstream output;
output.open(fb_path);
output << binary;
output.close();
return 0;
}
@@ -0,0 +1,106 @@
/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
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 TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_COMPATIBILITY_VARIABLES_H_
#define TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_COMPATIBILITY_VARIABLES_H_
// This file lists generally useful compatibility properties.
// Properties starting with "tflite." are reserved.
// Users of the compatibility library can use arbitrary other property names.
namespace tflite {
namespace acceleration {
// System properties, not specific to any single delegate.
// Android properties.
//
// Android SDK version number. Android system property ro.build.version.sdk.
// E.g., "28".
inline constexpr char kAndroidSdkVersion[] = "tflite.android_sdk_version";
// SoC model. Looked up from database or possibly returned from Android system
// property ro.board.platform, normalized. E.g., "sdm450".
inline constexpr char kSoCModel[] = "tflite.soc_model";
// SoC vendor. Looked up from database. E.g., "qualcomm".
inline constexpr char kSoCVendor[] = "tflite.soc_vendor";
// Device manufacturer. Android API android.os.Build.MANUFACTURER, normalized.
// E.g., "google".
inline constexpr char kManufacturer[] = "tflite.manufacturer";
// Device model. Android API android.os.Build.MODEL, normalized.
// E.g., "pixel_2".
inline constexpr char kDeviceModel[] = "tflite.device_model";
// Device name. Android API android.os.Build.DEVICE, normalized.
// E.g., "walleye".
inline constexpr char kDeviceName[] = "tflite.device_name";
// GPU-related properties.
//
// OpenGL ES version. E.g., 3.2.
inline constexpr char kOpenGLESVersion[] = "tflite.opengl_es_version";
// GPU model, result of querying GL_RENDERER, normalized. E.g.,
// "adreno_(tm)_505".
inline constexpr char kGPUModel[] = "tflite.gpu_model";
// GPU vendor, normalized. E.g., "adreno_(tm)_505".
inline constexpr char kGPUVendor[] = "tflite.gpu_vendor";
// OpenGL driver version, result of querying GL_VERSION. E.g.,
// "opengl_es_3.2_v@328.0_(git@6fb5a5b,_ife855c4895)_(date:08/21/18)"
inline constexpr char kOpenGLDriverVersion[] = "tflite.opengl_driver_version";
// Allowlist use case. This property is used to allow joining multiple lists
// into a single decision tree.
inline constexpr char kUseCase[] = "tflite.use_case";
// NNAPI-related properties.
//
// NNAPI accelerator name, returned by ANeuralNetworksDevice_getName. E.g.,
// "qti-dsp".
inline constexpr char kNNAPIAccelerator[] = "tflite.nnapi_accelerator";
// NNAPI accelerator feature level, returned by
// ANeuralNetworksDevice_getFeatureLevel. E.g., 29. Actual variables are named
// "tflite.nnapi_feature_level.<accelerator name>", e.g.,
// "tflite.nnapi_feature_level.qti-dsp".
inline constexpr char kNNAPIFeatureLevelPrefix[] = "tflite.nnapi_feature_level";
namespace gpu {
// GPU-delegate derived properties.
// Whether the GPU delegate works in general.
// Possible values are ("", "SUPPORTED", "UNSUPPORTED"). An empty value for
// this field means that the device is unsupported.
inline constexpr char kStatus[] = "tflite.gpu.status";
inline constexpr char kStatusSupported[] = "SUPPORTED";
inline constexpr char kStatusUnknown[] = "UNKNOWN";
inline constexpr char kStatusUnsupported[] = "UNSUPPORTED";
enum class CompatibilityStatus {
kUnknown = 0,
kSupported,
kUnsupported,
};
} // namespace gpu
namespace metadata {
// Latency for model to run.
inline constexpr char kLatency[] = "tflite.latency";
// Frame time for one frame through model.
inline constexpr char kFrameTime[] = "tflite.frame_time";
} // namespace metadata
} // namespace acceleration
} // namespace tflite
#endif // TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_COMPATIBILITY_VARIABLES_H_