Generic Benchmark Tool changes (#2451)

@tensorflow/micro

Add ability to build with a model chosen at compile time. Add README with build instructions.

bug=fixes #2450
diff --git a/tensorflow/lite/micro/tools/benchmarking/Makefile.inc b/tensorflow/lite/micro/tools/benchmarking/Makefile.inc
index 036927e..32e782c 100644
--- a/tensorflow/lite/micro/tools/benchmarking/Makefile.inc
+++ b/tensorflow/lite/micro/tools/benchmarking/Makefile.inc
@@ -1,5 +1,23 @@
 MICROLITE_BENCHMARK_ROOT_DIR := $(TENSORFLOW_ROOT)tensorflow/lite/micro/tools/benchmarking
 
+ifneq ($(BENCHMARK_MODEL_PATH),)
+    GENERIC_BENCHMARK_MODEL_DIR := $(dir $(BENCHMARK_MODEL_PATH))
+    GENERIC_BENCHMARK_MODEL_NAME := $(notdir $(basename $(BENCHMARK_MODEL_PATH)))
+    CXXFLAGS += -DMODEL_HEADER_PATH=\"$(GENERIC_BENCHMARK_MODEL_DIR)$(GENERIC_BENCHMARK_MODEL_NAME)_model_data.h\"
+    CXXFLAGS += -DMODEL_NAME=$(GENERIC_BENCHMARK_MODEL_NAME)
+ifneq ($(BENCHMARK_ARENA_SIZE),)
+    CXXFLAGS += -DTENSOR_ARENA_SIZE=$(BENCHMARK_ARENA_SIZE)
+endif
+
+    GENERIC_BENCHMARK_GENERATOR_INPUTS := $(TENSORFLOW_ROOT)$(BENCHMARK_MODEL_PATH)
+
+    GENERIC_BENCHMARK_GENERATED_SRCS := \
+    $(GENERATED_SRCS_DIR)$(TENSORFLOW_ROOT)$(GENERIC_BENCHMARK_MODEL_DIR)$(GENERIC_BENCHMARK_MODEL_NAME)_model_data.cc
+
+    GENERIC_BENCHMARK_GENERATED_HDRS := \
+    $(GENERATED_SRCS_DIR)$(TENSORFLOW_ROOT)$(GENERIC_BENCHMARK_MODEL_DIR)$(GENERIC_BENCHMARK_MODEL_NAME)_model_data.h
+endif
+
 GENERIC_BENCHMARK_SRCS := \
 $(MICROLITE_BENCHMARK_ROOT_DIR)/generic_model_benchmark.cc \
 $(MICROLITE_BENCHMARK_ROOT_DIR)/metrics.cc
@@ -11,6 +29,7 @@
 ifneq ($(TARGET),bluepill)
 ifneq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), hifimini))
     $(eval $(call microlite_test,tflm_benchmark,\
-    $(GENERIC_BENCHMARK_SRCS),$(GENERIC_BENCHMARK_HDRS),))
+    $(GENERIC_BENCHMARK_SRCS),$(GENERIC_BENCHMARK_HDRS),\
+    $(GENERIC_BENCHMARK_GENERATOR_INPUTS)))
 endif
 endif
