From ef0a7b025a9d78dee0b81d7d27053f3aff097fb1 Mon Sep 17 00:00:00 2001 From: David Davis Date: Thu, 6 Jul 2023 13:21:19 -0700 Subject: [PATCH] DebugLog changes (#2073) @tensorflow/micro Change DebugLog to allow stdio style formatted output using either or a third party printf library. Remove micro_string code. bug=fixes #2083 --- tensorflow/lite/kernels/op_macros.h | 7 +- tensorflow/lite/micro/BUILD | 23 -- tensorflow/lite/micro/arc_emsdp/debug_log.cc | 26 +- tensorflow/lite/micro/bluepill/debug_log.cc | 24 +- tensorflow/lite/micro/chre/debug_log.cc | 18 +- .../lite/micro/cortex_m_generic/debug_log.cc | 26 +- tensorflow/lite/micro/debug_log.cc | 32 +- tensorflow/lite/micro/debug_log.h | 13 +- tensorflow/lite/micro/memory_planner/BUILD | 1 - .../memory_planner/greedy_memory_planner.cc | 3 +- tensorflow/lite/micro/micro_context.cc | 4 +- tensorflow/lite/micro/micro_log.cc | 34 +- tensorflow/lite/micro/micro_log.h | 14 +- tensorflow/lite/micro/micro_string.cc | 317 ------------------ tensorflow/lite/micro/micro_string.h | 33 -- tensorflow/lite/micro/micro_string_test.cc | 161 --------- .../tflite_bridge/micro_error_reporter.cc | 4 +- tensorflow/lite/micro/tools/make/Makefile | 2 +- .../tools/make/ext_libs/eyalroz_printf.inc | 28 ++ .../make/ext_libs/eyalroz_printf_download.sh | 63 ++++ .../tools/make/targets/arc_emsdp_makefile.inc | 6 +- .../tools/make/targets/bluepill_makefile.inc | 17 + .../tools/make/targets/chre_makefile.inc | 4 +- .../targets/cortex_m_generic_makefile.inc | 4 +- .../micro/tools/project_generation/Makefile | 9 +- 25 files changed, 260 insertions(+), 613 deletions(-) delete mode 100644 tensorflow/lite/micro/micro_string.cc delete mode 100644 tensorflow/lite/micro/micro_string.h delete mode 100644 tensorflow/lite/micro/micro_string_test.cc create mode 100644 tensorflow/lite/micro/tools/make/ext_libs/eyalroz_printf.inc create mode 100755 tensorflow/lite/micro/tools/make/ext_libs/eyalroz_printf_download.sh diff --git a/tensorflow/lite/kernels/op_macros.h b/tensorflow/lite/kernels/op_macros.h index 4255d253511..39e3119c971 100644 --- a/tensorflow/lite/kernels/op_macros.h +++ b/tensorflow/lite/kernels/op_macros.h @@ -1,4 +1,4 @@ -/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. +/* Copyright 2023 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. @@ -15,14 +15,13 @@ limitations under the License. #ifndef TENSORFLOW_LITE_KERNELS_OP_MACROS_H_ #define TENSORFLOW_LITE_KERNELS_OP_MACROS_H_ -#include "tensorflow/lite/micro/debug_log.h" - #if !defined(TF_LITE_MCU_DEBUG_LOG) #include #define TFLITE_ABORT abort() #else +#include "tensorflow/lite/micro/micro_log.h" inline void AbortImpl() { - DebugLog("HALTED\n"); + MicroPrintf("HALTED"); while (1) { } } diff --git a/tensorflow/lite/micro/BUILD b/tensorflow/lite/micro/BUILD index 72c23f34521..475c541ce61 100644 --- a/tensorflow/lite/micro/BUILD +++ b/tensorflow/lite/micro/BUILD @@ -269,7 +269,6 @@ cc_library( copts = micro_copts(), deps = [ ":debug_log", - ":micro_string", ], ) @@ -291,17 +290,6 @@ cc_library( ], ) -cc_library( - name = "micro_string", - srcs = [ - "micro_string.cc", - ], - hdrs = [ - "micro_string.h", - ], - copts = micro_copts(), -) - cc_library( name = "micro_time", srcs = [ @@ -549,17 +537,6 @@ cc_test( ], ) -cc_test( - name = "micro_string_test", - srcs = [ - "micro_string_test.cc", - ], - deps = [ - ":micro_string", - "//tensorflow/lite/micro/testing:micro_test", - ], -) - cc_test( name = "micro_time_test", srcs = [ diff --git a/tensorflow/lite/micro/arc_emsdp/debug_log.cc b/tensorflow/lite/micro/arc_emsdp/debug_log.cc index 1b4d641e5e9..55cf4208694 100644 --- a/tensorflow/lite/micro/arc_emsdp/debug_log.cc +++ b/tensorflow/lite/micro/arc_emsdp/debug_log.cc @@ -1,4 +1,4 @@ -/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. +/* Copyright 2023 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. @@ -19,6 +19,12 @@ limitations under the License. #include #include +#ifndef TF_LITE_STRIP_ERROR_STRINGS +#include "eyalroz_printf/src/printf/printf.h" +#endif + +namespace { + // Print to debug console by default. One can define next to extend destinations // set: EMSDP_LOG_TO_MEMORY // : fill .debug_log memory region (data section) with passed chars. @@ -89,9 +95,7 @@ void LogToMem(const char* s) { debug_log_mem[cursor] = '^'; } -extern "C" void DebugLog(const char* s) { -#ifndef TF_LITE_STRIP_ERROR_STRINGS - +void LogDebugString(const char* s) { #if defined EMSDP_LOG_TO_UART DbgUartSendStr(s); #endif @@ -106,6 +110,16 @@ extern "C" void DebugLog(const char* s) { #warning "EMSDP_LOG_TO_HOST is defined. Ensure hostlib is linked." fprintf(stderr, "%s", s); #endif - -#endif // TF_LITE_STRIP_ERROR_STRINGS } + +} // namespace + +extern "C" void DebugLog(const char* format, va_list args) { +#ifndef TF_LITE_STRIP_ERROR_STRINGS + constexpr int kMaxLogLen = 256; + char log_buffer[kMaxLogLen]; + + vsnprintf_(log_buffer, kMaxLogLen, format, args); + LogDebugString(log_buffer); +#endif +} \ No newline at end of file diff --git a/tensorflow/lite/micro/bluepill/debug_log.cc b/tensorflow/lite/micro/bluepill/debug_log.cc index 3fd2d52c8d8..6d0d53bb85f 100644 --- a/tensorflow/lite/micro/bluepill/debug_log.cc +++ b/tensorflow/lite/micro/bluepill/debug_log.cc @@ -1,4 +1,4 @@ -/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. +/* Copyright 2023 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. @@ -15,9 +15,16 @@ limitations under the License. #include "tensorflow/lite/micro/debug_log.h" +#ifndef TF_LITE_STRIP_ERROR_STRINGS +#include "eyalroz_printf/src/printf/printf.h" +#endif + +namespace { + +#ifndef TF_LITE_STRIP_ERROR_STRINGS // For Arm Cortex-M devices, calling SYS_WRITE0 will output the zero-terminated // string pointed to by R1 to any debug console that's attached to the system. -extern "C" void DebugLog(const char* s) { +void SysWriteDebugConsole(const char* s) { asm("mov r0, #0x04\n" // SYS_WRITE0 "mov r1, %[str]\n" "bkpt #0xAB\n" @@ -25,3 +32,16 @@ extern "C" void DebugLog(const char* s) { : [str] "r"(s) : "r0", "r1"); } +#endif // TF_LITE_STRIP_ERROR_STRINGS + +} // namespace + +extern "C" void DebugLog(const char* format, va_list args) { +#ifndef TF_LITE_STRIP_ERROR_STRINGS + constexpr int kMaxLogLen = 256; + char log_buffer[kMaxLogLen]; + + vsnprintf_(log_buffer, kMaxLogLen, format, args); + SysWriteDebugConsole(log_buffer); +#endif // TF_LITE_STRIP_ERROR_STRINGS +} diff --git a/tensorflow/lite/micro/chre/debug_log.cc b/tensorflow/lite/micro/chre/debug_log.cc index 23bb82eb7b6..b599ebe8a86 100644 --- a/tensorflow/lite/micro/chre/debug_log.cc +++ b/tensorflow/lite/micro/chre/debug_log.cc @@ -1,4 +1,4 @@ -/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. +/* Copyright 2023 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. @@ -17,6 +17,16 @@ limitations under the License. #include -extern "C" void DebugLog(const char* s) { - chreLog(CHRE_LOG_DEBUG, "[TFL_MICRO] %s", s); -} +#ifndef TF_LITE_STRIP_ERROR_STRINGS +#include "eyalroz_printf/src/printf/printf.h" +#endif + +extern "C" void DebugLog(const char* format, va_list args) { +#ifndef TF_LITE_STRIP_ERROR_STRINGS + constexpr int kMaxLogLen = 256; + char log_buffer[kMaxLogLen]; + + vsnprintf_(log_buffer, kMaxLogLen, format, args); + chreLog(CHRE_LOG_DEBUG, "[TFL_MICRO] %s", log_buffer); +#endif +} \ No newline at end of file diff --git a/tensorflow/lite/micro/cortex_m_generic/debug_log.cc b/tensorflow/lite/micro/cortex_m_generic/debug_log.cc index bc79d439170..2c237fe63da 100644 --- a/tensorflow/lite/micro/cortex_m_generic/debug_log.cc +++ b/tensorflow/lite/micro/cortex_m_generic/debug_log.cc @@ -1,4 +1,4 @@ -/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. +/* Copyright 2023 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. @@ -24,17 +24,33 @@ extern "C" { #include "tensorflow/lite/micro/cortex_m_generic/debug_log_callback.h" +#ifndef TF_LITE_STRIP_ERROR_STRINGS +#include "eyalroz_printf/src/printf/printf.h" +#endif + static DebugLogCallback debug_log_callback = nullptr; +namespace { + +void InvokeDebugLogCallback(const char* s) { + if (debug_log_callback != nullptr) { + debug_log_callback(s); + } +} + +} // namespace + void RegisterDebugLogCallback(void (*cb)(const char* s)) { debug_log_callback = cb; } -void DebugLog(const char* s) { +void DebugLog(const char* format, va_list args) { #ifndef TF_LITE_STRIP_ERROR_STRINGS - if (debug_log_callback != nullptr) { - debug_log_callback(s); - } + constexpr int kMaxLogLen = 256; + char log_buffer[kMaxLogLen]; + + vsnprintf_(log_buffer, kMaxLogLen, format, args); + InvokeDebugLogCallback(log_buffer); #endif } diff --git a/tensorflow/lite/micro/debug_log.cc b/tensorflow/lite/micro/debug_log.cc index 46ca253a6d5..a8ef36b3424 100644 --- a/tensorflow/lite/micro/debug_log.cc +++ b/tensorflow/lite/micro/debug_log.cc @@ -1,4 +1,4 @@ -/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. +/* Copyright 2023 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. @@ -18,21 +18,17 @@ limitations under the License. // the only function that's absolutely required to be available on a target // device, since it's used for communicating test results back to the host so // that we can verify the implementation is working correctly. -// It's designed to be as easy as possible to supply an implementation though. -// On platforms that have a POSIX stack or C library, it can be written as a -// single call to `fprintf(stderr, "%s", s)` to output a string to the error -// stream of the console, but if there's no OS or C library available, there's -// almost always an equivalent way to write out a string to some serial -// interface that can be used instead. For example on Arm M-series MCUs, calling -// the `bkpt #0xAB` assembler instruction will output the string in r1 to -// whatever debug serial connection is available. If you're running mbed, you -// can do the same by creating `Serial pc(USBTX, USBRX)` and then calling -// `pc.printf("%s", s)`. -// To add an equivalent function for your own platform, create your own -// implementation file, and place it in a subfolder with named after the OS -// you're targeting. For example, see the Cortex M bare metal version in -// tensorflow/lite/micro/bluepill/debug_log.cc or the mbed one on -// tensorflow/lite/micro/mbed/debug_log.cc. +// This function should support standard C/C++ stdio style formatting +// operations. It's designed to be as easy as possible to supply an +// implementation though. On platforms that have a POSIX stack or C library, it +// can be written as a single call to `vfprintf(stderr, format, args)` to output +// a string to the error stream of the console, but if there's no OS or C +// library available, there's almost always an equivalent way to write out a +// string to some serial interface that can be used instead. To add an +// equivalent function for your own platform, create your own implementation +// file, and place it in a subfolder with named after the OS you're targeting. +// For example, see the Cortex M bare metal version in the +// tensorflow/lite/micro/bluepill/debug_log.cc file. #include "tensorflow/lite/micro/debug_log.h" @@ -40,11 +36,11 @@ limitations under the License. #include #endif -extern "C" void DebugLog(const char* s) { +extern "C" void DebugLog(const char* format, va_list args) { #ifndef TF_LITE_STRIP_ERROR_STRINGS // Reusing TF_LITE_STRIP_ERROR_STRINGS to disable DebugLog completely to get // maximum reduction in binary size. This is because we have DebugLog calls // via TF_LITE_CHECK that are not stubbed out by TF_LITE_REPORT_ERROR. - fprintf(stderr, "%s", s); + vfprintf(stderr, format, args); #endif } diff --git a/tensorflow/lite/micro/debug_log.h b/tensorflow/lite/micro/debug_log.h index c2840d0f4b5..c0cf69956ef 100644 --- a/tensorflow/lite/micro/debug_log.h +++ b/tensorflow/lite/micro/debug_log.h @@ -1,4 +1,4 @@ -/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. +/* Copyright 2023 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. @@ -15,14 +15,21 @@ limitations under the License. #ifndef TENSORFLOW_LITE_MICRO_DEBUG_LOG_H_ #define TENSORFLOW_LITE_MICRO_DEBUG_LOG_H_ +#ifdef __cplusplus +#include +#else +#include +#endif // __cplusplus + #ifdef __cplusplus extern "C" { #endif // __cplusplus // This function should be implemented by each target platform, and provide a // way for strings to be output to some text stream. For more information, see -// tensorflow/lite/micro/debug_log.cc. -void DebugLog(const char* s); +// the tensorflow/lite/micro/debug_log.cc file. This function should support +// standard C/C++ stdio style formatting operations. +void DebugLog(const char* format, va_list args); #ifdef __cplusplus } // extern "C" diff --git a/tensorflow/lite/micro/memory_planner/BUILD b/tensorflow/lite/micro/memory_planner/BUILD index 0329e73feef..7111da4e1c2 100644 --- a/tensorflow/lite/micro/memory_planner/BUILD +++ b/tensorflow/lite/micro/memory_planner/BUILD @@ -52,7 +52,6 @@ cc_library( ":micro_memory_planner", "//tensorflow/lite/micro:micro_compatibility", "//tensorflow/lite/micro:micro_log", - "//tensorflow/lite/micro:micro_string", ], ) diff --git a/tensorflow/lite/micro/memory_planner/greedy_memory_planner.cc b/tensorflow/lite/micro/memory_planner/greedy_memory_planner.cc index 471a5b22935..a087b236cc9 100644 --- a/tensorflow/lite/micro/memory_planner/greedy_memory_planner.cc +++ b/tensorflow/lite/micro/memory_planner/greedy_memory_planner.cc @@ -1,4 +1,4 @@ -/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. +/* Copyright 2023 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. @@ -16,7 +16,6 @@ limitations under the License. #include "tensorflow/lite/micro/memory_planner/greedy_memory_planner.h" #include "tensorflow/lite/micro/micro_log.h" -#include "tensorflow/lite/micro/micro_string.h" namespace tflite { diff --git a/tensorflow/lite/micro/micro_context.cc b/tensorflow/lite/micro/micro_context.cc index b06252acb5f..352d2c0bad8 100644 --- a/tensorflow/lite/micro/micro_context.cc +++ b/tensorflow/lite/micro/micro_context.cc @@ -1,4 +1,4 @@ -/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. +/* Copyright 2023 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. @@ -142,7 +142,7 @@ void MicroContextReportOpError(struct TfLiteContext* context, const char* format, ...) { va_list args; va_start(args, format); - Log(format, args); + VMicroPrintf(format, args); va_end(args); } diff --git a/tensorflow/lite/micro/micro_log.cc b/tensorflow/lite/micro/micro_log.cc index 9c8ccaa3c25..45f7051cb7d 100644 --- a/tensorflow/lite/micro/micro_log.cc +++ b/tensorflow/lite/micro/micro_log.cc @@ -1,4 +1,4 @@ -/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. +/* Copyright 2023 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. @@ -17,31 +17,33 @@ limitations under the License. #include #include -#include #if !defined(TF_LITE_STRIP_ERROR_STRINGS) #include "tensorflow/lite/micro/debug_log.h" -#include "tensorflow/lite/micro/micro_string.h" #endif -void Log(const char* format, va_list args) { #if !defined(TF_LITE_STRIP_ERROR_STRINGS) - // Only pulling in the implementation of this function for builds where we - // expect to make use of it to be extra cautious about not increasing the code - // size. - static constexpr int kMaxLogLen = 256; - char log_buffer[kMaxLogLen]; - MicroVsnprintf(log_buffer, kMaxLogLen, format, args); - DebugLog(log_buffer); - DebugLog("\r\n"); -#endif +namespace { + +void VDebugLog(const char* format, ...) { + va_list args; + va_start(args, format); + DebugLog(format, args); + va_end(args); +} + +} // namespace + +void VMicroPrintf(const char* format, va_list args) { + DebugLog(format, args); + // TODO(b/290051015): remove "\r\n" + VDebugLog("\r\n"); } -#if !defined(TF_LITE_STRIP_ERROR_STRINGS) void MicroPrintf(const char* format, ...) { va_list args; va_start(args, format); - Log(format, args); + VMicroPrintf(format, args); va_end(args); } -#endif +#endif // !defined(TF_LITE_STRIP_ERROR_STRINGS) diff --git a/tensorflow/lite/micro/micro_log.h b/tensorflow/lite/micro/micro_log.h index d9cfbe8c08d..669e9e661b4 100644 --- a/tensorflow/lite/micro/micro_log.h +++ b/tensorflow/lite/micro/micro_log.h @@ -1,4 +1,4 @@ -/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. +/* Copyright 2023 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. @@ -15,20 +15,17 @@ limitations under the License. #ifndef TENSORFLOW_LITE_MICRO_MICRO_LOG_H_ #define TENSORFLOW_LITE_MICRO_MICRO_LOG_H_ -#include - -// This is a free function used to perform the actual logging. -// This function will be used by MicroPrintf and MicroErrorReporter::Report() -void Log(const char* format, va_list args); - #if !defined(TF_LITE_STRIP_ERROR_STRINGS) -// This function can be used independent of the MicroErrorReporter to get +#include +// These functions can be used independent of the MicroErrorReporter to get // printf-like functionalitys and are common to all target platforms. void MicroPrintf(const char* format, ...); +void VMicroPrintf(const char* format, va_list args); #else // We use a #define to ensure that the strings are completely stripped, to // prevent an unnecessary increase in the binary size. #define MicroPrintf(...) tflite::Unused(__VA_ARGS__) +#define VMicroPrintf(...) tflite::Unused(__VA_ARGS__) #endif namespace tflite { @@ -39,6 +36,7 @@ template void Unused(Args&&... args) { (void)(sizeof...(args)); } + } // namespace tflite #endif // TENSORFLOW_LITE_MICRO_MICRO_LOG_H_ diff --git a/tensorflow/lite/micro/micro_string.cc b/tensorflow/lite/micro/micro_string.cc deleted file mode 100644 index bb41a9e394c..00000000000 --- a/tensorflow/lite/micro/micro_string.cc +++ /dev/null @@ -1,317 +0,0 @@ -/* Copyright 2018 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. -==============================================================================*/ - -// Implements debug logging for numbers by converting them into strings and then -// calling the main DebugLog(char*) function. These are separated into a -// different file so that platforms can just implement the string output version -// of DebugLog() and then get the numerical variations without requiring any -// more code. - -#include "tensorflow/lite/micro/micro_string.h" - -#include -#include -#include - -namespace { - -// Int formats can need up to 10 bytes for the value plus a single byte for the -// sign. -constexpr int kMaxIntCharsNeeded = 10 + 1; -// Hex formats can need up to 8 bytes for the value plus two bytes for the "0x". -constexpr int kMaxHexCharsNeeded = 8 + 2; - -// Float formats can need up to 7 bytes for the fraction plus 3 bytes for "x2^" -// plus 3 bytes for the exponent and a single sign bit. -constexpr float kMaxFloatCharsNeeded = 7 + 3 + 3 + 1; - -// All input buffers to the number conversion functions must be this long. -const int kFastToBufferSize = 48; - -// Reverses a zero-terminated string in-place. -char* ReverseStringInPlace(char* start, char* end) { - char* p1 = start; - char* p2 = end - 1; - while (p1 < p2) { - char tmp = *p1; - *p1++ = *p2; - *p2-- = tmp; - } - return start; -} - -// Appends a string to a string, in-place. You need to pass in the maximum -// string length as the second argument. -char* StrCatStr(char* main, int main_max_length, const char* to_append) { - char* current = main; - while (*current != 0) { - ++current; - } - char* current_end = main + (main_max_length - 1); - while ((*to_append != 0) && (current < current_end)) { - *current = *to_append; - ++current; - ++to_append; - } - *current = 0; - return current; -} - -// Populates the provided buffer with an ASCII representation of the number. -char* FastUInt32ToBufferLeft(uint32_t i, char* buffer, int base) { - char* start = buffer; - do { - int32_t digit = i % base; - char character; - if (digit < 10) { - character = '0' + digit; - } else { - character = 'a' + (digit - 10); - } - *buffer++ = character; - i /= base; - } while (i > 0); - *buffer = 0; - ReverseStringInPlace(start, buffer); - return buffer; -} - -// Populates the provided buffer with an ASCII representation of the number. -char* FastInt32ToBufferLeft(int32_t i, char* buffer) { - uint32_t u = i; - if (i < 0) { - *buffer++ = '-'; - u = -u; - } - return FastUInt32ToBufferLeft(u, buffer, 10); -} - -// Converts a number to a string and appends it to another. -char* StrCatInt32(char* main, int main_max_length, int32_t number) { - char number_string[kFastToBufferSize]; - FastInt32ToBufferLeft(number, number_string); - return StrCatStr(main, main_max_length, number_string); -} - -// Converts a number to a string and appends it to another. -char* StrCatUInt32(char* main, int main_max_length, uint32_t number, int base) { - char number_string[kFastToBufferSize]; - FastUInt32ToBufferLeft(number, number_string, base); - return StrCatStr(main, main_max_length, number_string); -} - -// Populates the provided buffer with ASCII representation of the float number. -// Avoids the use of any floating point instructions (since these aren't -// supported on many microcontrollers) and as a consequence prints values with -// power-of-two exponents. -char* FastFloatToBufferLeft(float f, char* buffer) { - char* current = buffer; - char* current_end = buffer + (kFastToBufferSize - 1); - // Access the bit fields of the floating point value to avoid requiring any - // float instructions. These constants are derived from IEEE 754. - const uint32_t sign_mask = 0x80000000; - const uint32_t exponent_mask = 0x7f800000; - const int32_t exponent_shift = 23; - const int32_t exponent_bias = 127; - const uint32_t fraction_mask = 0x007fffff; - uint32_t u; - memcpy(&u, &f, sizeof(int32_t)); - const int32_t exponent = - ((u & exponent_mask) >> exponent_shift) - exponent_bias; - const uint32_t fraction = (u & fraction_mask); - // Expect ~0x2B1B9D3 for fraction. - if (u & sign_mask) { - *current = '-'; - current += 1; - } - *current = 0; - // These are special cases for infinities and not-a-numbers. - if (exponent == 128) { - if (fraction == 0) { - current = StrCatStr(current, (current_end - current), "Inf"); - return current; - } else { - current = StrCatStr(current, (current_end - current), "NaN"); - return current; - } - } - // 0x007fffff (8388607) represents 0.99... for the fraction, so to print the - // correct decimal digits we need to scale our value before passing it to the - // conversion function. This scale should be 10000000/8388608 = 1.1920928955. - // We can approximate this using multiply-adds and right-shifts using the - // values in this array. The 1. portion of the number string is printed out - // in a fixed way before the fraction, below. - const int32_t scale_shifts_size = 13; - const int8_t scale_shifts[13] = {3, 4, 8, 11, 13, 14, 17, - 18, 19, 20, 21, 22, 23}; - uint32_t scaled_fraction = fraction; - for (int i = 0; i < scale_shifts_size; ++i) { - scaled_fraction += (fraction >> scale_shifts[i]); - } - *current = '1'; - current += 1; - *current = '.'; - current += 1; - *current = 0; - - // Prepend leading zeros to fill in all 7 bytes of the fraction. Truncate - // zeros off the end of the fraction. Every fractional value takes 7 bytes. - // For example, 2500 would be written into the buffer as 0002500 since it - // represents .00025. - constexpr int kMaxFractionalDigits = 7; - - // Abort early if there is not enough space in the buffer. - if (current_end - current <= kMaxFractionalDigits) { - return current; - } - - // Pre-fill buffer with zeros to ensure zero-truncation works properly. - for (int i = 1; i < kMaxFractionalDigits; i++) { - *(current + i) = '0'; - } - - // Track how large the fraction is to add leading zeros. - char* previous = current; - current = StrCatUInt32(current, (current_end - current), scaled_fraction, 10); - int fraction_digits = current - previous; - int leading_zeros = kMaxFractionalDigits - fraction_digits; - - // Overwrite the null terminator from StrCatUInt32 to ensure zero-trunctaion - // works properly. - *current = '0'; - - // Shift fraction values and prepend zeros if necessary. - if (leading_zeros != 0) { - for (int i = 0; i < fraction_digits; i++) { - current--; - *(current + leading_zeros) = *current; - *current = '0'; - } - current += kMaxFractionalDigits; - } - - // Truncate trailing zeros for cleaner logs. Ensure we leave at least one - // fractional character for the case when scaled_fraction is 0. - while (*(current - 1) == '0' && (current - 1) > previous) { - current--; - } - *current = 0; - current = StrCatStr(current, (current_end - current), "*2^"); - current = StrCatInt32(current, (current_end - current), exponent); - return current; -} - -int FormatInt32(char* output, int32_t i) { - return static_cast(FastInt32ToBufferLeft(i, output) - output); -} - -int FormatUInt32(char* output, uint32_t i) { - return static_cast(FastUInt32ToBufferLeft(i, output, 10) - output); -} - -int FormatHex(char* output, uint32_t i) { - return static_cast(FastUInt32ToBufferLeft(i, output, 16) - output); -} - -int FormatFloat(char* output, float i) { - return static_cast(FastFloatToBufferLeft(i, output) - output); -} - -} // namespace - -extern "C" int MicroVsnprintf(char* output, int len, const char* format, - va_list args) { - int output_index = 0; - const char* current = format; - // One extra character must be left for the null terminator. - const int usable_length = len - 1; - while (*current != '\0' && output_index < usable_length) { - if (*current == '%') { - current++; - switch (*current) { - case 'd': - // Cut off log message if format could exceed log buffer length. - if (usable_length - output_index < kMaxIntCharsNeeded) { - output[output_index++] = '\0'; - return output_index; - } - output_index += - FormatInt32(&output[output_index], va_arg(args, int32_t)); - current++; - break; - case 'u': - if (usable_length - output_index < kMaxIntCharsNeeded) { - output[output_index++] = '\0'; - return output_index; - } - output_index += - FormatUInt32(&output[output_index], va_arg(args, uint32_t)); - current++; - break; - case 'x': - if (usable_length - output_index < kMaxHexCharsNeeded) { - output[output_index++] = '\0'; - return output_index; - } - output[output_index++] = '0'; - output[output_index++] = 'x'; - output_index += - FormatHex(&output[output_index], va_arg(args, uint32_t)); - current++; - break; - case 'f': - if (usable_length - output_index < kMaxFloatCharsNeeded) { - output[output_index++] = '\0'; - return output_index; - } - output_index += - FormatFloat(&output[output_index], va_arg(args, double)); - current++; - break; - case '%': - output[output_index++] = *current++; - break; - case 'c': - if (usable_length - output_index < 1) { - output[output_index++] = '\0'; - return output_index; - } - output[output_index++] = va_arg(args, int32_t); - current++; - break; - case 's': - char* string = va_arg(args, char*); - int string_idx = 0; - while (string_idx + output_index < usable_length && - string[string_idx] != '\0') { - output[output_index++] = string[string_idx++]; - } - current++; - } - } else { - output[output_index++] = *current++; - } - } - output[output_index++] = '\0'; - return output_index; -} - -extern "C" int MicroSnprintf(char* output, int len, const char* format, ...) { - va_list args; - va_start(args, format); - int bytes_written = MicroVsnprintf(output, len, format, args); - va_end(args); - return bytes_written; -} diff --git a/tensorflow/lite/micro/micro_string.h b/tensorflow/lite/micro/micro_string.h deleted file mode 100644 index 59303e82b09..00000000000 --- a/tensorflow/lite/micro/micro_string.h +++ /dev/null @@ -1,33 +0,0 @@ -/* Copyright 2018 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. -==============================================================================*/ -#ifndef TENSORFLOW_LITE_MICRO_MICRO_STRING_H_ -#define TENSORFLOW_LITE_MICRO_MICRO_STRING_H_ - -#include - -// Implements simple string formatting for numeric types. Returns the number of -// bytes written to output. -extern "C" { -// Functionally equivalent to vsnprintf, trimmed down for TFLite Micro. -// MicroSnprintf() is implemented using MicroVsnprintf(). -int MicroVsnprintf(char* output, int len, const char* format, va_list args); -// Functionally equavalent to snprintf, trimmed down for TFLite Micro. -// For example, MicroSnprintf(buffer, 10, "int %d", 10) will put the string -// "int 10" in the buffer. -// Floating point values are logged in exponent notation (1.XXX*2^N). -int MicroSnprintf(char* output, int len, const char* format, ...); -} - -#endif // TENSORFLOW_LITE_MICRO_MICRO_STRING_H_ diff --git a/tensorflow/lite/micro/micro_string_test.cc b/tensorflow/lite/micro/micro_string_test.cc deleted file mode 100644 index 3c1d8e971ee..00000000000 --- a/tensorflow/lite/micro/micro_string_test.cc +++ /dev/null @@ -1,161 +0,0 @@ -/* Copyright 2020 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. -==============================================================================*/ - -#include "tensorflow/lite/micro/micro_string.h" - -#include "tensorflow/lite/micro/testing/micro_test.h" - -TF_LITE_MICRO_TESTS_BEGIN - -TF_LITE_MICRO_TEST(FormatPositiveIntShouldMatchExpected) { - const int kBufferLen = 32; - char buffer[kBufferLen]; - const char golden[] = "Int: 55"; - int bytes_written = MicroSnprintf(buffer, kBufferLen, "Int: %d", 55); - TF_LITE_MICRO_EXPECT_EQ(static_cast(sizeof(golden)), bytes_written); - TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer); -} - -TF_LITE_MICRO_TEST(FormatNegativeIntShouldMatchExpected) { - const int kBufferLen = 32; - char buffer[kBufferLen]; - const char golden[] = "Int: -55"; - int bytes_written = MicroSnprintf(buffer, kBufferLen, "Int: %d", -55); - TF_LITE_MICRO_EXPECT_EQ(static_cast(sizeof(golden)), bytes_written); - TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer); -} - -TF_LITE_MICRO_TEST(FormatUnsignedIntShouldMatchExpected) { - const int kBufferLen = 32; - char buffer[kBufferLen]; - const char golden[] = "UInt: 12345"; - int bytes_written = MicroSnprintf(buffer, kBufferLen, "UInt: %u", 12345); - TF_LITE_MICRO_EXPECT_EQ(static_cast(sizeof(golden)), bytes_written); - TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer); -} - -TF_LITE_MICRO_TEST(FormatHexShouldMatchExpected) { - const int kBufferLen = 32; - char buffer[kBufferLen]; - const char golden[] = "Hex: 0x12345"; - int bytes_written = MicroSnprintf(buffer, kBufferLen, "Hex: %x", 0x12345); - TF_LITE_MICRO_EXPECT_EQ(static_cast(sizeof(golden)), bytes_written); - TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer); -} - -TF_LITE_MICRO_TEST(FormatFloatShouldMatchExpected) { - const int kBufferLen = 32; - char buffer[kBufferLen]; - const char golden[] = "Float: 1.0*2^4"; - int bytes_written = MicroSnprintf(buffer, kBufferLen, "Float: %f", 16.); - TF_LITE_MICRO_EXPECT_EQ(static_cast(sizeof(golden)), bytes_written); - TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer); -} - -TF_LITE_MICRO_TEST(FormatCharShouldMatchExpected) { - const int kBufferLen = 32; - char buffer[kBufferLen]; - const char golden[] = "Chars: @,Z"; - int bytes_written = - MicroSnprintf(buffer, kBufferLen, "Chars: %c,%c", 64, 'Z'); - TF_LITE_MICRO_EXPECT_EQ(static_cast(sizeof(golden)), bytes_written); - TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer); -} - -TF_LITE_MICRO_TEST(BadlyFormattedStringShouldProduceReasonableString) { - const int kBufferLen = 32; - char buffer[kBufferLen]; - const char golden[] = "Test Badly % formated % string"; - int bytes_written = - MicroSnprintf(buffer, kBufferLen, "Test Badly %% formated %% string%"); - TF_LITE_MICRO_EXPECT_EQ(static_cast(sizeof(golden)), bytes_written); - TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer); -} - -TF_LITE_MICRO_TEST(IntFormatOverrunShouldTruncate) { - const int kBufferLen = 8; - char buffer[kBufferLen]; - const char golden[] = "Int: "; - int bytes_written = MicroSnprintf(buffer, kBufferLen, "Int: %d", 12345); - TF_LITE_MICRO_EXPECT_EQ(static_cast(sizeof(golden)), bytes_written); - TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer); -} - -TF_LITE_MICRO_TEST(UnsignedIntFormatOverrunShouldTruncate) { - const int kBufferLen = 8; - char buffer[kBufferLen]; - const char golden[] = "UInt: "; - int bytes_written = MicroSnprintf(buffer, kBufferLen, "UInt: %u", 12345); - TF_LITE_MICRO_EXPECT_EQ(static_cast(sizeof(golden)), bytes_written); - TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer); -} - -TF_LITE_MICRO_TEST(HexFormatOverrunShouldTruncate) { - const int kBufferLen = 8; - char buffer[kBufferLen]; - const char golden[] = "Hex: "; - int bytes_written = MicroSnprintf(buffer, kBufferLen, "Hex: %x", 0x12345); - TF_LITE_MICRO_EXPECT_EQ(static_cast(sizeof(golden)), bytes_written); - TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer); -} - -TF_LITE_MICRO_TEST(FloatFormatOverrunShouldTruncate) { - const int kBufferLen = 12; - char buffer[kBufferLen]; - const char golden[] = "Float: "; - int bytes_written = MicroSnprintf(buffer, kBufferLen, "Float: %x", 12345.); - TF_LITE_MICRO_EXPECT_EQ(static_cast(sizeof(golden)), bytes_written); - TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer); -} - -TF_LITE_MICRO_TEST(FloatFormatShouldPrintFractionCorrectly) { - const int kBufferLen = 24; - char buffer[kBufferLen]; - const char golden[] = "Float: 1.0625*2^0"; - // Add small offset to float value to account for float rounding error. - int bytes_written = MicroSnprintf(buffer, kBufferLen, "Float: %f", 1.0625001); - TF_LITE_MICRO_EXPECT_EQ(static_cast(sizeof(golden)), bytes_written); - TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer); -} - -TF_LITE_MICRO_TEST(FloatFormatShouldPrintFractionCorrectlyNoLeadingZeros) { - const int kBufferLen = 24; - char buffer[kBufferLen]; - const char golden[] = "Float: 1.6332993*2^-1"; - int bytes_written = MicroSnprintf(buffer, kBufferLen, "Float: %f", 0.816650); - TF_LITE_MICRO_EXPECT_EQ(static_cast(sizeof(golden)), bytes_written); - TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer); -} - -TF_LITE_MICRO_TEST(StringFormatOverrunShouldTruncate) { - const int kBufferLen = 10; - char buffer[kBufferLen]; - const char golden[] = "String: h"; - int bytes_written = - MicroSnprintf(buffer, kBufferLen, "String: %s", "hello world"); - TF_LITE_MICRO_EXPECT_EQ(static_cast(sizeof(golden)), bytes_written); - TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer); -} - -TF_LITE_MICRO_TEST(StringFormatWithExactOutputSizeOverrunShouldTruncate) { - const int kBufferLen = 10; - char buffer[kBufferLen]; - const char golden[] = "format st"; - int bytes_written = MicroSnprintf(buffer, kBufferLen, "format str"); - TF_LITE_MICRO_EXPECT_EQ(static_cast(sizeof(golden)), bytes_written); - TF_LITE_MICRO_EXPECT_STRING_EQ(golden, buffer); -} - -TF_LITE_MICRO_TESTS_END diff --git a/tensorflow/lite/micro/tflite_bridge/micro_error_reporter.cc b/tensorflow/lite/micro/tflite_bridge/micro_error_reporter.cc index 63cc42ed535..d5d77c35cb0 100644 --- a/tensorflow/lite/micro/tflite_bridge/micro_error_reporter.cc +++ b/tensorflow/lite/micro/tflite_bridge/micro_error_reporter.cc @@ -1,4 +1,4 @@ -/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. +/* Copyright 2023 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. @@ -36,7 +36,7 @@ ErrorReporter* GetMicroErrorReporter() { } int MicroErrorReporter::Report(const char* format, va_list args) { - Log(format, args); + VMicroPrintf(format, args); return 0; } diff --git a/tensorflow/lite/micro/tools/make/Makefile b/tensorflow/lite/micro/tools/make/Makefile index 25ebe9df94e..e9b69dcdf5b 100644 --- a/tensorflow/lite/micro/tools/make/Makefile +++ b/tensorflow/lite/micro/tools/make/Makefile @@ -80,6 +80,7 @@ DOWNLOADS_DIR := $(MAKEFILE_DIR)/downloads INCLUDES := \ -I. \ +-I$(DOWNLOADS_DIR) \ -I$(DOWNLOADS_DIR)/gemmlowp \ -I$(DOWNLOADS_DIR)/flatbuffers/include \ -I$(DOWNLOADS_DIR)/kissfft \ @@ -298,7 +299,6 @@ $(TENSORFLOW_ROOT)tensorflow/lite/micro/micro_log_test.cc \ $(TENSORFLOW_ROOT)tensorflow/lite/micro/micro_interpreter_test.cc \ $(TENSORFLOW_ROOT)tensorflow/lite/micro/micro_mutable_op_resolver_test.cc \ $(TENSORFLOW_ROOT)tensorflow/lite/micro/micro_resource_variable_test.cc \ -$(TENSORFLOW_ROOT)tensorflow/lite/micro/micro_string_test.cc \ $(TENSORFLOW_ROOT)tensorflow/lite/micro/micro_time_test.cc \ $(TENSORFLOW_ROOT)tensorflow/lite/micro/micro_utils_test.cc \ $(TENSORFLOW_ROOT)tensorflow/lite/micro/recording_micro_allocator_test.cc \ diff --git a/tensorflow/lite/micro/tools/make/ext_libs/eyalroz_printf.inc b/tensorflow/lite/micro/tools/make/ext_libs/eyalroz_printf.inc new file mode 100644 index 00000000000..63112c12029 --- /dev/null +++ b/tensorflow/lite/micro/tools/make/ext_libs/eyalroz_printf.inc @@ -0,0 +1,28 @@ +# Copyright 2023 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. +# ============================================================================== + +DOWNLOAD_RESULT := $(shell $(MAKEFILE_DIR)/ext_libs/eyalroz_printf_download.sh $(DOWNLOADS_DIR) $(TENSORFLOW_ROOT)) +ifneq ($(DOWNLOAD_RESULT), SUCCESS) + $(error Something went wrong with the printf download: $(DOWNLOAD_RESULT)) +endif + +PRINTF_PATH := $(DOWNLOADS_DIR)/eyalroz_printf +THIRD_PARTY_CC_SRCS += \ + $(PRINTF_PATH)/src/printf/printf.c +THIRD_PARTY_CC_HDRS += \ + $(PRINTF_PATH)/src/printf/printf.h + +INCLUDES += \ + -I$(PRINTF_PATH)/src diff --git a/tensorflow/lite/micro/tools/make/ext_libs/eyalroz_printf_download.sh b/tensorflow/lite/micro/tools/make/ext_libs/eyalroz_printf_download.sh new file mode 100755 index 00000000000..79c5ba0ec84 --- /dev/null +++ b/tensorflow/lite/micro/tools/make/ext_libs/eyalroz_printf_download.sh @@ -0,0 +1,63 @@ +#!/bin/bash +# Copyright 2023 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. +# ============================================================================== +# +# Called with following arguments: +# 1 - Path to the downloads folder which is typically +# ${TENSORFLOW_ROOT}/tensorflow/lite/micro/tools/make/downloads +# 2 - (optional) TENSORFLOW_ROOT: path to root of the TFLM tree (relative to directory from where the script is called). +# +# This script is called from the Makefile and uses the following convention to +# enable determination of sucess/failure: +# +# - If the script is successful, the only output on stdout should be SUCCESS. +# The makefile checks for this particular string. +# +# - Any string on stdout that is not SUCCESS will be shown in the makefile as +# the cause for the script to have failed. +# +# - Any other informational prints should be on stderr. + +set -e + +TENSORFLOW_ROOT=${2} +source ${TENSORFLOW_ROOT}tensorflow/lite/micro/tools/make/bash_helpers.sh + +DOWNLOADS_DIR=${1} +if [ ! -d ${DOWNLOADS_DIR} ]; then + echo "The top-level downloads directory: ${DOWNLOADS_DIR} does not exist." + exit 1 +fi + +DOWNLOADED_PRINTF_PATH=${DOWNLOADS_DIR}/eyalroz_printf + +if [ -d ${DOWNLOADED_PRINTF_PATH} ]; then + echo >&2 "${DOWNLOADED_PRINTF_PATH} already exists, skipping the download." +else + + ZIP_PREFIX="f8ed5a9bd9fa8384430973465e94aa14c925872d" + PRINTF_URL="https://github.com/eyalroz/printf/archive/${ZIP_PREFIX}.zip" + PRINTF_MD5="5772534c1d6f718301bca1fefaba28f3" + + # wget is much faster than git clone of the entire repo. So we wget a specific + # version and can then apply a patch, as needed. + wget ${PRINTF_URL} -O /tmp/${ZIP_PREFIX}.zip >&2 + check_md5 /tmp/${ZIP_PREFIX}.zip ${PRINTF_MD5} + + unzip -qo /tmp/${ZIP_PREFIX}.zip -d /tmp >&2 + mv /tmp/printf-${ZIP_PREFIX} ${DOWNLOADED_PRINTF_PATH} +fi + +echo "SUCCESS" \ No newline at end of file diff --git a/tensorflow/lite/micro/tools/make/targets/arc_emsdp_makefile.inc b/tensorflow/lite/micro/tools/make/targets/arc_emsdp_makefile.inc index f7c3066ee70..7fce24b927e 100644 --- a/tensorflow/lite/micro/tools/make/targets/arc_emsdp_makefile.inc +++ b/tensorflow/lite/micro/tools/make/targets/arc_emsdp_makefile.inc @@ -1,4 +1,4 @@ -# Copyright 2021 The TensorFlow Authors. All Rights Reserved. +# Copyright 2023 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. @@ -26,4 +26,6 @@ $(eval $(call add_third_party_download,$(EMBARC_MLI_PRE_COMPILED_URL),$(EMBARC_M TCF_FILE = $(PWD)/$(MAKEFILE_DIR)/downloads/$(MLI_LIB_DIR)/hw/emsdp_em11d_em9d_dfss.tcf -include $(MAKEFILE_DIR)/targets/arc/arc_common.inc \ No newline at end of file +include $(MAKEFILE_DIR)/targets/arc/arc_common.inc + +include $(MAKEFILE_DIR)/ext_libs/eyalroz_printf.inc diff --git a/tensorflow/lite/micro/tools/make/targets/bluepill_makefile.inc b/tensorflow/lite/micro/tools/make/targets/bluepill_makefile.inc index c14bda496e7..532689cd832 100644 --- a/tensorflow/lite/micro/tools/make/targets/bluepill_makefile.inc +++ b/tensorflow/lite/micro/tools/make/targets/bluepill_makefile.inc @@ -1,3 +1,18 @@ +# Copyright 2023 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. +# ============================================================================== + export PATH := $(DOWNLOADS_DIR)/gcc_embedded/bin/:$(PATH) TARGET_ARCH := cortex-m3 TARGET_TOOLCHAIN_PREFIX := arm-none-eabi- @@ -87,3 +102,5 @@ TEST_TARGET_BINARIES = $(shell ls -1 $(BINDIR)/*_test) test: build $(TEST_SCRIPT) "$(TEST_TARGET_BINARIES)" $(TEST_PASS_STRING) $(TARGET) + +include $(MAKEFILE_DIR)/ext_libs/eyalroz_printf.inc diff --git a/tensorflow/lite/micro/tools/make/targets/chre_makefile.inc b/tensorflow/lite/micro/tools/make/targets/chre_makefile.inc index 3665b264aa9..d2e5892a761 100644 --- a/tensorflow/lite/micro/tools/make/targets/chre_makefile.inc +++ b/tensorflow/lite/micro/tools/make/targets/chre_makefile.inc @@ -1,4 +1,4 @@ -# Copyright 2020 The TensorFlow Authors. All Rights Reserved. +# Copyright 2023 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. @@ -32,3 +32,5 @@ MICROLITE_CC_KERNEL_SRCS := $(filter-out $(EXCLUDED_CC_SRCS),$(MICROLITE_CC_KERN MICROLITE_TEST_SRCS := $(filter-out $(EXCLUDED_TESTS),$(MICROLITE_TEST_SRCS)) THIRD_PARTY_CC_HDRS := $(filter-out $(EXCLUDED_HDRS),$(THIRD_PARTY_CC_HDRS)) MICROLITE_CC_HDRS := $(filter-out $(EXCLUDED_KERNEL_HDRS),$(MICROLITE_CC_HDRS)) + +include $(MAKEFILE_DIR)/ext_libs/eyalroz_printf.inc diff --git a/tensorflow/lite/micro/tools/make/targets/cortex_m_generic_makefile.inc b/tensorflow/lite/micro/tools/make/targets/cortex_m_generic_makefile.inc index 0ed14fcb8bb..0e034ad8168 100644 --- a/tensorflow/lite/micro/tools/make/targets/cortex_m_generic_makefile.inc +++ b/tensorflow/lite/micro/tools/make/targets/cortex_m_generic_makefile.inc @@ -1,4 +1,4 @@ -# Copyright 2022 The TensorFlow Authors. All Rights Reserved. +# Copyright 2023 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. @@ -204,3 +204,5 @@ ifneq ($(TARGET_ARCH), project_generation) $(TENSORFLOW_ROOT)tensorflow/lite/micro/examples/micro_speech/Makefile.inc MICRO_LITE_EXAMPLE_TESTS := $(filter-out $(EXCLUDED_EXAMPLE_TESTS), $(MICRO_LITE_EXAMPLE_TESTS)) endif + +include $(MAKEFILE_DIR)/ext_libs/eyalroz_printf.inc diff --git a/tensorflow/lite/micro/tools/project_generation/Makefile b/tensorflow/lite/micro/tools/project_generation/Makefile index 092ba7e07f4..7497f0701d8 100644 --- a/tensorflow/lite/micro/tools/project_generation/Makefile +++ b/tensorflow/lite/micro/tools/project_generation/Makefile @@ -1,4 +1,4 @@ -# Copyright 2022 The TensorFlow Authors. All Rights Reserved. +# Copyright 2023 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. @@ -92,6 +92,13 @@ LIB := $(GENDIR)/libtflm.a TFLM_CC_SRCS := $(shell find $(TENSORFLOW_ROOT)tensorflow -name "*.cc" -o -name "*.c") OBJS := $(addprefix $(OBJDIR)/, $(patsubst %.c,%.o,$(patsubst %.cc,%.o,$(TFLM_CC_SRCS)))) +# if the third party printf library is present, add the include paths +TFLM_PRINTF_PATH := $(shell find third_party -name eyalroz_printf) +ifneq ($(TFLM_PRINTF_PATH),) + INCLUDES += \ + -I./third_party +endif + $(OBJDIR)/%.o: %.cc @mkdir -p $(dir $@) $(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@