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:
parent
3c98419e46
commit
d6aa41f1e2
@ -402,7 +402,9 @@ cc_library(
|
||||
"//tensorflow:android": ["-llog"],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
visibility = ["//visibility:private"],
|
||||
visibility = [
|
||||
"//tensorflow/lite:__subpackages__",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
|
@ -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({
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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_
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user