diff --git a/tensorflow/lite/micro/tools/benchmarking/README.md b/tensorflow/lite/micro/tools/benchmarking/README.md
new file mode 100644
index 0000000..0bc727e
--- /dev/null
+++ b/tensorflow/lite/micro/tools/benchmarking/README.md
@@ -0,0 +1,48 @@
+# Generic Benchmarking Tool build/run instructions
+This tool can be used to benchmark any TfLite format model.  The tool can be
+compiled in one of two ways:
+1. Such that it takes command line arguments, allowing the path to the model
+file to be specified as a program argument
+2. With a model compiled into the tool, allowing use in any simulator or on
+any hardware platform
+
+Building the tool with the model compiled in uses two additional Makefile
+variables:
+* `BENCHMARK_MODEL_PATH`: the path to the TfLite format model file.  This
+can be a relative or absolute path.  This variable is required.
+* `BENCHMARK_ARENA_SIZE`: the size of the TFLM interpreter arena, in bytes.
+This variable is optional.
+
+## Tested, working targets
+* x86
+* cortex_m_qemu (no timing data)
+* Xtensa
+* cortex_m_corstone_300
+
+## Tested, non-working targets
+* none currently
+
+## Build and run for x86
+Build for command line arguments:
+```
+make -f tensorflow/lite/micro/tools/make/Makefile tflm_benchmark -j$(nproc)
+```
+Run with command line arguments:
+```
+gen/linux_x86_64_default/bin/tflm_benchmark tensorflow/lite/micro/models/person_detect.tflite
+```
+
+Build with model compiled into tool:
+```
+make -f tensorflow/lite/micro/tools/make/Makefile tflm_benchmark -j$(nproc) BENCHMARK_MODEL_PATH=tensorflow/lite/micro/models/person_detect.tflite BENCHMARK_ARENA_SIZE=`expr 100 \* 1024`
+```
+Run with model compiled into tool:
+```
+gen/linux_x86_64_default/bin/tflm_benchmark
+```
+
+## Build and run for Xtensa
+Build and run with model compiled into tool:
+```
+make -f tensorflow/lite/micro/tools/make/Makefile TARGET=xtensa TARGET_ARCH=vision_p6 OPTIMIZED_KERNEL_DIR=xtensa XTENSA_CORE=P6_200528 BUILD_TYPE=default run_tflm_benchmark -j$(nproc) BENCHMARK_MODEL_PATH=/tmp/keyword_scrambled.tflite BENCHMARK_ARENA_SIZE=`expr 50 \* 1024`
+```
diff --git a/tensorflow/lite/micro/tools/benchmarking/generic_model_benchmark.cc b/tensorflow/lite/micro/tools/benchmarking/generic_model_benchmark.cc
index 5f6e4c3..eef5f4c 100644
--- a/tensorflow/lite/micro/tools/benchmarking/generic_model_benchmark.cc
+++ b/tensorflow/lite/micro/tools/benchmarking/generic_model_benchmark.cc
@@ -1,4 +1,4 @@
-/* Copyright 2023 The TensorFlow Authors. All Rights Reserved.
+/* Copyright 2024 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.
@@ -20,9 +20,11 @@
 #include <cstring>
 #include <memory>
 #include <random>
+#include <type_traits>
 
 #include "tensorflow/lite/c/c_api_types.h"
 #include "tensorflow/lite/c/common.h"
+#include "tensorflow/lite/micro/micro_context.h"
 #include "tensorflow/lite/micro/micro_log.h"
 #include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
 #include "tensorflow/lite/micro/micro_op_resolver.h"
@@ -34,6 +36,23 @@
 #include "tensorflow/lite/micro/tools/benchmarking/op_resolver.h"
 #include "tensorflow/lite/schema/schema_generated.h"
 
+#if defined(MODEL_HEADER_PATH)
+#if !defined(MODEL_NAME)
+#error "MODEL_NAME missing from CCFLAGS"
+#endif  // !defined(MODEL_NAME)
+
+#include MODEL_HEADER_PATH
+
+#define __MODEL_DATA(x) g_##x##_model_data
+#define _MODEL_DATA(x) __MODEL_DATA(x)
+#define MODEL_DATA _MODEL_DATA(MODEL_NAME)
+#define __MODEL_SIZE(x) g_##x##_model_data_size
+#define _MODEL_SIZE(x) __MODEL_SIZE(x)
+#define MODEL_SIZE _MODEL_SIZE(MODEL_NAME)
+
+#define USING_BUILTIN_MODEL
+#endif  // defind(MODEL_HEADER_PATH)
+
 /*
  * Generic model benchmark.  Evaluates runtime performance of a provided model
  * with random inputs.
@@ -45,15 +64,20 @@
 
 using Profiler = ::tflite::MicroProfiler;
 
-constexpr int kTfLiteAbort = -9;
-
 // Seed used for the random input. Input data shouldn't affect invocation timing
 // so randomness isn't really needed.
 constexpr uint32_t kRandomSeed = 0xFB;
 
+#if !defined(USING_BUILTIN_MODEL)
 constexpr size_t kTensorArenaSize = 3e6;
-constexpr int kNumResourceVariable = 100;
 constexpr size_t kModelSize = 2e6;
+#elif defined(TENSOR_ARENA_SIZE)
+constexpr size_t kTensorArenaSize = TENSOR_ARENA_SIZE;
+#else
+constexpr size_t kTensorArenaSize = 5e6 - MODEL_SIZE;
+#endif  // !defined(USING_BUILTIN_MODEL)
+
+constexpr int kNumResourceVariable = 100;
 
 void SetRandomInput(const uint32_t random_seed,
                     tflite::MicroInterpreter& interpreter) {
@@ -71,6 +95,7 @@
   }
 }
 
+#if !defined(USING_BUILTIN_MODEL)
 bool ReadFile(const char* file_name, void* buffer, size_t buffer_size) {
   std::unique_ptr<FILE, decltype(&fclose)> file(fopen(file_name, "rb"), fclose);
 
@@ -95,17 +120,16 @@
 
   return true;
 }
+#endif  // !defined(USING_BUILTIN_MODEL)
 
-int Benchmark(const char* model_file_name, tflite::PrettyPrintType print_type) {
+int Benchmark(const uint8_t* model_data, tflite::PrettyPrintType print_type) {
   Profiler profiler;
   alignas(16) static uint8_t tensor_arena[kTensorArenaSize];
-  alignas(16) static uint8_t model_file_content[kModelSize];
 
-  if (!ReadFile(model_file_name, model_file_content, kModelSize)) {
-    return -1;
-  }
+  MicroPrintf("\nConfigured arena size = %d\n", kTensorArenaSize);
+
   uint32_t event_handle = profiler.BeginEvent("TfliteGetModel");
-  const tflite::Model* model = tflite::GetModel(model_file_content);
+  const tflite::Model* model = tflite::GetModel(model_data);
   profiler.EndEvent(event_handle);
 
   TflmOpResolver op_resolver;
@@ -156,14 +180,18 @@
 }  // namespace
 }  // namespace tflite
 
+#if !defined(USING_BUILTIN_MODEL)
 void usage(const char* prog_name) {
   MicroPrintf("usage: %s filename [--csv]", prog_name);
 }
+#endif  // !defined(USING_BUILTIN_MODEL)
 
 int main(int argc, char** argv) {
   // Which format should be used to output debug information.
   tflite::PrettyPrintType print_type = tflite::PrettyPrintType::kTable;
+  tflite::InitializeTarget();
 
+#if !defined(USING_BUILTIN_MODEL)
   if (argc < 2 || argc > 3) {
     usage(argv[0]);
     return -1;
@@ -179,5 +207,14 @@
     }
   }
 
-  return tflite::Benchmark(model_filename, print_type);
+  alignas(16) static uint8_t model_data[tflite::kModelSize];
+
+  if (!tflite::ReadFile(model_filename, model_data, tflite::kModelSize)) {
+    return -1;
+  }
+#else
+  const uint8_t* model_data = MODEL_DATA;
+#endif  // !defined(USING_BUILTIN_MODEL)
+
+  return tflite::Benchmark(model_data, print_type);
 }
diff --git a/tensorflow/lite/micro/tools/generate_cc_arrays.py b/tensorflow/lite/micro/tools/generate_cc_arrays.py
index 4d1e54c..16d72c1 100644
--- a/tensorflow/lite/micro/tools/generate_cc_arrays.py
+++ b/tensorflow/lite/micro/tools/generate_cc_arrays.py
@@ -35,8 +35,6 @@
     out_cc_file.write('#include <cstdint>\n\n')
     out_cc_file.write('#include "{}"\n\n'.format(
         out_fname.split('genfiles/')[-1].replace('.cc', '.h')))
-    out_cc_file.write('const unsigned int {}_size = {};\n'.format(
-        array_name, str(size)))
     out_cc_file.write('alignas(16) const {} {}[] = {{'.format(
         array_type, array_name))
     out_cc_file.write(array_contents)
@@ -45,8 +43,8 @@
   elif out_fname.endswith('.h'):
     out_hdr_file = open(out_fname, 'w')
     out_hdr_file.write('#include <cstdint>\n\n')
-    out_hdr_file.write(
-        'extern const unsigned int {}_size;\n'.format(array_name))
+    out_hdr_file.write('constexpr unsigned int {}_size = {};\n'.format(
+        array_name, str(size)))
     out_hdr_file.write('extern const {} {}[];\n'.format(
         array_type, array_name))
     out_hdr_file.close()