diff --git a/tensorflow/lite/BUILD b/tensorflow/lite/BUILD index fc2a1aa4302..a0b1ffff0c9 100644 --- a/tensorflow/lite/BUILD +++ b/tensorflow/lite/BUILD @@ -402,7 +402,9 @@ cc_library( "//tensorflow:android": ["-llog"], "//conditions:default": [], }), - visibility = ["//visibility:private"], + visibility = [ + "//tensorflow/lite:__subpackages__", + ], ) cc_test( diff --git a/tensorflow/lite/delegates/flex/BUILD b/tensorflow/lite/delegates/flex/BUILD index bca8e514fe4..185a59e9407 100644 --- a/tensorflow/lite/delegates/flex/BUILD +++ b/tensorflow/lite/delegates/flex/BUILD @@ -86,6 +86,7 @@ cc_library( "@com_google_absl//absl/strings:strings", "//tensorflow/lite/c:c_api_internal", "//tensorflow/lite:kernel_api", + "//tensorflow/lite:minimal_logging", "//tensorflow/lite:string_util", "//tensorflow/lite:util", ] + select({ diff --git a/tensorflow/lite/delegates/flex/delegate.cc b/tensorflow/lite/delegates/flex/delegate.cc index dcf5b795d82..9400ef697e0 100644 --- a/tensorflow/lite/delegates/flex/delegate.cc +++ b/tensorflow/lite/delegates/flex/delegate.cc @@ -22,6 +22,7 @@ limitations under the License. #include "tensorflow/lite/delegates/flex/buffer_map.h" #include "tensorflow/lite/delegates/flex/kernel.h" #include "tensorflow/lite/delegates/flex/util.h" +#include "tensorflow/lite/minimal_logging.h" #include "tensorflow/lite/string_util.h" #include "tensorflow/lite/util.h" @@ -133,6 +134,8 @@ AcquireFlexDelegate() { } std::unique_ptr FlexDelegate::Create() { + TFLITE_LOG_PROD_ONCE(TFLITE_LOG_INFO, + "Created TensorFlow Lite delegate for select TF ops."); return std::unique_ptr(new FlexDelegate()); } diff --git a/tensorflow/lite/delegates/gpu/BUILD b/tensorflow/lite/delegates/gpu/BUILD index 6ccb3e366b6..e43e9388091 100644 --- a/tensorflow/lite/delegates/gpu/BUILD +++ b/tensorflow/lite/delegates/gpu/BUILD @@ -27,6 +27,7 @@ cc_library( deps = [ "@com_google_absl//absl/types:span", "//tensorflow/lite:kernel_api", + "//tensorflow/lite:minimal_logging", "//tensorflow/lite/c:c_api_internal", "//tensorflow/lite/delegates/gpu/common:convert", "//tensorflow/lite/delegates/gpu/common:model", @@ -65,6 +66,7 @@ objc_library( sdk_frameworks = ["Metal"], deps = [ "//tensorflow/lite:kernel_api", + "//tensorflow/lite:minimal_logging", "//tensorflow/lite/c:c_api_internal", "//tensorflow/lite/delegates/gpu/common:convert", "//tensorflow/lite/delegates/gpu/common:model", diff --git a/tensorflow/lite/delegates/gpu/gl_delegate.cc b/tensorflow/lite/delegates/gpu/gl_delegate.cc index ad636c7acdd..d2accc9a549 100644 --- a/tensorflow/lite/delegates/gpu/gl_delegate.cc +++ b/tensorflow/lite/delegates/gpu/gl_delegate.cc @@ -43,6 +43,7 @@ limitations under the License. #include "tensorflow/lite/delegates/gpu/gl/gl_call.h" #include "tensorflow/lite/delegates/gpu/gl/kernels/registry.h" #include "tensorflow/lite/delegates/gpu/gl/workgroups/best_effort_calculator.h" +#include "tensorflow/lite/minimal_logging.h" #ifndef TFLITE_GPU_BINARY_RELEASE #include "flatbuffers/flatbuffers.h" // TF:flatbuffers @@ -430,6 +431,8 @@ TfLiteStatus DelegateCopyToBufferHandle(TfLiteContext* context, TfLiteDelegate* TfLiteGpuDelegateCreate( const TfLiteGpuDelegateOptions* options) { + TFLITE_LOG_PROD_ONCE(tflite::TFLITE_LOG_INFO, + "Created TensorFlow Lite delegate for GPU."); auto* gpu_delegate = new tflite::gpu::gl::Delegate(options); return gpu_delegate ? gpu_delegate->tflite_delegate() : nullptr; } diff --git a/tensorflow/lite/delegates/gpu/metal_delegate.mm b/tensorflow/lite/delegates/gpu/metal_delegate.mm index 8556f3f5f98..66bfb043e58 100644 --- a/tensorflow/lite/delegates/gpu/metal_delegate.mm +++ b/tensorflow/lite/delegates/gpu/metal_delegate.mm @@ -39,6 +39,7 @@ limitations under the License. #include "tensorflow/lite/delegates/gpu/metal/compiled_model.h" #include "tensorflow/lite/delegates/gpu/metal/inference_context.h" #include "tensorflow/lite/delegates/gpu/metal/runtime_options.h" +#include "tensorflow/lite/minimal_logging.h" namespace tflite { namespace gpu { @@ -427,6 +428,8 @@ TfLiteStatus DelegatePrepare(TfLiteContext* context, TfLiteDelegate* delegate) { } // namespace tflite TfLiteDelegate* NewGpuDelegate(const GpuDelegateOptions* options) { + TFLITE_LOG_PROD_ONCE(tflite::TFLITE_LOG_INFO, + "Created TensorFlow Lite delegate for Metal."); auto* metal_delegate = new ::tflite::gpu::metal::Delegate(options); return metal_delegate ? metal_delegate->tflite_delegate() : nullptr; } diff --git a/tensorflow/lite/interpreter.cc b/tensorflow/lite/interpreter.cc index a6c1d88be28..f6f797278d2 100644 --- a/tensorflow/lite/interpreter.cc +++ b/tensorflow/lite/interpreter.cc @@ -19,7 +19,6 @@ limitations under the License. #include #include #include -#include // NOLINT(build/c++11): only using std::call_once, not mutex. #include "tensorflow/lite/c/c_api_internal.h" #include "tensorflow/lite/context_util.h" @@ -57,12 +56,8 @@ TfLiteQuantization GetQuantizationFromLegacy( Interpreter::Interpreter(ErrorReporter* error_reporter) : error_reporter_(error_reporter ? error_reporter : DefaultErrorReporter()) { - // Only log initialization once per-process to avoid log spam. - static std::once_flag init_log_once_flag; - std::call_once(init_log_once_flag, []() { - // TODO(b/128420794): Include the TFLite runtime version in the log. - TFLITE_LOG_PROD(TFLITE_LOG_INFO, "Initialized TensorFlow Lite runtime."); - }); + // TODO(b/128420794): Include the TFLite runtime version in the log. + TFLITE_LOG_PROD_ONCE(TFLITE_LOG_INFO, "Initialized TensorFlow Lite runtime."); // There's always at least 1 subgraph which is the primary subgraph. AddSubgraphs(1); diff --git a/tensorflow/lite/minimal_logging.cc b/tensorflow/lite/minimal_logging.cc index 8768ef6e312..b59c0f82028 100644 --- a/tensorflow/lite/minimal_logging.cc +++ b/tensorflow/lite/minimal_logging.cc @@ -23,7 +23,7 @@ namespace logging_internal { void MinimalLogger::Log(LogSeverity severity, const char* format, ...) { va_list args; va_start(args, format); - VLog(severity, format, args); + LogFormatted(severity, format, args); va_end(args); } diff --git a/tensorflow/lite/minimal_logging.h b/tensorflow/lite/minimal_logging.h index 7682ed8edc4..23ab269827d 100644 --- a/tensorflow/lite/minimal_logging.h +++ b/tensorflow/lite/minimal_logging.h @@ -36,7 +36,8 @@ class MinimalLogger { static void Log(LogSeverity severity, const char* format, ...); // Logging hook that takes a formatted va_list. - static void VLog(LogSeverity severity, const char* format, va_list args); + static void LogFormatted(LogSeverity severity, const char* format, + va_list args); private: static const char* GetSeverityName(LogSeverity severity); @@ -53,4 +54,26 @@ class MinimalLogger { #define TFLITE_LOG_PROD(severity, format, ...) \ tflite::logging_internal::MinimalLogger::Log(severity, format, ##__VA_ARGS__); +// Convenience macro for logging a statement *once* for a given process lifetime +// in production builds. +#define TFLITE_LOG_PROD_ONCE(severity, format, ...) \ + do { \ + static const bool s_logged = [&] { \ + TFLITE_LOG_PROD(severity, format, ##__VA_ARGS__) \ + return true; \ + }(); \ + (void)s_logged; \ + } while (false); + +#ifndef NDEBUG +// In debug builds, always log. +#define TFLITE_LOG TFLITE_LOG_PROD +#else +// In prod builds, never log, but ensure the code is well-formed and compiles. +#define TFLITE_LOG(severity, format, ...) \ + while (false) { \ + TFLITE_LOG_PROD(severity, format, ##__VA_ARGS__); \ + } +#endif + #endif // TENSORFLOW_LITE_MINIMAL_LOGGING_H_ diff --git a/tensorflow/lite/minimal_logging_android.cc b/tensorflow/lite/minimal_logging_android.cc index f87e6fa18e1..92a6980ce5d 100644 --- a/tensorflow/lite/minimal_logging_android.cc +++ b/tensorflow/lite/minimal_logging_android.cc @@ -37,8 +37,8 @@ int GetPlatformSeverity(LogSeverity severity) { } // namespace -void MinimalLogger::VLog(LogSeverity severity, const char* format, - va_list args) { +void MinimalLogger::LogFormatted(LogSeverity severity, const char* format, + va_list args) { // First log to Android's explicit log(cat) API. va_list args_for_android_log; va_copy(args_for_android_log, args); diff --git a/tensorflow/lite/minimal_logging_default.cc b/tensorflow/lite/minimal_logging_default.cc index 9fa13e47e63..74a9642bb3c 100644 --- a/tensorflow/lite/minimal_logging_default.cc +++ b/tensorflow/lite/minimal_logging_default.cc @@ -20,8 +20,8 @@ limitations under the License. namespace tflite { namespace logging_internal { -void MinimalLogger::VLog(LogSeverity severity, const char* format, - va_list args) { +void MinimalLogger::LogFormatted(LogSeverity severity, const char* format, + va_list args) { fprintf(stderr, "%s: ", GetSeverityName(severity)); vfprintf(stderr, format, args); fputc('\n', stderr); diff --git a/tensorflow/lite/minimal_logging_ios.cc b/tensorflow/lite/minimal_logging_ios.cc index a774682a5b4..ab1c7feff7f 100644 --- a/tensorflow/lite/minimal_logging_ios.cc +++ b/tensorflow/lite/minimal_logging_ios.cc @@ -37,8 +37,8 @@ int GetPlatformSeverity(LogSeverity severity) { } // namespace -void MinimalLogger::VLog(LogSeverity severity, const char* format, - va_list args) { +void MinimalLogger::LogFormatted(LogSeverity severity, const char* format, + va_list args) { // TODO(b/123704468): Use os_log when available. vsyslog(GetPlatformSeverity(severity), format, args); } diff --git a/tensorflow/lite/minimal_logging_test.cc b/tensorflow/lite/minimal_logging_test.cc index e59425a2b26..751233aea24 100644 --- a/tensorflow/lite/minimal_logging_test.cc +++ b/tensorflow/lite/minimal_logging_test.cc @@ -52,6 +52,27 @@ TEST(MinimalLogging, UnknownSeverity) { testing::internal::GetCapturedStderr()); } +TEST(MinimalLogging, Once) { + testing::internal::CaptureStderr(); + for (int i = 0; i < 10; ++i) { + TFLITE_LOG_PROD_ONCE(TFLITE_LOG_INFO, "Count: %d", i); + } + EXPECT_EQ("INFO: Count: 0\n", testing::internal::GetCapturedStderr()); +} + +TEST(MinimalLogging, Debug) { + testing::internal::CaptureStderr(); + TFLITE_LOG(TFLITE_LOG_INFO, "Foo"); + TFLITE_LOG(TFLITE_LOG_WARNING, "Bar"); + TFLITE_LOG(TFLITE_LOG_ERROR, "Baz"); +#ifndef NDEBUG + EXPECT_EQ("INFO: Foo\nWARNING: Bar\nERROR: Baz\n", + testing::internal::GetCapturedStderr()); +#else + EXPECT_TRUE(testing::internal::GetCapturedStderr().empty()); +#endif +} + } // namespace tflite int main(int argc, char** argv) { diff --git a/tensorflow/lite/stderr_reporter.cc b/tensorflow/lite/stderr_reporter.cc index 366a1816ef2..2eecbbf7a93 100644 --- a/tensorflow/lite/stderr_reporter.cc +++ b/tensorflow/lite/stderr_reporter.cc @@ -19,7 +19,7 @@ limitations under the License. namespace tflite { int StderrReporter::Report(const char* format, va_list args) { - logging_internal::MinimalLogger::VLog(TFLITE_LOG_ERROR, format, args); + logging_internal::MinimalLogger::LogFormatted(TFLITE_LOG_ERROR, format, args); return 0; }