diff --git a/tensorflow/lite/interpreter.cc b/tensorflow/lite/interpreter.cc index 6ef6c2ce194..a0c4fc8c567 100644 --- a/tensorflow/lite/interpreter.cc +++ b/tensorflow/lite/interpreter.cc @@ -29,6 +29,20 @@ limitations under the License. #include "tensorflow/lite/schema/schema_generated.h" #include "tensorflow/lite/util.h" +// TODO(b/139446230): Move to portable platform header. +#if defined(__ANDROID__) +#define TFLITE_IS_MOBILE_PLATFORM +#endif // defined(__ANDROID__) + +#if defined(__APPLE__) +#include "TargetConditionals.h" +#if TARGET_IPHONE_SIMULATOR +#define TFLITE_IS_MOBILE_PLATFORM +#elif TARGET_OS_IPHONE +#define TFLITE_IS_MOBILE_PLATFORM +#endif +#endif // defined(__APPLE__) + // TODO(b/132087118): move static_assert to c_api_internal when compiled with // C++. static_assert(sizeof(TfLiteFloat16) == sizeof(uint16_t), @@ -60,7 +74,13 @@ Interpreter::Interpreter(ErrorReporter* error_reporter) : error_reporter_(error_reporter ? error_reporter : DefaultErrorReporter()) { // TODO(b/128420794): Include the TFLite runtime version in the log. + // Prod logging is useful for mobile platforms where scraping console logs is + // critical for debugging. +#if defined(TFLITE_IS_MOBILE_PLATFORM) TFLITE_LOG_PROD_ONCE(TFLITE_LOG_INFO, "Initialized TensorFlow Lite runtime."); +#else + TFLITE_LOG_ONCE(TFLITE_LOG_INFO, "Initialized TensorFlow Lite runtime."); +#endif // There's always at least 1 subgraph which is the primary subgraph. AddSubgraphs(1); diff --git a/tensorflow/lite/interpreter_test.cc b/tensorflow/lite/interpreter_test.cc index f8ab53fb807..f6d8bae4eff 100644 --- a/tensorflow/lite/interpreter_test.cc +++ b/tensorflow/lite/interpreter_test.cc @@ -65,8 +65,14 @@ TEST(BasicInterpreter, ZeroInterpreter) { testing::internal::CaptureStderr(); Interpreter interpreter; + +#ifndef NDEBUG + const char* kExpectedLog = "INFO: Initialized TensorFlow Lite runtime"; +#else + const char* kExpectedLog = ""; +#endif EXPECT_THAT(testing::internal::GetCapturedStderr(), - testing::HasSubstr("INFO: Initialized TensorFlow Lite runtime")); + testing::HasSubstr(kExpectedLog)); interpreter.SetInputs({}); interpreter.SetOutputs({}); diff --git a/tensorflow/lite/minimal_logging.h b/tensorflow/lite/minimal_logging.h index 23ab269827d..5f42bc7eb81 100644 --- a/tensorflow/lite/minimal_logging.h +++ b/tensorflow/lite/minimal_logging.h @@ -68,12 +68,14 @@ class MinimalLogger { #ifndef NDEBUG // In debug builds, always log. #define TFLITE_LOG TFLITE_LOG_PROD +#define TFLITE_LOG_ONCE TFLITE_LOG_PROD_ONCE #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__); \ } +#define TFLITE_LOG_ONCE TFLITE_LOG #endif #endif // TENSORFLOW_LITE_MINIMAL_LOGGING_H_ diff --git a/tensorflow/lite/minimal_logging_test.cc b/tensorflow/lite/minimal_logging_test.cc index 751233aea24..b5212452dab 100644 --- a/tensorflow/lite/minimal_logging_test.cc +++ b/tensorflow/lite/minimal_logging_test.cc @@ -73,6 +73,18 @@ TEST(MinimalLogging, Debug) { #endif } +TEST(MinimalLogging, DebugOnce) { + testing::internal::CaptureStderr(); + for (int i = 0; i < 10; ++i) { + TFLITE_LOG_ONCE(TFLITE_LOG_INFO, "Count: %d", i); + } +#ifndef NDEBUG + EXPECT_EQ("INFO: Count: 0\n", testing::internal::GetCapturedStderr()); +#else + EXPECT_TRUE(testing::internal::GetCapturedStderr().empty()); +#endif +} + } // namespace tflite int main(int argc, char** argv) {