Add console log hooks for TFLite delegates

Note that the log calls are throttled to once per process
lifetime for the GPU/Metal/Flex delegates.

PiperOrigin-RevId: 241413553
This commit is contained in:
Jared Duke 2019-04-01 15:34:29 -07:00 committed by TensorFlower Gardener
parent 3c98419e46
commit d6aa41f1e2
14 changed files with 70 additions and 17 deletions

View File

@ -402,7 +402,9 @@ cc_library(
"//tensorflow:android": ["-llog"],
"//conditions:default": [],
}),
visibility = ["//visibility:private"],
visibility = [
"//tensorflow/lite:__subpackages__",
],
)
cc_test(

View File

@ -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({

View File

@ -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> FlexDelegate::Create() {
TFLITE_LOG_PROD_ONCE(TFLITE_LOG_INFO,
"Created TensorFlow Lite delegate for select TF ops.");
return std::unique_ptr<FlexDelegate>(new FlexDelegate());
}

View File

@ -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",

View File

@ -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;
}

View File

@ -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;
}

View File

@ -19,7 +19,6 @@ limitations under the License.
#include <cstdarg>
#include <cstdint>
#include <cstring>
#include <mutex> // 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);

View File

@ -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);
}

View File

@ -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_

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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) {

View File

@ -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;
}