diff --git a/tensorflow/lite/core/acceleration/configuration/c/BUILD b/tensorflow/lite/core/acceleration/configuration/c/BUILD index 2e0abf85bb12a56ada8b02e323928b5d9eb2eeca..929dd5aa64c500c39103c6c8c70093d113d89f82 100644 --- a/tensorflow/lite/core/acceleration/configuration/c/BUILD +++ b/tensorflow/lite/core/acceleration/configuration/c/BUILD @@ -16,19 +16,20 @@ # C API for delegate plugins. load("//tensorflow:tensorflow.default.bzl", "get_compatible_with_portable") +load( + "//tensorflow/core/platform:build_config_root.bzl", + "tf_gpu_tests_tags", +) load("//tensorflow/lite:build_def.bzl", "tflite_cc_library_with_c_headers_test", "tflite_copts", "tflite_copts_warnings") -load("//tensorflow/lite/delegates/gpu:build_defs.bzl", "gpu_delegate_linkopts") -load("//tensorflow/lite/core/c:special_rules.bzl", "experimental_acceleration_api_allowlist") load( "//tensorflow/lite/core/acceleration/configuration/c:special_rules.bzl", "delegate_plugin_visibility_allowlist", "gpu_plugin_visibility_allowlist", "xnnpack_plugin_visibility_allowlist", ) -load( - "//tensorflow/core/platform:build_config_root.bzl", - "tf_gpu_tests_tags", -) +load("//tensorflow/lite/core/c:special_rules.bzl", "experimental_acceleration_api_allowlist") +load("//tensorflow/lite/core/shims:build_defs.bzl", "build_test") +load("//tensorflow/lite/delegates/gpu:build_defs.bzl", "gpu_delegate_linkopts") package( # copybara:uncomment default_applicable_licenses = ["//tensorflow:license"], @@ -173,6 +174,36 @@ cc_test( ], ) +tflite_cc_library_with_c_headers_test( + name = "xnnpack_plugin_c_test_lib", + testonly = True, + srcs = ["xnnpack_plugin_c_test_lib.c"], + hdrs = ["xnnpack_plugin_c_test_lib.h"], + deps = [ + ":configuration_c_fbs", + ":xnnpack_plugin", + "//tensorflow/lite/core/c:common", + "//third_party/flatcc:runtime", + "@pthreadpool", + ], +) + +cc_test( + name = "xnnpack_plugin_c_test", + srcs = ["xnnpack_plugin_c_test.cc"], + deps = [ + ":configuration_c_fbs", + ":xnnpack_plugin", + ":xnnpack_plugin_c_test_lib", + "//tensorflow/lite/acceleration/configuration:configuration_fbs", + "//tensorflow/lite/core/c:common", + "//tensorflow/lite/delegates/xnnpack:xnnpack_delegate", + "//third_party/flatcc:runtime", + "@com_google_googletest//:gtest_main", + "@pthreadpool", + ], +) + tflite_cc_library_with_c_headers_test( name = "stable_delegate", hdrs = ["stable_delegate.h"], @@ -181,3 +212,44 @@ tflite_cc_library_with_c_headers_test( "//tensorflow/lite/core/acceleration/configuration/c:delegate_plugin", ], ) + +# This rule invokes the "flatcc" FlatBuffer C API compiler to generate the sources +# use by the ":configuration_c_fbs" C library rule below. +genrule( + name = "configuration_c_fbs_gen", + srcs = ["//tensorflow/lite/acceleration/configuration:configuration.fbs"], + outs = [ + "configuration_builder.h", + "configuration_reader.h", + ], + cmd = "$(location //third_party/flatcc:flatcc) -o$(RULEDIR) --builder --reader $(SRCS)", + tools = ["//third_party/flatcc"], + # Currently this only enables the API for _building_ configuration flatbuffer objects, + # not the APIs for reading them, verifying them, or converting them to/from JSON. + # [If you need to enable those, replace the two lines above with the following + # outs = ["configuration_builder.h", "configuration_reader.h", "configuration_verifier.h", + # "configuration_json_parser.h", "configuration_json_printer.h"], + # cmd = "$(location //third_party/flatcc:flatcc) -o$(RULEDIR) " + + # "--builder --reader --verifier --json $(SRCS)", + # and then in the rule below -- or preferably in a separate target -- + # add the additional header files in "hdrs" and fix the dependencies.] +) + +# This rule defines a C library containing the Flatbuffer-generated C API for constructing objects +# using the FlatBuffer schema generated from tensorflow/lite/acceleration/configuration/configuration.proto, +# which defines the 'TFLiteSettings' FlatBuffer table and related types. +tflite_cc_library_with_c_headers_test( + name = "configuration_c_fbs", + hdrs = [ + "configuration_builder.h", + "configuration_reader.h", + ], + deps = ["//third_party/flatcc:runtime"], +) + +build_test( + name = "configuration_c_fbs_build_test", + targets = [ + ":configuration_c_fbs", + ], +) diff --git a/tensorflow/lite/core/acceleration/configuration/c/xnnpack_plugin_c_test.cc b/tensorflow/lite/core/acceleration/configuration/c/xnnpack_plugin_c_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..8037cffb8cd2bbce0fb45858cdc00844d7251f94 --- /dev/null +++ b/tensorflow/lite/core/acceleration/configuration/c/xnnpack_plugin_c_test.cc @@ -0,0 +1,119 @@ +/* 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. +==============================================================================*/ + +// Some simple unit tests of the C API Delegate Plugin for the +// XNNPACK Delegate, implemented using the FlatBuffers C API +// to construct the TFLiteSettings FlatBuffer. + +#include +#include "pthreadpool.h" // from @pthreadpool +#include "tensorflow/lite/acceleration/configuration/configuration_generated.h" +#include "tensorflow/lite/core/acceleration/configuration/c/configuration_reader.h" +#include "tensorflow/lite/core/acceleration/configuration/c/xnnpack_plugin.h" +#include "tensorflow/lite/core/acceleration/configuration/c/xnnpack_plugin_c_test_lib.h" +#include "tensorflow/lite/core/c/common.h" +#include "tensorflow/lite/delegates/xnnpack/xnnpack_delegate.h" + +namespace tflite { + +class XnnpackTest : public testing::Test { + public: + static constexpr int kNumThreadsForTest = 7; + void SetUp() override { + // Construct a FlatBuffer that contains + // TFLiteSettings { XNNPackSettings { num_threads: kNumThreadsForTest } }. + settings_storage_ = + SettingsStorageCreateWithXnnpackThreads(kNumThreadsForTest); + settings_ = SettingsStorageGetSettings(settings_storage_); + } + void TearDown() override { + SettingsStorageDestroy(settings_storage_); + settings_ = nullptr; + } + ~XnnpackTest() override = default; + + protected: + SettingsStorage *settings_storage_; + const void + *settings_; // settings_ points into storage owned by settings_storage_. +}; + +constexpr int XnnpackTest::kNumThreadsForTest; + +TEST_F(XnnpackTest, CanCreateAndDestroyDelegate) { + TfLiteDelegate *delegate = + TfLiteXnnpackDelegatePluginCApi()->create(settings_); + EXPECT_NE(delegate, nullptr); + TfLiteXnnpackDelegatePluginCApi()->destroy(delegate); +} + +TEST_F(XnnpackTest, CanGetDelegateErrno) { + TfLiteDelegate *delegate = + TfLiteXnnpackDelegatePluginCApi()->create(settings_); + int error_number = + TfLiteXnnpackDelegatePluginCApi()->get_delegate_errno(delegate); + EXPECT_EQ(error_number, 0); + TfLiteXnnpackDelegatePluginCApi()->destroy(delegate); +} + +TEST_F(XnnpackTest, SetsCorrectThreadCount) { + TfLiteDelegate *delegate = + TfLiteXnnpackDelegatePluginCApi()->create(settings_); + pthreadpool_t threadpool = + static_cast(TfLiteXNNPackDelegateGetThreadPool(delegate)); + int thread_count = pthreadpool_get_threads_count(threadpool); + EXPECT_EQ(thread_count, kNumThreadsForTest); + TfLiteXnnpackDelegatePluginCApi()->destroy(delegate); +} + +TEST_F(XnnpackTest, UsesDefaultFlagsByDefault) { + TfLiteDelegate *delegate = + TfLiteXnnpackDelegatePluginCApi()->create(settings_); + int flags = TfLiteXNNPackDelegateGetFlags(delegate); + EXPECT_EQ(flags, TfLiteXNNPackDelegateOptionsDefault().flags); + TfLiteXnnpackDelegatePluginCApi()->destroy(delegate); +} + +TEST_F(XnnpackTest, UsesSpecifiedFlagsWhenNonzero) { + SettingsStorageDestroy(settings_storage_); + settings_storage_ = SettingsStorageCreateWithXnnpackFlags( + tflite_XNNPackFlags_TFLITE_XNNPACK_DELEGATE_FLAG_QU8); + settings_ = SettingsStorageGetSettings(settings_storage_); + + TfLiteDelegate *delegate = + TfLiteXnnpackDelegatePluginCApi()->create(settings_); + int flags = TfLiteXNNPackDelegateGetFlags(delegate); + EXPECT_EQ(flags, tflite::XNNPackFlags_TFLITE_XNNPACK_DELEGATE_FLAG_QU8); + TfLiteXnnpackDelegatePluginCApi()->destroy(delegate); +} + +// Settings flags to XNNPackFlags_TFLITE_XNNPACK_DELEGATE_NO_FLAGS (zero) +// causes flags to be set to their default values, not zero. +// This is potentially confusing behaviour, but we can't distinguish +// the case when flags isn't set from the case when flags is set to zero. +TEST_F(XnnpackTest, UsesDefaultFlagsWhenZero) { + SettingsStorageDestroy(settings_storage_); + settings_storage_ = SettingsStorageCreateWithXnnpackFlags( + tflite_XNNPackFlags_TFLITE_XNNPACK_DELEGATE_NO_FLAGS); + settings_ = SettingsStorageGetSettings(settings_storage_); + + TfLiteDelegate *delegate = + TfLiteXnnpackDelegatePluginCApi()->create(settings_); + int flags = TfLiteXNNPackDelegateGetFlags(delegate); + EXPECT_EQ(flags, TfLiteXNNPackDelegateOptionsDefault().flags); + TfLiteXnnpackDelegatePluginCApi()->destroy(delegate); +} + +} // namespace tflite diff --git a/tensorflow/lite/core/acceleration/configuration/c/xnnpack_plugin_c_test_lib.c b/tensorflow/lite/core/acceleration/configuration/c/xnnpack_plugin_c_test_lib.c new file mode 100644 index 0000000000000000000000000000000000000000..a5f2c26f92b550a83fd4b0274a16e52805008090 --- /dev/null +++ b/tensorflow/lite/core/acceleration/configuration/c/xnnpack_plugin_c_test_lib.c @@ -0,0 +1,101 @@ +/* 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. +==============================================================================*/ + +// Some tests of the XNNPack Plugin using the FlatBuffers C API. +// This source file is C, not C++, to ensure that we're not accidentally +// depending on the FlatBuffers C++ API here. + +#include "tensorflow/lite/core/acceleration/configuration/c/xnnpack_plugin_c_test_lib.h" + +#include +#include + +#include "third_party/flatcc/include/flatcc/flatcc_builder.h" +#include "tensorflow/lite/core/acceleration/configuration/c/configuration_builder.h" +#include "tensorflow/lite/core/acceleration/configuration/c/configuration_reader.h" + +struct SettingsStorage { + // The builder object that allocates the storage. + flatcc_builder_t builder; + + // The raw buffer. + void* buffer; + size_t size; + + // The parsed TFLiteSettings object. + const struct tflite_TFLiteSettings_table* tflite_settings; +}; +typedef struct SettingsStorage SettingsStorage; + +SettingsStorage* SettingsStorageCreateWithXnnpackThreads(int num_threads) { + struct SettingsStorage* storage = + (struct SettingsStorage*) malloc(sizeof(SettingsStorage)); + + flatcc_builder_t* builder = &storage->builder; + flatcc_builder_init(builder); + + /* Construct a buffer specific to the schema. */ + tflite_TFLiteSettings_start_as_root(builder); + tflite_TFLiteSettings_xnnpack_settings_start(builder); + tflite_XNNPackSettings_num_threads_add(builder, num_threads); + tflite_TFLiteSettings_xnnpack_settings_end(builder); + tflite_TFLiteSettings_end_as_root(builder); + + /* Retrieve buffer - see also `flatcc_builder_get_direct_buffer`. */ + storage->buffer = flatcc_builder_finalize_buffer(builder, &storage->size); + + /* 'Parse' the buffer. (This is actually just an offset lookup.) */ + storage->tflite_settings = tflite_TFLiteSettings_as_root(storage->buffer); + + return storage; +} + +SettingsStorage* SettingsStorageCreateWithXnnpackFlags( + tflite_XNNPackFlags_enum_t flags) { + struct SettingsStorage* storage = + (struct SettingsStorage*) malloc(sizeof(SettingsStorage)); + + flatcc_builder_t* builder = &storage->builder; + flatcc_builder_init(builder); + + /* Construct a buffer specific to the schema. */ + tflite_TFLiteSettings_start_as_root(builder); + tflite_TFLiteSettings_xnnpack_settings_start(builder); + tflite_XNNPackSettings_flags_add(builder, flags); + tflite_TFLiteSettings_xnnpack_settings_end(builder); + tflite_TFLiteSettings_end_as_root(builder); + + /* Retrieve buffer - see also `flatcc_builder_get_direct_buffer`. */ + storage->buffer = flatcc_builder_finalize_buffer(builder, &storage->size); + + /* 'Parse' the buffer. (This is actually just an offset lookup.) */ + storage->tflite_settings = tflite_TFLiteSettings_as_root(storage->buffer); + + return storage; +} + +tflite_TFLiteSettings_table_t SettingsStorageGetSettings( + const SettingsStorage* storage) { + return storage->tflite_settings; +} + +void SettingsStorageDestroy(SettingsStorage* storage) { + free(storage->buffer); + flatcc_builder_clear(&storage->builder); + storage->tflite_settings = NULL; + storage->buffer = NULL; + storage->size = 0; + free(storage); +} diff --git a/tensorflow/lite/core/acceleration/configuration/c/xnnpack_plugin_c_test_lib.h b/tensorflow/lite/core/acceleration/configuration/c/xnnpack_plugin_c_test_lib.h new file mode 100644 index 0000000000000000000000000000000000000000..f07831e10eb71e28a0d83958773d7c99138ace17 --- /dev/null +++ b/tensorflow/lite/core/acceleration/configuration/c/xnnpack_plugin_c_test_lib.h @@ -0,0 +1,64 @@ +/* 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. +==============================================================================*/ + +// Some library routines for constructing TFLiteSettings FlatBuffers, +// implemented using the FlatBuffers C API. + +#ifndef TENSORFLOW_LITE_CORE_ACCELERATION_CONFIGURATION_C_XNNPACK_PLUGIN_C_TEST_LIB_H_ +#define TENSORFLOW_LITE_CORE_ACCELERATION_CONFIGURATION_C_XNNPACK_PLUGIN_C_TEST_LIB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "tensorflow/lite/core/acceleration/configuration/c/configuration_reader.h" + +// Opaque type for building a TfLiteSettings flatbuffer object. +typedef struct SettingsStorage SettingsStorage; + +// Constructs a TFLiteSettings FlatBuffer with the following contents: +// +// tflite_settings { +// xnnpack_settings { +// num_threads: +// } +// } +struct SettingsStorage* SettingsStorageCreateWithXnnpackThreads( + int num_threads); + +// Constructs a TFLiteSettings FlatBuffer with the following contents: +// +// tflite_settings { +// xnnpack_settings { +// flags: +// } +// } +struct SettingsStorage* SettingsStorageCreateWithXnnpackFlags( + tflite_XNNPackFlags_enum_t flags); + +// Gets the parsed TFLiteSettings FlatBuffer object from the SettingsStorage. +const struct tflite_TFLiteSettings_table* SettingsStorageGetSettings( + const SettingsStorage* storage); + +// Deallocates the settings storage allocated by +// SettingsStorageCreateWithXnnpackThreads or +// SettingsStorageCreateWithXnnpackFlags. +void SettingsStorageDestroy(SettingsStorage* storage); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // TENSORFLOW_LITE_CORE_ACCELERATION_CONFIGURATION_C_XNNPACK_PLUGIN_C_TEST_LIB_H_