Automated sync from github.com/tensorflow/tensorflow (#71)

diff --git a/tensorflow/lite/micro/BUILD b/tensorflow/lite/micro/BUILD
index dc06fb5..3baec20 100644
--- a/tensorflow/lite/micro/BUILD
+++ b/tensorflow/lite/micro/BUILD
@@ -24,28 +24,69 @@
 )
 
 cc_library(
+    # TODO(b/187093492): Rename to micro_interpreter.
     name = "micro_framework",
     srcs = [
-        "micro_allocator.cc",
         "micro_interpreter.cc",
+    ],
+    hdrs = [
+        "micro_interpreter.h",
+    ],
+    copts = micro_copts(),
+    deps = [
+        ":memory_helpers",
+        ":micro_allocator",
+        ":micro_error_reporter",
+        ":micro_graph",
+        ":micro_profiler",
+        ":op_resolvers",
+        "//tensorflow/lite:type_to_tflitetype",
+        "//tensorflow/lite/c:common",
+        "//tensorflow/lite/core/api",
+        "//tensorflow/lite/core/api:error_reporter",
+        "//tensorflow/lite/kernels/internal:tensor",
+        "//tensorflow/lite/schema:schema_fbs",
+        "//tensorflow/lite/schema:schema_utils",
+        "@flatbuffers//:runtime_cc",
+    ],
+)
+
+cc_library(
+    name = "micro_graph",
+    srcs = ["micro_graph.cc"],
+    hdrs = ["micro_graph.h"],
+    deps = [
+        ":memory_helpers",
+        ":micro_allocator",
+        ":micro_error_reporter",
+        ":micro_profiler",
+        "//tensorflow/lite/c:common",
+        "//tensorflow/lite/kernels/internal:compatibility",
+        "//tensorflow/lite/schema:schema_fbs",
+        "@flatbuffers//:runtime_cc",
+    ],
+)
+
+cc_library(
+    name = "micro_allocator",
+    srcs = [
+        "micro_allocator.cc",
         "simple_memory_allocator.cc",
     ],
     hdrs = [
         "micro_allocator.h",
-        "micro_interpreter.h",
         "simple_memory_allocator.h",
     ],
     copts = micro_copts(),
     deps = [
         ":memory_helpers",
         ":micro_compatibility",
-        ":micro_profiler",
-        ":op_resolvers",
-        "//tensorflow/lite:type_to_tflitetype",
+        ":micro_error_reporter",
         "//tensorflow/lite/c:common",
         "//tensorflow/lite/core/api",
+        "//tensorflow/lite/core/api:error_reporter",
+        "//tensorflow/lite/core/api:op_resolver",
         "//tensorflow/lite/kernels/internal:compatibility",
-        "//tensorflow/lite/kernels/internal:tensor",
         "//tensorflow/lite/micro/memory_planner",
         "//tensorflow/lite/micro/memory_planner:greedy_memory_planner",
         "//tensorflow/lite/schema:schema_fbs",
@@ -211,6 +252,7 @@
     ],
     copts = micro_copts(),
     deps = [
+        ":micro_allocator",
         ":micro_compatibility",
         ":micro_framework",
         "//tensorflow/lite/core/api",
@@ -258,7 +300,9 @@
     ],
     deps = [
         ":micro_compatibility",
+        ":micro_error_reporter",
         ":micro_framework",
+        ":micro_profiler",
         ":micro_utils",
         ":op_resolvers",
         ":recording_allocators",
@@ -300,8 +344,10 @@
     ],
     deps = [
         ":memory_helpers",
-        ":micro_framework",
+        ":micro_allocator",
+        ":micro_error_reporter",
         ":test_helpers",
+        "//tensorflow/lite/c:common",
         "//tensorflow/lite/micro/testing:micro_test",
         "//tensorflow/lite/micro/testing:test_conv_model",
     ],
@@ -313,7 +359,8 @@
         "recording_micro_allocator_test.cc",
     ],
     deps = [
-        ":micro_framework",
+        ":micro_allocator",
+        ":micro_error_reporter",
         ":op_resolvers",
         ":recording_allocators",
         ":test_helpers",
@@ -385,6 +432,7 @@
         "memory_arena_threshold_test.cc",
     ],
     deps = [
+        ":micro_error_reporter",
         ":op_resolvers",
         ":recording_allocators",
         "//tensorflow/lite/micro/benchmarks:keyword_scrambled_model_data",
diff --git a/tensorflow/lite/micro/memory_arena_threshold_test.cc b/tensorflow/lite/micro/memory_arena_threshold_test.cc
index c828210..a7daf2e 100644
--- a/tensorflow/lite/micro/memory_arena_threshold_test.cc
+++ b/tensorflow/lite/micro/memory_arena_threshold_test.cc
@@ -50,13 +50,13 @@
 // Run this test with '--copt=-DTF_LITE_STATIC_MEMORY' to get optimized memory
 // runtime values:
 #ifdef TF_LITE_STATIC_MEMORY
-constexpr int kKeywordModelTotalSize = 14384;
-constexpr int kKeywordModelTailSize = 13712;
+constexpr int kKeywordModelTotalSize = 14416;
+constexpr int kKeywordModelTailSize = 13744;
 constexpr int kKeywordModelPersistentTfLiteTensorDataSize = 128;
-constexpr int kKeywordModelPersistentBufferDataSize = 572;
+constexpr int kKeywordModelPersistentBufferDataSize = 564;
 #else
-constexpr int kKeywordModelTotalSize = 14832;
-constexpr int kKeywordModelTailSize = 14160;
+constexpr int kKeywordModelTotalSize = 14992;
+constexpr int kKeywordModelTailSize = 14320;
 constexpr int kKeywordModelPersistentTfLiteTensorDataSize = 224;
 constexpr int kKeywordModelPersistentBufferDataSize = 564;
 #endif
@@ -74,13 +74,13 @@
 // NOTE: These values are measured on x86-64:
 // TODO(b/158651472): Consider auditing these values on non-64 bit systems.
 #ifdef TF_LITE_STATIC_MEMORY
-constexpr int kTestConvModelTotalSize = 9744;
-constexpr int kTestConvModelTailSize = 2000;
+constexpr int kTestConvModelTotalSize = 9792;
+constexpr int kTestConvModelTailSize = 2048;
 constexpr int kTestConvModelPersistentTfLiteTensorDataSize = 128;
-constexpr int kTestConvModelPersistentBufferDataSize = 672;
+constexpr int kTestConvModelPersistentBufferDataSize = 680;
 #else
-constexpr int kTestConvModelTotalSize = 10016;
-constexpr int kTestConvModelTailSize = 2272;
+constexpr int kTestConvModelTotalSize = 10112;
+constexpr int kTestConvModelTailSize = 2368;
 constexpr int kTestConvModelPersistentTfLiteTensorDataSize = 224;
 constexpr int kTestConvModelPersistentBufferDataSize = 680;
 #endif
@@ -177,11 +177,6 @@
           .used_bytes,
       sizeof(tflite::NodeAndRegistration) *
           thresholds.node_and_registration_count);
-  EnsureAllocatedSizeThreshold(
-      "OpData",
-      allocator.GetRecordedAllocation(tflite::RecordedAllocationType::kOpData)
-          .used_bytes,
-      thresholds.op_runtime_data_size);
 
   // Ensure tail allocation recording is not missing any large chunks:
   size_t tail_est_length = sizeof(TfLiteEvalTensor) * thresholds.tensor_count +
diff --git a/tensorflow/lite/micro/micro_allocator.cc b/tensorflow/lite/micro/micro_allocator.cc
index 8655168..6bfd0ff 100644
--- a/tensorflow/lite/micro/micro_allocator.cc
+++ b/tensorflow/lite/micro/micro_allocator.cc
@@ -29,7 +29,7 @@
 #include "tensorflow/lite/micro/memory_helpers.h"
 #include "tensorflow/lite/micro/memory_planner/greedy_memory_planner.h"
 #include "tensorflow/lite/micro/memory_planner/memory_planner.h"
-#include "tensorflow/lite/micro/micro_op_resolver.h"
+#include "tensorflow/lite/micro/micro_error_reporter.h"
 #include "tensorflow/lite/micro/simple_memory_allocator.h"
 #include "tensorflow/lite/schema/schema_generated.h"
 #include "tensorflow/lite/schema/schema_utils.h"
@@ -608,33 +608,46 @@
   return allocator;
 }
 
-TfLiteStatus MicroAllocator::StartModelAllocation(
-    const Model* model, const MicroOpResolver& op_resolver,
-    NodeAndRegistration** node_and_registrations,
-    TfLiteEvalTensor** eval_tensors) {
+SubgraphAllocations* MicroAllocator::StartModelAllocation(const Model* model) {
   TFLITE_DCHECK(model != nullptr);
 
   if (model_is_allocating_) {
     TF_LITE_REPORT_ERROR(error_reporter_,
                          "MicroAllocator: Model allocation started before "
                          "finishing previously allocated model");
-    return kTfLiteError;
+    return nullptr;
   }
 
   model_is_allocating_ = true;
 
-  TF_LITE_ENSURE_STATUS(InitScratchBufferData());
-  TF_LITE_ENSURE_STATUS(AllocateTfLiteEvalTensors(model, eval_tensors));
-  TF_LITE_ENSURE_STATUS(
-      AllocateNodeAndRegistrations(model, node_and_registrations));
-  TF_LITE_ENSURE_STATUS(PrepareNodeAndRegistrationDataFromFlatbuffer(
-      model, op_resolver, *node_and_registrations));
+  uint8_t* data_allocator_buffer = memory_allocator_->AllocateFromTail(
+      sizeof(MicroBuiltinDataAllocator), alignof(MicroBuiltinDataAllocator));
+  builtin_data_allocator_ =
+      new (data_allocator_buffer) MicroBuiltinDataAllocator(memory_allocator_);
 
-  return kTfLiteOk;
+  if (InitScratchBufferData() != kTfLiteOk) {
+    return nullptr;
+  }
+
+  // Allocate struct to store eval tensors, nodes and registrations.
+  SubgraphAllocations* output = reinterpret_cast<SubgraphAllocations*>(
+      memory_allocator_->AllocateFromTail(
+          sizeof(SubgraphAllocations) * model->subgraphs()->size(),
+          alignof(SubgraphAllocations)));
+  if (output == nullptr) {
+    MicroPrintf("Failed to allocate memory for model metadata.");
+    return nullptr;
+  }
+
+  if (AllocateTfLiteEvalTensors(model, output) != kTfLiteOk ||
+      AllocateNodeAndRegistrations(model, output) != kTfLiteOk) {
+    return nullptr;
+  }
+  return output;
 }
 
 TfLiteStatus MicroAllocator::FinishModelAllocation(
-    const Model* model, TfLiteEvalTensor* eval_tensors,
+    const Model* model, SubgraphAllocations* subgraph_allocations,
     ScratchBufferHandle** scratch_buffer_handles) {
   if (!model_is_allocating_) {
     TF_LITE_REPORT_ERROR(error_reporter_,
@@ -643,15 +656,20 @@
     return kTfLiteError;
   }
 
-  const SubGraph* subgraph = GetSubGraphFromModel(model);
-  TFLITE_DCHECK(subgraph != nullptr);
+  // TODO(b/187993197): Track scratch buffers for each subgraph.
+  for (size_t subgraph_idx = 0; subgraph_idx < model->subgraphs()->size();
+       subgraph_idx++) {
+    const SubGraph* subgraph = model->subgraphs()->Get(subgraph_idx);
+    TFLITE_DCHECK(subgraph != nullptr);
 
-  TF_LITE_ENSURE_STATUS(AllocateScratchBufferHandles(
-      scratch_buffer_handles, scratch_buffer_request_count_));
-  TF_LITE_ENSURE_STATUS(CommitStaticMemoryPlan(model, subgraph, eval_tensors,
-                                               *scratch_buffer_handles));
-  TF_LITE_ENSURE_STATUS(AllocateVariables(subgraph, eval_tensors));
-
+    TF_LITE_ENSURE_STATUS(AllocateScratchBufferHandles(
+        scratch_buffer_handles, scratch_buffer_request_count_));
+    TF_LITE_ENSURE_STATUS(CommitStaticMemoryPlan(
+        model, subgraph_allocations[subgraph_idx].tensors,
+        *scratch_buffer_handles, subgraph_idx));
+    TF_LITE_ENSURE_STATUS(AllocateVariables(
+        subgraph, subgraph_allocations[subgraph_idx].tensors));
+  }
   model_is_allocating_ = false;
   return kTfLiteOk;
 }
@@ -661,6 +679,7 @@
 }
 
 TfLiteStatus MicroAllocator::RequestScratchBufferInArena(size_t bytes,
+                                                         int subgraph_idx,
                                                          int* buffer_idx) {
   // All scratch buffer requests are stored in the head section of the arena
   // when a model is in the prepare phase. First align a scratch buffer request
@@ -735,153 +754,66 @@
 }
 
 TfLiteStatus MicroAllocator::AllocateNodeAndRegistrations(
-    const Model* model, NodeAndRegistration** node_and_registrations) {
-  TFLITE_DCHECK(node_and_registrations);
+    const Model* model, SubgraphAllocations* subgraph_allocations) {
+  TFLITE_DCHECK(subgraph_allocations != nullptr);
 
-  const SubGraph* subgraph = GetSubGraphFromModel(model);
-  TFLITE_DCHECK(subgraph != nullptr);
+  for (size_t subgraph_idx = 0; subgraph_idx < model->subgraphs()->size();
+       subgraph_idx++) {
+    const SubGraph* subgraph = model->subgraphs()->Get(subgraph_idx);
+    TFLITE_DCHECK(subgraph != nullptr);
 
-  NodeAndRegistration* output = reinterpret_cast<NodeAndRegistration*>(
-      memory_allocator_->AllocateFromTail(
-          sizeof(NodeAndRegistration) * subgraph->operators()->size(),
-          alignof(NodeAndRegistration)));
-  if (output == nullptr) {
-    TF_LITE_REPORT_ERROR(
-        error_reporter_,
-        "Failed to allocate memory for node_and_registrations.");
-    return kTfLiteError;
-  }
-  *node_and_registrations = output;
-  return kTfLiteOk;
-}
-
-TfLiteStatus MicroAllocator::PrepareNodeAndRegistrationDataFromFlatbuffer(
-    const Model* model, const MicroOpResolver& op_resolver,
-    NodeAndRegistration* node_and_registrations) {
-  TFLITE_DCHECK(model != nullptr);
-  TFLITE_DCHECK(node_and_registrations != nullptr);
-
-  const SubGraph* subgraph = GetSubGraphFromModel(model);
-  TFLITE_DCHECK(subgraph != nullptr);
-
-  TfLiteStatus status = kTfLiteOk;
-  auto* opcodes = model->operator_codes();
-  MicroBuiltinDataAllocator builtin_data_allocator(memory_allocator_);
-  for (size_t i = 0; i < subgraph->operators()->size(); ++i) {
-    const auto* op = subgraph->operators()->Get(i);
-    const size_t index = op->opcode_index();
-    if (index >= opcodes->size()) {
-      TF_LITE_REPORT_ERROR(error_reporter_,
-                           "Missing registration for opcode_index %d\n", index);
+    // Initialize NodeAndRegistrations for the subgraph.
+    NodeAndRegistration* output = reinterpret_cast<NodeAndRegistration*>(
+        memory_allocator_->AllocateFromTail(
+            sizeof(NodeAndRegistration) * subgraph->operators()->size(),
+            alignof(NodeAndRegistration)));
+    if (output == nullptr) {
+      TF_LITE_REPORT_ERROR(
+          error_reporter_,
+          "Failed to allocate memory for node_and_registrations.");
       return kTfLiteError;
     }
-    auto* opcode = (*opcodes)[index];
-    status =
-        GetRegistrationFromOpCode(opcode, op_resolver, error_reporter_,
-                                  &(node_and_registrations[i].registration));
-    if (status != kTfLiteOk) {
-      TF_LITE_REPORT_ERROR(error_reporter_,
-                           "Failed to get registration from op code %s\n ",
-                           EnumNameBuiltinOperator(GetBuiltinCode(opcode)));
-      return status;
-    }
-    const auto* registration = node_and_registrations[i].registration;
-    if (registration == nullptr) {
-      TF_LITE_REPORT_ERROR(error_reporter_, "Skipping op for opcode_index %d\n",
-                           index);
-      return kTfLiteError;
-    }
-    BuiltinOperator op_type =
-        static_cast<BuiltinOperator>(registration->builtin_code);
-
-    const char* custom_data = nullptr;
-    size_t custom_data_size = 0;
-    unsigned char* builtin_data = nullptr;
-
-    if (op_type == BuiltinOperator_CUSTOM) {
-      // Custom Ops may or may not have a non-null custom_options field.
-      if (op->custom_options() != nullptr) {
-        custom_data =
-            reinterpret_cast<const char*>(op->custom_options()->data());
-        custom_data_size = op->custom_options()->size();
-      }
-    } else {
-      if (op->custom_options() != nullptr) {
-        TF_LITE_REPORT_ERROR(
-            error_reporter_,
-            "Unsupported behavior: found builtin operator %s with custom "
-            "options.\n",
-            EnumNameBuiltinOperator(op_type));
-        return kTfLiteError;
-      }
-
-      MicroOpResolver::BuiltinParseFunction parser =
-          op_resolver.GetOpDataParser(op_type);
-      if (parser == nullptr) {
-        TF_LITE_REPORT_ERROR(error_reporter_, "Did not find a parser for %s",
-                             EnumNameBuiltinOperator(op_type));
-
-        return kTfLiteError;
-      }
-      TF_LITE_ENSURE_STATUS(parser(op, error_reporter_, &builtin_data_allocator,
-                                   (void**)(&builtin_data)));
-    }
-
-    TfLiteIntArray* inputs_array;
-    TF_LITE_ENSURE_STATUS(internal::FlatBufferVectorToTfLiteTypeArray(
-        memory_allocator_, error_reporter_, op->inputs(), &inputs_array));
-
-    TfLiteIntArray* outputs_array;
-    TF_LITE_ENSURE_STATUS(internal::FlatBufferVectorToTfLiteTypeArray(
-        memory_allocator_, error_reporter_, op->outputs(), &outputs_array));
-
-    TfLiteNode* node = &(node_and_registrations[i].node);
-    *node = {};
-    node->inputs = inputs_array;
-    node->outputs = outputs_array;
-    node->builtin_data = reinterpret_cast<void*>(builtin_data);
-    node->custom_initial_data = custom_data;
-    node->custom_initial_data_size = custom_data_size;
+    subgraph_allocations[subgraph_idx].node_and_registrations = output;
   }
-
   return kTfLiteOk;
 }
-
 TfLiteTensor* MicroAllocator::AllocatePersistentTfLiteTensor(
-    const Model* model, TfLiteEvalTensor* eval_tensors, int tensor_index) {
-  const SubGraph* subgraph = GetSubGraphFromModel(model);
+    const Model* model, const SubgraphAllocations* subgraph_allocations,
+    int tensor_index, int subgraph_index) {
+  const SubGraph* subgraph = model->subgraphs()->Get(subgraph_index);
   TFLITE_DCHECK(subgraph != nullptr);
 
   // This value is allocated from persistent arena space. It is guaranteed to be
   // around for the lifetime of the application.
-  TfLiteTensor* tensor =
-      AllocatePersistentTfLiteTensorInternal(model, eval_tensors, tensor_index);
+  TfLiteTensor* tensor = AllocatePersistentTfLiteTensorInternal();
 
   // Populate any fields from the flatbuffer, since this TfLiteTensor struct is
   // allocated in the persistent section of the arena, ensure that additional
   // allocations also take place in that section of the arena.
-  if (PopulateTfLiteTensorFromFlatbuffer(model, subgraph, tensor, tensor_index,
-                                         /*allocate_temp=*/false) !=
-      kTfLiteOk) {
+  if (PopulateTfLiteTensorFromFlatbuffer(
+          model, tensor, tensor_index, subgraph_index,
+          /*allocate_temp=*/false) != kTfLiteOk) {
     TF_LITE_REPORT_ERROR(error_reporter_,
                          "Failed to populate a persistent TfLiteTensor struct "
                          "from flatbuffer data!");
     return nullptr;
   }
 
-  if (eval_tensors != nullptr) {
+  if (subgraph_allocations != nullptr) {
     // Tensor buffers that are allocated at runtime (e.g. non-weight buffers)
     // and not located in the flatbuffer are stored on the pre-allocated list of
     // TfLiteEvalTensors structs. These structs are the source of truth, simply
     // point the corresponding buffer to the new TfLiteTensor data value.
-    tensor->data.data = eval_tensors[tensor_index].data.data;
+    tensor->data.data =
+        subgraph_allocations[subgraph_index].tensors[tensor_index].data.data;
   }
   return tensor;
 }
 
 TfLiteTensor* MicroAllocator::AllocateTempTfLiteTensor(
-    const Model* model, TfLiteEvalTensor* eval_tensors, int tensor_index) {
-  const SubGraph* subgraph = GetSubGraphFromModel(model);
+    const Model* model, const SubgraphAllocations* subgraph_allocations,
+    int tensor_index, int subgraph_index) {
+  const SubGraph* subgraph = model->subgraphs()->Get(subgraph_index);
   TFLITE_DCHECK(subgraph != nullptr);
 
   // This value is allocated from temporary arena space. It is guaranteed to be
@@ -894,7 +826,8 @@
   // Populate any fields from the flatbuffer, since this TfLiteTensor struct is
   // allocated in the temp section of the arena, ensure that additional
   // allocations also take place in that section of the arena.
-  if (PopulateTfLiteTensorFromFlatbuffer(model, subgraph, tensor, tensor_index,
+  if (PopulateTfLiteTensorFromFlatbuffer(model, tensor, tensor_index,
+                                         subgraph_index,
                                          /*allocate_temp=*/true) != kTfLiteOk) {
     TF_LITE_REPORT_ERROR(
         error_reporter_,
@@ -902,12 +835,13 @@
     return nullptr;
   }
 
-  if (eval_tensors != nullptr) {
+  if (subgraph_allocations != nullptr) {
     // Tensor buffers that are allocated at runtime (e.g. non-weight buffers)
     // and not located in the flatbuffer are stored on the pre-allocated list of
     // TfLiteEvalTensors structs. These structs are the source of truth, simply
     // point the corresponding buffer to the new TfLiteTensor data value.
-    tensor->data.data = eval_tensors[tensor_index].data.data;
+    tensor->data.data =
+        subgraph_allocations[subgraph_index].tensors[tensor_index].data.data;
   }
   return tensor;
 }
@@ -917,38 +851,41 @@
 }
 
 TfLiteStatus MicroAllocator::AllocateTfLiteEvalTensors(
-    const Model* model, TfLiteEvalTensor** eval_tensors) {
-  TFLITE_DCHECK(eval_tensors != nullptr);
+    const Model* model, SubgraphAllocations* subgraph_allocations) {
+  TFLITE_DCHECK(subgraph_allocations != nullptr);
 
-  const SubGraph* subgraph = GetSubGraphFromModel(model);
-  TFLITE_DCHECK(subgraph != nullptr);
+  for (size_t subgraph_idx = 0; subgraph_idx < model->subgraphs()->size();
+       subgraph_idx++) {
+    const SubGraph* subgraph = model->subgraphs()->Get(subgraph_idx);
+    TFLITE_DCHECK(subgraph != nullptr);
 
-  size_t alloc_count = subgraph->tensors()->size();
-  TfLiteEvalTensor* tensors =
-      reinterpret_cast<TfLiteEvalTensor*>(memory_allocator_->AllocateFromTail(
-          sizeof(TfLiteEvalTensor) * alloc_count, alignof(TfLiteEvalTensor)));
-  if (tensors == nullptr) {
-    TF_LITE_REPORT_ERROR(error_reporter_,
-                         "Failed to allocate memory for context->eval_tensors, "
-                         "%d bytes required",
-                         sizeof(TfLiteEvalTensor) * alloc_count);
-    return kTfLiteError;
-  }
-
-  for (size_t i = 0; i < alloc_count; ++i) {
-    TfLiteStatus status = internal::InitializeTfLiteEvalTensorFromFlatbuffer(
-        memory_allocator_, *subgraph->tensors()->Get(i), model->buffers(),
-        error_reporter_, &tensors[i]);
-    if (status != kTfLiteOk) {
-      TF_LITE_REPORT_ERROR(error_reporter_, "Failed to initialize tensor %d",
-                           i);
+    size_t alloc_count = subgraph->tensors()->size();
+    TfLiteEvalTensor* tensors =
+        reinterpret_cast<TfLiteEvalTensor*>(memory_allocator_->AllocateFromTail(
+            sizeof(TfLiteEvalTensor) * alloc_count, alignof(TfLiteEvalTensor)));
+    if (tensors == nullptr) {
+      TF_LITE_REPORT_ERROR(
+          error_reporter_,
+          "Failed to allocate memory for context->eval_tensors, "
+          "%d bytes required",
+          sizeof(TfLiteEvalTensor) * alloc_count);
       return kTfLiteError;
     }
+
+    for (size_t i = 0; i < alloc_count; ++i) {
+      TfLiteStatus status = internal::InitializeTfLiteEvalTensorFromFlatbuffer(
+          memory_allocator_, *subgraph->tensors()->Get(i), model->buffers(),
+          error_reporter_, &tensors[i]);
+      if (status != kTfLiteOk) {
+        TF_LITE_REPORT_ERROR(error_reporter_, "Failed to initialize tensor %d",
+                             i);
+        return kTfLiteError;
+      }
+    }
+    subgraph_allocations[subgraph_idx].tensors = tensors;
   }
-  *eval_tensors = tensors;
   return kTfLiteOk;
 }
-
 TfLiteStatus MicroAllocator::AllocateVariables(const SubGraph* subgraph,
                                                TfLiteEvalTensor* eval_tensors) {
   for (size_t i = 0; i < subgraph->tensors()->size(); ++i) {
@@ -972,20 +909,20 @@
   return kTfLiteOk;
 }
 
-TfLiteTensor* MicroAllocator::AllocatePersistentTfLiteTensorInternal(
-    const Model* model, TfLiteEvalTensor* eval_tensors, int tensor_index) {
+TfLiteTensor* MicroAllocator::AllocatePersistentTfLiteTensorInternal() {
   return reinterpret_cast<TfLiteTensor*>(memory_allocator_->AllocateFromTail(
       sizeof(TfLiteTensor), alignof(TfLiteTensor)));
 }
 
 TfLiteStatus MicroAllocator::PopulateTfLiteTensorFromFlatbuffer(
-    const Model* model, const SubGraph* subgraph, TfLiteTensor* tensor,
-    int tensor_index, bool allocate_temp) {
+    const Model* model, TfLiteTensor* tensor, int tensor_index,
+    int subgraph_idx, bool allocate_temp) {
   // TODO(b/162311891): This method serves as a stub to ensure quantized
   // allocations in the tail can be recorded. Once the interpreter has APIs for
   // accessing buffers on TfLiteEvalTensor this method can be dropped.
   return internal::InitializeTfLiteTensorFromFlatbuffer(
-      memory_allocator_, allocate_temp, *subgraph->tensors()->Get(tensor_index),
+      memory_allocator_, allocate_temp,
+      *model->subgraphs()->Get(subgraph_idx)->tensors()->Get(tensor_index),
       model->buffers(), error_reporter_, tensor);
 }
 
@@ -993,20 +930,9 @@
   return error_reporter_;
 }
 
-const SubGraph* MicroAllocator::GetSubGraphFromModel(const Model* model) {
-  auto* subgraphs = model->subgraphs();
-  if (subgraphs->size() != 1) {
-    TF_LITE_REPORT_ERROR(error_reporter_,
-                         "Only 1 subgraph is currently supported.\n");
-    return nullptr;
-  }
-  return (*subgraphs)[0];
-}
-
 TfLiteStatus MicroAllocator::CommitStaticMemoryPlan(
-    const Model* model, const SubGraph* subgraph,
-    TfLiteEvalTensor* eval_tensors,
-    ScratchBufferHandle* scratch_buffer_handles) {
+    const Model* model, TfLiteEvalTensor* eval_tensors,
+    ScratchBufferHandle* scratch_buffer_handles, int subgraph_idx) {
   size_t head_usage = 0;
   // Create static memory plan
   // 1. Calculate AllocationInfo to know the lifetime of each tensor/buffer.
@@ -1018,6 +944,7 @@
   // allocated from the temp section and cleaned up at the bottom of this
   // function.
 
+  const SubGraph* subgraph = model->subgraphs()->Get(subgraph_idx);
   size_t allocation_info_count =
       subgraph->tensors()->size() + scratch_buffer_request_count_;
   size_t bytes = sizeof(AllocationInfo) * allocation_info_count;
@@ -1142,4 +1069,15 @@
                      alignof(internal::ScratchBufferRequest)));
 }
 
+TfLiteStatus MicroAllocator::FlatBufferVectorToTfLiteTypeArray(
+    const flatbuffers::Vector<int32_t>* flatbuffer_array,
+    TfLiteIntArray** result) {
+  return internal::FlatBufferVectorToTfLiteTypeArray(
+      memory_allocator_, error_reporter_, flatbuffer_array, result);
+}
+
+BuiltinDataAllocator* MicroAllocator::GetBuiltinDataAllocator() {
+  return builtin_data_allocator_;
+}
+
 }  // namespace tflite
diff --git a/tensorflow/lite/micro/micro_allocator.h b/tensorflow/lite/micro/micro_allocator.h
index 39a12ea..d64b35f 100644
--- a/tensorflow/lite/micro/micro_allocator.h
+++ b/tensorflow/lite/micro/micro_allocator.h
@@ -21,8 +21,8 @@
 #include "flatbuffers/flatbuffers.h"  // from @flatbuffers
 #include "tensorflow/lite/c/common.h"
 #include "tensorflow/lite/core/api/error_reporter.h"
+#include "tensorflow/lite/core/api/flatbuffer_conversions.h"
 #include "tensorflow/lite/micro/compatibility.h"
-#include "tensorflow/lite/micro/micro_op_resolver.h"
 #include "tensorflow/lite/micro/simple_memory_allocator.h"
 #include "tensorflow/lite/schema/schema_generated.h"
 
@@ -75,6 +75,13 @@
   uint8_t* data;
 } ScratchBufferHandle;
 
+// Stores all per-subgraph allocations. This includes the node and registration
+// array, tensor list and scratch buffer handles for each subgraph.
+typedef struct {
+  NodeAndRegistration* node_and_registrations;
+  TfLiteEvalTensor* tensors;
+} SubgraphAllocations;
+
 // Allocator responsible for allocating memory for all intermediate tensors
 // necessary to invoke a model.
 //
@@ -114,28 +121,31 @@
   static MicroAllocator* Create(SimpleMemoryAllocator* memory_allocator,
                                 ErrorReporter* error_reporter);
 
-  // Begin allocating internal resources required for model inference.
+  // Allocates internal resources required for model inference for each subgraph
+  // from the arena.
+  //
   // This method will run through the flatbuffer data supplied in the model to
   // properly allocate tensor, node, and op registration data. This method is
-  // expected to be followed with a call to FinishModelAllocation() before
-  // resuming allocation with another model. All persistent tensor buffers are
-  // stored in the out-param eval_tensors. This value is allocated from the
-  // persistent memory arena and will be used to host runtime tensor buffers.
-  TfLiteStatus StartModelAllocation(
-      const Model* model, const MicroOpResolver& op_resolver,
-      NodeAndRegistration** node_and_registrations,
-      TfLiteEvalTensor** eval_tensors);
+  // expected to be followed with a call to FinishModelAllocation()  Returns a
+  // pointer to an array of SubgraphAllocations (also stored in the tail of the
+  // arena) where each index corresponds to a different subgraph in the model.
+  // Return value is nullptr if the allocations failed.
+  SubgraphAllocations* StartModelAllocation(const Model* model);
 
   // Finish allocating internal resources required for model inference.
-  // This method will plan non-persistent buffers and commit a memory plan to
-  // the 'head' section of the memory arena. All variable tensor data will also
-  // be allocated. This method should be called after assigning model resources
-  // in StartModelAllocation(). The eval_tensors pointer should be the value
-  // passed into this class during StartModelAllocation(). Scratch buffer
-  // handles are stored in the out-param `scratch_buffer_handles`. This value
-  // will be used in `GetScratchBuffer` call to retrieve scratch buffers.
+  //
+  // -Plan the memory for activation tensors and scratch buffers.
+  // -Update eval tensors for each subgraph based on planned offsets.
+  // -Allocate scratch buffer handles array and update based on planned offsets.
+  //
+  // This method should be called after assigning model resources
+  // in StartModelAllocation(). The subgraph_allocations pointer should be the
+  // value passed into this class during StartModelAllocation(). Scratch buffer
+  // handles are stored in the out-param `scratch_buffer_handles` array which is
+  // allocated in this method. This value will be used in `GetScratchBuffer`
+  // call to retrieve scratch buffers.
   TfLiteStatus FinishModelAllocation(
-      const Model* model, TfLiteEvalTensor* eval_tensors,
+      const Model* model, SubgraphAllocations* subgraph_allocations,
       ScratchBufferHandle** scratch_buffer_handles);
 
   // Allocates a TfLiteTensor struct and populates the returned value with
@@ -145,17 +155,19 @@
   // class during StartModelAllocation() and contains the source-of-truth for
   // buffers.
   virtual TfLiteTensor* AllocatePersistentTfLiteTensor(
-      const Model* model, TfLiteEvalTensor* eval_tensors, int tensor_index);
+      const Model* model, const SubgraphAllocations* subgraph_allocations,
+      int tensor_index, int subgraph_index);
 
   // Allocates a TfLiteTensor struct and populates the returned value with
   // properties from the model flatbuffer. This struct is allocated from
   // temporary arena memory is only guaranteed until a call is made to
-  // ResetTempAllocations(). The eval_tensors pointer should be the value passed
-  // into this class during StartModelAllocation() and contains the
-  // source-of-truth for buffers.
-  virtual TfLiteTensor* AllocateTempTfLiteTensor(const Model* model,
-                                                 TfLiteEvalTensor* eval_tensors,
-                                                 int tensor_index);
+  // ResetTempAllocations(). Subgraph_allocaitons contains the array of
+  // TfLiteEvalTensors. If the newly allocated temp at the specified subgraph
+  // and tensor index is already present int the TfLiteEvalTensor array, its
+  // data buffer will be re-used.
+  virtual TfLiteTensor* AllocateTempTfLiteTensor(
+      const Model* model, const SubgraphAllocations* subgraph_allocations,
+      int tensor_index, int subgraph_index);
 
   // Resets all temporary allocations. This method should be called after a
   // chain of temp allocations (e.g. chain of TfLiteTensor objects via
@@ -171,7 +183,8 @@
   // This method only requests a buffer with a given size to be used after a
   // model has finished allocation via FinishModelAllocation(). All requested
   // buffers will be accessible by the out-param in that method.
-  TfLiteStatus RequestScratchBufferInArena(size_t bytes, int* buffer_idx);
+  TfLiteStatus RequestScratchBufferInArena(size_t bytes, int subgraph_idx,
+                                           int* buffer_idx);
 
   // Finish allocating a specific NodeAndRegistration prepare block (kernel
   // entry for a model) with a given node ID. This call ensures that any scratch
@@ -183,6 +196,14 @@
   // `FinishModelAllocation`. Otherwise, it will return 0.
   size_t used_bytes() const;
 
+  // Converts a flatbuffer int32_t array to a TfLiteIntArray, accounting for
+  // endiannes.
+  TfLiteStatus FlatBufferVectorToTfLiteTypeArray(
+      const flatbuffers::Vector<int32_t>* flatbuffer_array,
+      TfLiteIntArray** result);
+
+  BuiltinDataAllocator* GetBuiltinDataAllocator();
+
  protected:
   MicroAllocator(SimpleMemoryAllocator* memory_allocator,
                  ErrorReporter* error_reporter);
@@ -192,23 +213,13 @@
   // registration pointers required to represent the inference graph of the
   // model.
   virtual TfLiteStatus AllocateNodeAndRegistrations(
-      const Model* model, NodeAndRegistration** node_and_registrations);
-
-  // Populates node and registration pointers representing the inference graph
-  // of the model from values inside the flatbuffer (loaded from the TfLiteModel
-  // instance). Persistent data (e.g. operator data) is allocated from the
-  // arena.
-  virtual TfLiteStatus PrepareNodeAndRegistrationDataFromFlatbuffer(
-      const Model* model, const MicroOpResolver& op_resolver,
-      NodeAndRegistration* node_and_registrations);
+      const Model* model, SubgraphAllocations* subgraph_allocations);
 
   // Allocates the list of persistent TfLiteEvalTensors that are used for the
   // "eval" phase of model inference. These structs will be the source of truth
-  // for all tensor buffers. Allocation results are stored in the out-param
-  // eval_tensors.
+  // for all tensor buffers.
   virtual TfLiteStatus AllocateTfLiteEvalTensors(
-      const Model* model, TfLiteEvalTensor** eval_tensors);
-
+      const Model* model, SubgraphAllocations* subgraph_allocations);
   // Allocates persistent tensor buffers for variable tensors in the subgraph.
   virtual TfLiteStatus AllocateVariables(const SubGraph* subgraph,
                                          TfLiteEvalTensor* eval_tensors);
@@ -216,21 +227,19 @@
   // Allocate and return a persistent TfLiteTensor.
   // TODO(b/162311891): Drop this method when the interpreter has an API for
   // accessing TfLiteEvalTensor structs.
-  virtual TfLiteTensor* AllocatePersistentTfLiteTensorInternal(
-      const Model* model, TfLiteEvalTensor* eval_tensors, int tensor_index);
+  virtual TfLiteTensor* AllocatePersistentTfLiteTensorInternal();
 
   // Populates a TfLiteTensor struct with data from the model flatbuffer. Any
   // quantization data is allocated from either the tail (persistent) or temp
   // sections of the arena based on the allocation flag.
-  virtual TfLiteStatus PopulateTfLiteTensorFromFlatbuffer(
-      const Model* model, const SubGraph* subgraph, TfLiteTensor* tensor,
-      int tensor_index, bool allocate_temp);
+  virtual TfLiteStatus PopulateTfLiteTensorFromFlatbuffer(const Model* model,
+                                                          TfLiteTensor* tensor,
+                                                          int tensor_index,
+                                                          int subgraph_idx,
+                                                          bool allocate_temp);
 
   ErrorReporter* error_reporter() const;
 
-  // Returns the first subgraph from the model.
-  const SubGraph* GetSubGraphFromModel(const Model* model);
-
  private:
   // Commits a memory plan for all non-persistent buffer allocations in the
   // 'head' section of the memory arena. The eval_tensors pointer is the list of
@@ -240,9 +249,8 @@
   // ScratchBufferHandle structs that will point to allocated buffers also in
   // the head section.
   virtual TfLiteStatus CommitStaticMemoryPlan(
-      const Model* model, const SubGraph* subgraph,
-      TfLiteEvalTensor* eval_tensors,
-      ScratchBufferHandle* scratch_buffer_handles);
+      const Model* model, TfLiteEvalTensor* eval_tensors,
+      ScratchBufferHandle* scratch_buffer_handles, int subgraph_idx);
 
   // Allocates an array of ScratchBufferHandle structs in the tail section for a
   // given number of handles.
@@ -261,6 +269,9 @@
   // A simple memory allocator that always allocate from the arena tail or head.
   SimpleMemoryAllocator* memory_allocator_;
 
+  // Allocator used to allocate persistent builtin data.
+  BuiltinDataAllocator* builtin_data_allocator_;
+
   ErrorReporter* error_reporter_;
   bool model_is_allocating_;
 
diff --git a/tensorflow/lite/micro/micro_allocator_test.cc b/tensorflow/lite/micro/micro_allocator_test.cc
index 53bc55f..1c856ef 100644
--- a/tensorflow/lite/micro/micro_allocator_test.cc
+++ b/tensorflow/lite/micro/micro_allocator_test.cc
@@ -17,6 +17,7 @@
 
 #include <cstdint>
 
+#include "tensorflow/lite/c/common.h"
 #include "tensorflow/lite/micro/memory_helpers.h"
 #include "tensorflow/lite/micro/micro_error_reporter.h"
 #include "tensorflow/lite/micro/simple_memory_allocator.h"
@@ -82,19 +83,29 @@
 }
 
 void VerifyMockTensor(const Model* model, MicroAllocator* allocator,
-                      TfLiteEvalTensor* eval_tensors, int tensor_idx,
+                      SubgraphAllocations* subgraph_allocations, int tensor_idx,
                       bool is_variable = false) {
-  VerifyMockTfLiteTensor(allocator->AllocatePersistentTfLiteTensor(
-                             model, eval_tensors, tensor_idx),
-                         is_variable);
-  VerifyMockTfLiteEvalTensor(&eval_tensors[tensor_idx]);
+  for (size_t subgraph_idx = 0; subgraph_idx < model->subgraphs()->size();
+       subgraph_idx++) {
+    VerifyMockTfLiteTensor(
+        allocator->AllocatePersistentTfLiteTensor(model, subgraph_allocations,
+                                                  tensor_idx, subgraph_idx),
+        is_variable);
+    VerifyMockTfLiteEvalTensor(
+        &subgraph_allocations[subgraph_idx].tensors[tensor_idx]);
+  }
 }
 
 void VerifyMockWeightTensor(const Model* model, MicroAllocator* allocator,
-                            TfLiteEvalTensor* eval_tensors, int tensor_idx) {
-  VerifyMockWeightTfLiteTensor(allocator->AllocatePersistentTfLiteTensor(
-      model, eval_tensors, tensor_idx));
-  VerifyMockWeightTfLiteEvalTensor(&eval_tensors[tensor_idx]);
+                            SubgraphAllocations* subgraph_allocations,
+                            int tensor_idx) {
+  for (size_t subgraph_idx = 0; subgraph_idx < model->subgraphs()->size();
+       subgraph_idx++) {
+    VerifyMockWeightTfLiteTensor(allocator->AllocatePersistentTfLiteTensor(
+        model, subgraph_allocations, tensor_idx, subgraph_idx));
+    VerifyMockWeightTfLiteEvalTensor(
+        &subgraph_allocations[subgraph_idx].tensors[tensor_idx]);
+  }
 }
 
 void EnsureUniqueVariableTensorBuffer(const Model* model,
@@ -109,11 +120,14 @@
 }
 
 void VerifyRegistrationAndNodeAllocation(
-    NodeAndRegistration* node_and_registration, size_t count) {
-  for (size_t i = 0; i < count; i++) {
-    TF_LITE_MICRO_EXPECT_NE(nullptr, node_and_registration[i].registration);
-    TF_LITE_MICRO_EXPECT_NE(nullptr, node_and_registration[i].node.inputs);
-    TF_LITE_MICRO_EXPECT_NE(nullptr, node_and_registration[i].node.outputs);
+    SubgraphAllocations* subgraph_allocations, size_t count,
+    int num_subgraphs) {
+  for (int subgraph_idx = 0; subgraph_idx < num_subgraphs; subgraph_idx++) {
+    for (size_t i = 0; i < count; i++) {
+      TF_LITE_MICRO_EXPECT_NE(nullptr, &subgraph_allocations[subgraph_idx]
+                                            .node_and_registrations[i]
+                                            .registration);
+    }
   }
 }
 
@@ -236,30 +250,21 @@
 
 TF_LITE_MICRO_TEST(TestFailsWhenModelStartsTwice) {
   const tflite::Model* model = tflite::testing::GetSimpleMockModel();
-  TfLiteEvalTensor* eval_tensors = nullptr;
   tflite::AllOpsResolver op_resolver = tflite::testing::GetOpResolver();
-  tflite::NodeAndRegistration* node_and_registration;
   constexpr size_t arena_size = 1024;
   uint8_t arena[arena_size];
   tflite::MicroAllocator* allocator = tflite::MicroAllocator::Create(
       arena, arena_size, tflite::GetMicroErrorReporter());
   TF_LITE_MICRO_EXPECT(nullptr != allocator);
-  TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteOk,
-      allocator->StartModelAllocation(model, op_resolver,
-                                      &node_and_registration, &eval_tensors));
-  TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteError,
-      allocator->StartModelAllocation(model, op_resolver,
-                                      &node_and_registration, &eval_tensors));
+  TF_LITE_MICRO_EXPECT_NE(nullptr, allocator->StartModelAllocation(model));
+  TF_LITE_MICRO_EXPECT(nullptr == allocator->StartModelAllocation(model));
 }
 
 TF_LITE_MICRO_TEST(TestFailsWithWrongSequence) {
   const tflite::Model* model = tflite::testing::GetSimpleMockModel();
-  TfLiteEvalTensor* eval_tensors = nullptr;
   tflite::ScratchBufferHandle* scratch_buffer_handles = nullptr;
   tflite::AllOpsResolver op_resolver = tflite::testing::GetOpResolver();
-  tflite::NodeAndRegistration* node_and_registration;
+  tflite::SubgraphAllocations* subgraph_allocations = nullptr;
   constexpr size_t arena_size = 1024;
   uint8_t arena[arena_size];
   tflite::MicroAllocator* allocator = tflite::MicroAllocator::Create(
@@ -268,47 +273,40 @@
 
   // We can't finish allocation before it ever got started.
   TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteError, allocator->FinishModelAllocation(model, eval_tensors,
-                                                     &scratch_buffer_handles));
+      kTfLiteError, allocator->FinishModelAllocation(
+                        model, subgraph_allocations, &scratch_buffer_handles));
 
   // Start twice is not allowed.
-  TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteOk,
-      allocator->StartModelAllocation(model, op_resolver,
-                                      &node_and_registration, &eval_tensors));
-  TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteError,
-      allocator->StartModelAllocation(model, op_resolver,
-                                      &node_and_registration, &eval_tensors));
+  TF_LITE_MICRO_EXPECT(nullptr != allocator->StartModelAllocation(model));
+  TF_LITE_MICRO_EXPECT(nullptr == allocator->StartModelAllocation(model));
 }
 
 TF_LITE_MICRO_TEST(TestMockModelAllocation) {
   const tflite::Model* model = tflite::testing::GetSimpleMockModel();
-  TfLiteEvalTensor* eval_tensors = nullptr;
   tflite::ScratchBufferHandle* scratch_buffer_handles = nullptr;
   tflite::AllOpsResolver op_resolver = tflite::testing::GetOpResolver();
-  tflite::NodeAndRegistration* node_and_registration;
   constexpr size_t arena_size = 1024;
   uint8_t arena[arena_size];
   tflite::MicroAllocator* allocator = tflite::MicroAllocator::Create(
       arena, arena_size, tflite::GetMicroErrorReporter());
   TF_LITE_MICRO_EXPECT(nullptr != allocator);
+  tflite::SubgraphAllocations* subgraph_allocations =
+      allocator->StartModelAllocation(model);
+  TF_LITE_MICRO_EXPECT(nullptr != subgraph_allocations);
   TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteOk,
-      allocator->StartModelAllocation(model, op_resolver,
-                                      &node_and_registration, &eval_tensors));
-  TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteOk, allocator->FinishModelAllocation(model, eval_tensors,
+      kTfLiteOk, allocator->FinishModelAllocation(model, subgraph_allocations,
                                                   &scratch_buffer_handles));
 
   size_t model_tensor_size = tflite::testing::GetModelTensorCount(model);
   TF_LITE_MICRO_EXPECT_EQ(static_cast<size_t>(4), model_tensor_size);
 
-  tflite::testing::VerifyMockTensor(model, allocator, eval_tensors, 0);
-  tflite::testing::VerifyMockWeightTensor(model, allocator, eval_tensors, 1);
-  tflite::testing::VerifyMockTensor(model, allocator, eval_tensors, 2);
-  tflite::testing::VerifyMockTensor(model, allocator, eval_tensors, 3);
+  tflite::testing::VerifyMockTensor(model, allocator, subgraph_allocations, 0);
+  tflite::testing::VerifyMockWeightTensor(model, allocator,
+                                          subgraph_allocations, 1);
+  tflite::testing::VerifyMockTensor(model, allocator, subgraph_allocations, 2);
+  tflite::testing::VerifyMockTensor(model, allocator, subgraph_allocations, 3);
 
+  TfLiteEvalTensor* eval_tensors = subgraph_allocations[0].tensors;
   TF_LITE_MICRO_EXPECT_NE(eval_tensors[1].data.raw, eval_tensors[0].data.raw);
   TF_LITE_MICRO_EXPECT_NE(eval_tensors[2].data.raw, eval_tensors[0].data.raw);
   TF_LITE_MICRO_EXPECT_NE(eval_tensors[1].data.raw, eval_tensors[2].data.raw);
@@ -318,8 +316,9 @@
   TF_LITE_MICRO_EXPECT_LE(allocator->used_bytes(), 856 + 100);
 
   // SimpleMockModel has 2 operators:
-  tflite::testing::VerifyRegistrationAndNodeAllocation(node_and_registration,
-                                                       /*count=*/2);
+  tflite::testing::VerifyRegistrationAndNodeAllocation(subgraph_allocations,
+                                                       /*count=*/2,
+                                                       /*num_subgraphs=*/1);
 }
 
 TF_LITE_MICRO_TEST(TestMultiTenantAllocation) {
@@ -333,31 +332,26 @@
   tflite::MicroAllocator* allocator = tflite::MicroAllocator::Create(
       arena, arena_size, tflite::GetMicroErrorReporter());
   TF_LITE_MICRO_EXPECT_NE(nullptr, allocator);
-  TfLiteEvalTensor* eval_tensors = nullptr;
   tflite::ScratchBufferHandle* scratch_buffer_handles = nullptr;
 
   // Allocate for model 1. We use ComplexMockModel here to cover the code path
   // allocatig variables.
   const tflite::Model* model1 = tflite::testing::GetComplexMockModel();
-  tflite::NodeAndRegistration* node_and_registration1;
+  tflite::SubgraphAllocations* subgraph_allocations1 =
+      allocator->StartModelAllocation(model1);
+  TF_LITE_MICRO_EXPECT(nullptr != subgraph_allocations1);
   TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteOk,
-      allocator->StartModelAllocation(model1, op_resolver,
-                                      &node_and_registration1, &eval_tensors));
-  TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteOk, allocator->FinishModelAllocation(model1, eval_tensors,
+      kTfLiteOk, allocator->FinishModelAllocation(model1, subgraph_allocations1,
                                                   &scratch_buffer_handles));
   const size_t single_model_used_bytes = allocator->used_bytes();
 
   // Allocate for model 2.
   const tflite::Model* model2 = tflite::testing::GetComplexMockModel();
-  tflite::NodeAndRegistration* node_and_registration2;
+  tflite::SubgraphAllocations* subgraph_allocations2 =
+      allocator->StartModelAllocation(model2);
+  TF_LITE_MICRO_EXPECT(nullptr != subgraph_allocations2);
   TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteOk,
-      allocator->StartModelAllocation(model2, op_resolver,
-                                      &node_and_registration2, &eval_tensors));
-  TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteOk, allocator->FinishModelAllocation(model2, eval_tensors,
+      kTfLiteOk, allocator->FinishModelAllocation(model2, subgraph_allocations2,
                                                   &scratch_buffer_handles));
 
   // Allocation for two instances of the same model takes less memory as `head`
@@ -367,90 +361,97 @@
 
 TF_LITE_MICRO_TEST(TestAllocationForModelsWithBranches) {
   const tflite::Model* model = tflite::testing::GetSimpleModelWithBranch();
-  TfLiteEvalTensor* eval_tensors = nullptr;
   tflite::ScratchBufferHandle* scratch_buffer_handles = nullptr;
   tflite::AllOpsResolver op_resolver = tflite::testing::GetOpResolver();
-  tflite::NodeAndRegistration* node_and_registration;
   constexpr size_t arena_size = 4096;
   uint8_t arena[arena_size];
   tflite::MicroAllocator* allocator = tflite::MicroAllocator::Create(
       arena, arena_size, tflite::GetMicroErrorReporter());
   TF_LITE_MICRO_EXPECT_NE(nullptr, allocator);
+  tflite::SubgraphAllocations* subgraph_allocations =
+      allocator->StartModelAllocation(model);
+  TF_LITE_MICRO_EXPECT(nullptr != subgraph_allocations);
   TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteOk,
-      allocator->StartModelAllocation(model, op_resolver,
-                                      &node_and_registration, &eval_tensors));
-  TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteOk, allocator->FinishModelAllocation(model, eval_tensors,
+      kTfLiteOk, allocator->FinishModelAllocation(model, subgraph_allocations,
                                                   &scratch_buffer_handles));
 
-  uint8_t* start = eval_tensors[0].data.uint8;
+  uint8_t* start = subgraph_allocations[0].tensors[0].data.uint8;
   // Check test_helpers.cc BuildSimpleModelWithBranch for model structure.
   // t0 is the first tensor, so place it in offset 0.
-  TF_LITE_MICRO_EXPECT_EQ(0, eval_tensors[0].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      0, subgraph_allocations[0].tensors[0].data.uint8 - start);
   // bytes = 2 * 2 * 3 * sizeof(float32) = 48, same for other tensors.
   size_t buffer_size;
-  TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, tflite::TfLiteEvalTensorByteLength(
-                                         &eval_tensors[0], &buffer_size));
+  TF_LITE_MICRO_EXPECT_EQ(
+      kTfLiteOk, tflite::TfLiteEvalTensorByteLength(
+                     &subgraph_allocations[0].tensors[0], &buffer_size));
   TF_LITE_MICRO_EXPECT_EQ(static_cast<size_t>(48), buffer_size);
   // t1 can't reuse any memory, as n0 requires both t0 and t1.
-  TF_LITE_MICRO_EXPECT_EQ(96, eval_tensors[1].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      96, subgraph_allocations[0].tensors[1].data.uint8 - start);
   // t2 can't reuse any memory, as n1 requires both t0 and t2. Also n2 requires
   // both t1 and t2.
-  TF_LITE_MICRO_EXPECT_EQ(48, eval_tensors[2].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      48, subgraph_allocations[0].tensors[2].data.uint8 - start);
   // t3 reuses the same memory from t0 as t0 is not an input to any node.
-  TF_LITE_MICRO_EXPECT_EQ(0, eval_tensors[3].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      0, subgraph_allocations[0].tensors[3].data.uint8 - start);
 
   // SimpleModelWithBranch has 3 operators:
-  tflite::testing::VerifyRegistrationAndNodeAllocation(node_and_registration,
-                                                       /*count=*/3);
+  tflite::testing::VerifyRegistrationAndNodeAllocation(subgraph_allocations,
+                                                       /*count=*/3,
+                                                       /*num_subgraphs=*/1);
 }
 
 TF_LITE_MICRO_TEST(TestAllocationForComplexModelAllocation) {
   const tflite::Model* model = tflite::testing::GetComplexMockModel();
-  TfLiteEvalTensor* eval_tensors = nullptr;
   tflite::ScratchBufferHandle* scratch_buffer_handles = nullptr;
   tflite::AllOpsResolver op_resolver = tflite::testing::GetOpResolver();
-  tflite::NodeAndRegistration* node_and_registration;
   constexpr size_t arena_size = 2048;
   uint8_t arena[arena_size];
   tflite::MicroAllocator* allocator = tflite::MicroAllocator::Create(
       arena, arena_size, tflite::GetMicroErrorReporter());
   TF_LITE_MICRO_EXPECT(nullptr != allocator);
+  tflite::SubgraphAllocations* subgraph_allocations =
+      allocator->StartModelAllocation(model);
+  TF_LITE_MICRO_EXPECT(nullptr != subgraph_allocations);
   TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteOk,
-      allocator->StartModelAllocation(model, op_resolver,
-                                      &node_and_registration, &eval_tensors));
-  TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteOk, allocator->FinishModelAllocation(model, eval_tensors,
+      kTfLiteOk, allocator->FinishModelAllocation(model, subgraph_allocations,
                                                   &scratch_buffer_handles));
 
   size_t model_tensor_size = tflite::testing::GetModelTensorCount(model);
   TF_LITE_MICRO_EXPECT_EQ(static_cast<size_t>(10), model_tensor_size);
 
   // NOTE: Tensor indexes match the values in GetComplexMockModel().
-  tflite::testing::VerifyMockTensor(model, allocator, eval_tensors, 0);
-  tflite::testing::VerifyMockTensor(model, allocator, eval_tensors, 1,
+  tflite::testing::VerifyMockTensor(model, allocator, subgraph_allocations, 0);
+  tflite::testing::VerifyMockTensor(model, allocator, subgraph_allocations, 1,
                                     /*is_variable=*/true);
-  tflite::testing::VerifyMockWeightTensor(model, allocator, eval_tensors, 2);
-  tflite::testing::VerifyMockTensor(model, allocator, eval_tensors, 3);
-  tflite::testing::VerifyMockTensor(model, allocator, eval_tensors, 4,
+  tflite::testing::VerifyMockWeightTensor(model, allocator,
+                                          subgraph_allocations, 2);
+  tflite::testing::VerifyMockTensor(model, allocator, subgraph_allocations, 3);
+  tflite::testing::VerifyMockTensor(model, allocator, subgraph_allocations, 4,
                                     /*is_variable=*/true);
-  tflite::testing::VerifyMockWeightTensor(model, allocator, eval_tensors, 5);
-  tflite::testing::VerifyMockTensor(model, allocator, eval_tensors, 6);
-  tflite::testing::VerifyMockTensor(model, allocator, eval_tensors, 7,
+  tflite::testing::VerifyMockWeightTensor(model, allocator,
+                                          subgraph_allocations, 5);
+  tflite::testing::VerifyMockTensor(model, allocator, subgraph_allocations, 6);
+  tflite::testing::VerifyMockTensor(model, allocator, subgraph_allocations, 7,
                                     /*is_variable=*/true);
-  tflite::testing::VerifyMockWeightTensor(model, allocator, eval_tensors, 8);
-  tflite::testing::VerifyMockTensor(model, allocator, eval_tensors, 9);
+  tflite::testing::VerifyMockWeightTensor(model, allocator,
+                                          subgraph_allocations, 8);
+  tflite::testing::VerifyMockTensor(model, allocator, subgraph_allocations, 9);
 
   // // Ensure that variable tensors have unique address
-  tflite::testing::EnsureUniqueVariableTensorBuffer(model, eval_tensors, 1);
-  tflite::testing::EnsureUniqueVariableTensorBuffer(model, eval_tensors, 4);
-  tflite::testing::EnsureUniqueVariableTensorBuffer(model, eval_tensors, 7);
+  tflite::testing::EnsureUniqueVariableTensorBuffer(
+      model, subgraph_allocations[0].tensors, 1);
+  tflite::testing::EnsureUniqueVariableTensorBuffer(
+      model, subgraph_allocations[0].tensors, 4);
+  tflite::testing::EnsureUniqueVariableTensorBuffer(
+      model, subgraph_allocations[0].tensors, 7);
 
   // ComplexMockModel has 3 operators:
-  tflite::testing::VerifyRegistrationAndNodeAllocation(node_and_registration,
-                                                       /*count=*/3);
+  tflite::testing::VerifyRegistrationAndNodeAllocation(subgraph_allocations,
+                                                       /*count=*/3,
+                                                       /*num_subgraphs=*/1);
 }
 
 TF_LITE_MICRO_TEST(OfflinePlannerBranchesAllOnline) {
@@ -458,7 +459,6 @@
   int subgraph = 0;
   constexpr int number_tensors = 4;
   tflite::AllOpsResolver op_resolver = tflite::testing::GetOpResolver();
-  tflite::NodeAndRegistration* node_and_registration;
   const int32_t metadata_buffer[tflite::testing::kOfflinePlannerHeaderSize +
                                 number_tensors] = {version, subgraph,
                                                    number_tensors,  // header
@@ -484,7 +484,6 @@
   const tflite::Model* model = tflite::testing::GetModelWithOfflinePlanning(
       number_tensors, metadata_buffer, node_list, number_connections);
 
-  TfLiteEvalTensor* eval_tensors = nullptr;
   tflite::ScratchBufferHandle* scratch_buffer_handles = nullptr;
 
   constexpr size_t arena_size = 4096;
@@ -492,33 +491,36 @@
   tflite::MicroAllocator* allocator = tflite::MicroAllocator::Create(
       arena, arena_size, tflite::GetMicroErrorReporter());
 
+  tflite::SubgraphAllocations* subgraph_allocations =
+      allocator->StartModelAllocation(model);
+  TF_LITE_MICRO_EXPECT(nullptr != subgraph_allocations);
   TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteOk,
-      allocator->StartModelAllocation(model, op_resolver,
-                                      &node_and_registration, &eval_tensors));
-  TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteOk, allocator->FinishModelAllocation(model, eval_tensors,
+      kTfLiteOk, allocator->FinishModelAllocation(model, subgraph_allocations,
                                                   &scratch_buffer_handles));
 
   // Since all of the tensors are online planned and the model structure is
   // identical to that in TestAllocationForModelsWithBranches,
   // the offsets be should identical to that test.
-  uint8_t* start = eval_tensors[0].data.uint8;
-  TF_LITE_MICRO_EXPECT_EQ(0, eval_tensors[0].data.uint8 - start);
+  uint8_t* start = subgraph_allocations[0].tensors[0].data.uint8;
+  TF_LITE_MICRO_EXPECT_EQ(
+      0, subgraph_allocations[0].tensors[0].data.uint8 - start);
 
   size_t buffer_size;
-  TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, tflite::TfLiteEvalTensorByteLength(
-                                         &eval_tensors[0], &buffer_size));
+  TF_LITE_MICRO_EXPECT_EQ(
+      kTfLiteOk, tflite::TfLiteEvalTensorByteLength(
+                     &subgraph_allocations[0].tensors[0], &buffer_size));
   TF_LITE_MICRO_EXPECT_EQ(static_cast<size_t>(48), buffer_size);
-  TF_LITE_MICRO_EXPECT_EQ(96, eval_tensors[1].data.uint8 - start);
-  TF_LITE_MICRO_EXPECT_EQ(48, eval_tensors[2].data.uint8 - start);
-  TF_LITE_MICRO_EXPECT_EQ(0, eval_tensors[3].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      96, subgraph_allocations[0].tensors[1].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      48, subgraph_allocations[0].tensors[2].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      0, subgraph_allocations[0].tensors[3].data.uint8 - start);
 }
 
 TF_LITE_MICRO_TEST(OfflinePlannerBasic) {
   constexpr int number_tensors = 4;
   tflite::AllOpsResolver op_resolver = tflite::testing::GetOpResolver();
-  tflite::NodeAndRegistration* node_and_registration;
   const int32_t metadata_buffer[tflite::testing::kOfflinePlannerHeaderSize +
                                 number_tensors] = {1,         0, number_tensors,
                                                    /*t0=*/0,
@@ -537,32 +539,33 @@
   const tflite::Model* model = tflite::testing::GetModelWithOfflinePlanning(
       number_tensors, metadata_buffer, node_list, number_connections);
 
-  TfLiteEvalTensor* eval_tensors = nullptr;
   tflite::ScratchBufferHandle* scratch_buffer_handles = nullptr;
   constexpr size_t arena_size = 4096;
   uint8_t arena[arena_size];
   tflite::MicroAllocator* allocator = tflite::MicroAllocator::Create(
       arena, arena_size, tflite::GetMicroErrorReporter());
 
+  tflite::SubgraphAllocations* subgraph_allocations =
+      allocator->StartModelAllocation(model);
+  TF_LITE_MICRO_EXPECT(nullptr != subgraph_allocations);
   TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteOk,
-      allocator->StartModelAllocation(model, op_resolver,
-                                      &node_and_registration, &eval_tensors));
-  TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteOk, allocator->FinishModelAllocation(model, eval_tensors,
+      kTfLiteOk, allocator->FinishModelAllocation(model, subgraph_allocations,
                                                   &scratch_buffer_handles));
 
-  uint8_t* start = eval_tensors[0].data.uint8;
-  TF_LITE_MICRO_EXPECT_EQ(0, eval_tensors[0].data.uint8 - start);
-  TF_LITE_MICRO_EXPECT_EQ(48, eval_tensors[1].data.uint8 - start);
-  TF_LITE_MICRO_EXPECT_EQ(0, eval_tensors[2].data.uint8 - start);
-  TF_LITE_MICRO_EXPECT_EQ(48, eval_tensors[3].data.uint8 - start);
+  uint8_t* start = subgraph_allocations[0].tensors[0].data.uint8;
+  TF_LITE_MICRO_EXPECT_EQ(
+      0, subgraph_allocations[0].tensors[0].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      48, subgraph_allocations[0].tensors[1].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      0, subgraph_allocations[0].tensors[2].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      48, subgraph_allocations[0].tensors[3].data.uint8 - start);
 }
 
 TF_LITE_MICRO_TEST(OfflinePlannerOverlappingAllocation) {
   constexpr int number_tensors = 4;
   tflite::AllOpsResolver op_resolver = tflite::testing::GetOpResolver();
-  tflite::NodeAndRegistration* node_and_registration;
   const int32_t metadata_buffer[tflite::testing::kOfflinePlannerHeaderSize +
                                 number_tensors] = {/*version=*/1,
                                                    /*subgraph=*/0,
@@ -583,33 +586,34 @@
   const tflite::Model* model = tflite::testing::GetModelWithOfflinePlanning(
       number_tensors, metadata_buffer, node_list, number_connections);
 
-  TfLiteEvalTensor* eval_tensors = nullptr;
   tflite::ScratchBufferHandle* scratch_buffer_handles = nullptr;
   constexpr size_t arena_size = 4096;
   uint8_t arena[arena_size];
   tflite::MicroAllocator* allocator = tflite::MicroAllocator::Create(
       arena, arena_size, tflite::GetMicroErrorReporter());
 
+  tflite::SubgraphAllocations* subgraph_allocations =
+      allocator->StartModelAllocation(model);
+  TF_LITE_MICRO_EXPECT(nullptr != subgraph_allocations);
   TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteOk,
-      allocator->StartModelAllocation(model, op_resolver,
-                                      &node_and_registration, &eval_tensors));
-  TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteOk, allocator->FinishModelAllocation(model, eval_tensors,
+      kTfLiteOk, allocator->FinishModelAllocation(model, subgraph_allocations,
                                                   &scratch_buffer_handles));
 
-  uint8_t* start = eval_tensors[0].data.uint8;
-  TF_LITE_MICRO_EXPECT_EQ(0, eval_tensors[0].data.uint8 - start);
-  TF_LITE_MICRO_EXPECT_EQ(0, eval_tensors[1].data.uint8 - start);
-  TF_LITE_MICRO_EXPECT_EQ(48, eval_tensors[2].data.uint8 - start);
-  TF_LITE_MICRO_EXPECT_EQ(0, eval_tensors[3].data.uint8 - start);
+  uint8_t* start = subgraph_allocations[0].tensors[0].data.uint8;
+  TF_LITE_MICRO_EXPECT_EQ(
+      0, subgraph_allocations[0].tensors[0].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      0, subgraph_allocations[0].tensors[1].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      48, subgraph_allocations[0].tensors[2].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      0, subgraph_allocations[0].tensors[3].data.uint8 - start);
   // TF_LITE_MICRO_EXPECT_EQ(static_cast<size_t>(48), context.tensors[0].bytes);
 }
 
 TF_LITE_MICRO_TEST(OfflinePlannerOfflineOnline) {
   constexpr int number_tensors = 5;
   tflite::AllOpsResolver op_resolver = tflite::testing::GetOpResolver();
-  tflite::NodeAndRegistration* node_and_registration;
   const int32_t metadata_buffer[tflite::testing::kOfflinePlannerHeaderSize +
                                 number_tensors] = {/*version=*/1,
                                                    /*subgraph=*/0,
@@ -635,27 +639,30 @@
   const tflite::Model* model = tflite::testing::GetModelWithOfflinePlanning(
       number_tensors, metadata_buffer, node_list, number_connections);
 
-  TfLiteEvalTensor* eval_tensors = nullptr;
   tflite::ScratchBufferHandle* scratch_buffer_handles = nullptr;
   constexpr size_t arena_size = 4096;
   uint8_t arena[arena_size];
   tflite::MicroAllocator* allocator = tflite::MicroAllocator::Create(
       arena, arena_size, tflite::GetMicroErrorReporter());
 
+  tflite::SubgraphAllocations* subgraph_allocations =
+      allocator->StartModelAllocation(model);
+  TF_LITE_MICRO_EXPECT(nullptr != subgraph_allocations);
   TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteOk,
-      allocator->StartModelAllocation(model, op_resolver,
-                                      &node_and_registration, &eval_tensors));
-  TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteOk, allocator->FinishModelAllocation(model, eval_tensors,
+      kTfLiteOk, allocator->FinishModelAllocation(model, subgraph_allocations,
                                                   &scratch_buffer_handles));
 
-  uint8_t* start = eval_tensors[0].data.uint8;
-  TF_LITE_MICRO_EXPECT_EQ(0, eval_tensors[0].data.uint8 - start);
-  TF_LITE_MICRO_EXPECT_EQ(48, eval_tensors[1].data.uint8 - start);
-  TF_LITE_MICRO_EXPECT_EQ(96, eval_tensors[2].data.uint8 - start);
-  TF_LITE_MICRO_EXPECT_EQ(48, eval_tensors[4].data.uint8 - start);
-  TF_LITE_MICRO_EXPECT_EQ(0, eval_tensors[3].data.uint8 - start);
+  uint8_t* start = subgraph_allocations[0].tensors[0].data.uint8;
+  TF_LITE_MICRO_EXPECT_EQ(
+      0, subgraph_allocations[0].tensors[0].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      48, subgraph_allocations[0].tensors[1].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      96, subgraph_allocations[0].tensors[2].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      48, subgraph_allocations[0].tensors[4].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      0, subgraph_allocations[0].tensors[3].data.uint8 - start);
 }
 
 TF_LITE_MICRO_TEST(TestAllocatePersistentTfLiteTensor) {
@@ -667,13 +674,15 @@
   TF_LITE_MICRO_EXPECT_NE(allocator, nullptr);
 
   TfLiteTensor* tensor1 = allocator->AllocatePersistentTfLiteTensor(
-      model, /*eval_tensors=*/nullptr, /*tensor_index=*/1);
+      model, /*subgraph_allocations=*/nullptr, /*tensor_index=*/1,
+      /*subgraph_index=*/0);
   TF_LITE_MICRO_EXPECT_NE(tensor1, nullptr);
   TF_LITE_MICRO_EXPECT_NE(tensor1->quantization.params, nullptr);
   TF_LITE_MICRO_EXPECT_FALSE(tensor1->is_variable);
 
   TfLiteTensor* tensor2 = allocator->AllocatePersistentTfLiteTensor(
-      model, /*eval_tensors=*/nullptr, /*tensor_index=*/2);
+      model, /*subgraph_allocations=*/nullptr, /*tensor_index=*/2,
+      /*subgraph_index=*/0);
   TF_LITE_MICRO_EXPECT_NE(tensor2, nullptr);
   TF_LITE_MICRO_EXPECT_NE(tensor2->quantization.params, nullptr);
   TF_LITE_MICRO_EXPECT_FALSE(tensor2->is_variable);
@@ -692,7 +701,8 @@
   TF_LITE_MICRO_EXPECT_NE(allocator, nullptr);
 
   TfLiteTensor* tensor1 = allocator->AllocateTempTfLiteTensor(
-      model, /*eval_tensors=*/nullptr, /*tensor_index=*/1);
+      model, /*subgraph_allocations=*/nullptr, /*tensor_index=*/1,
+      /*subgraph_index=*/0);
   TF_LITE_MICRO_EXPECT_NE(tensor1, nullptr);
 }
 
@@ -705,11 +715,13 @@
   TF_LITE_MICRO_EXPECT_NE(allocator, nullptr);
 
   TfLiteTensor* tensor1 = allocator->AllocateTempTfLiteTensor(
-      model, /*eval_tensors=*/nullptr, /*tensor_index=*/1);
+      model, /*subgraph_allocations=*/nullptr, /*tensor_index=*/1,
+      /*subgraph_index=*/0);
   TF_LITE_MICRO_EXPECT_NE(tensor1, nullptr);
 
   TfLiteTensor* tensor2 = allocator->AllocateTempTfLiteTensor(
-      model, /*eval_tensors=*/nullptr, /*tensor_index=*/2);
+      model, /*subgraph_allocations=*/nullptr, /*tensor_index=*/2,
+      /*subgraph_index=*/0);
   TF_LITE_MICRO_EXPECT_NE(tensor2, nullptr);
 
   // The address of tensor2 should be higher than the address of tensor1
@@ -726,13 +738,15 @@
   TF_LITE_MICRO_EXPECT(allocator != nullptr);
 
   TfLiteTensor* tensor1 = allocator->AllocateTempTfLiteTensor(
-      model, /*eval_tensors=*/nullptr, /*tensor_index=*/1);
+      model, /*subgraph_allocations=*/nullptr, /*tensor_index=*/1,
+      /*subgraph_index=*/0);
   TF_LITE_MICRO_EXPECT(tensor1 != nullptr);
 
   allocator->ResetTempAllocations();
 
   TfLiteTensor* tensor2 = allocator->AllocateTempTfLiteTensor(
-      model, /*eval_tensors=*/nullptr, /*tensor_index=*/2);
+      model, /*subgraph_allocations=*/nullptr, /*tensor_index=*/2,
+      /*subgraph_index=*/0);
   TF_LITE_MICRO_EXPECT(tensor2 != nullptr);
 
   // The address of tensor2 should be equal than the address of tensor1 since
@@ -743,7 +757,6 @@
 TF_LITE_MICRO_TEST(TestOperatorInputsNotInSubgraphInputs) {
   constexpr int number_tensors = 5;
   tflite::AllOpsResolver op_resolver = tflite::testing::GetOpResolver();
-  tflite::NodeAndRegistration* node_and_registration;
   const int32_t metadata_buffer[tflite::testing::kOfflinePlannerHeaderSize +
                                 number_tensors] = {/*version=*/1,
                                                    /*subgraph=*/0,
@@ -770,33 +783,35 @@
       number_tensors, metadata_buffer, node_list, number_connections,
       /*Only first tensor (t0) is in subgraph input list=*/1);
 
-  TfLiteEvalTensor* eval_tensors = nullptr;
   tflite::ScratchBufferHandle* scratch_buffer_handles = nullptr;
   constexpr size_t arena_size = 4096;
   uint8_t arena[arena_size];
   tflite::MicroAllocator* allocator = tflite::MicroAllocator::Create(
       arena, arena_size, tflite::GetMicroErrorReporter());
 
+  tflite::SubgraphAllocations* subgraph_allocations =
+      allocator->StartModelAllocation(model);
+  TF_LITE_MICRO_EXPECT(nullptr != subgraph_allocations);
   TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteOk,
-      allocator->StartModelAllocation(model, op_resolver,
-                                      &node_and_registration, &eval_tensors));
-  TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteOk, allocator->FinishModelAllocation(model, eval_tensors,
+      kTfLiteOk, allocator->FinishModelAllocation(model, subgraph_allocations,
                                                   &scratch_buffer_handles));
 
-  uint8_t* start = eval_tensors[0].data.uint8;
-  TF_LITE_MICRO_EXPECT_EQ(0, eval_tensors[0].data.uint8 - start);
-  TF_LITE_MICRO_EXPECT_EQ(0, eval_tensors[1].data.uint8 - start);
-  TF_LITE_MICRO_EXPECT_EQ(0, eval_tensors[2].data.uint8 - start);
-  TF_LITE_MICRO_EXPECT_EQ(48, eval_tensors[3].data.uint8 - start);
-  TF_LITE_MICRO_EXPECT_EQ(0, eval_tensors[4].data.uint8 - start);
+  uint8_t* start = subgraph_allocations[0].tensors[0].data.uint8;
+  TF_LITE_MICRO_EXPECT_EQ(
+      0, subgraph_allocations[0].tensors[0].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      0, subgraph_allocations[0].tensors[1].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      0, subgraph_allocations[0].tensors[2].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      48, subgraph_allocations[0].tensors[3].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      0, subgraph_allocations[0].tensors[4].data.uint8 - start);
 }
 
 TF_LITE_MICRO_TEST(TestTypicalFirstOpAndSecondOpWithScratchTensors) {
   constexpr int number_tensors = 6;
   tflite::AllOpsResolver op_resolver = tflite::testing::GetOpResolver();
-  tflite::NodeAndRegistration* node_and_registration;
   const int32_t metadata_buffer[tflite::testing::kOfflinePlannerHeaderSize +
                                 number_tensors] = {/*version=*/1,
                                                    /*subgraph=*/0,
@@ -826,28 +841,32 @@
       number_tensors, metadata_buffer, node_list, number_connections,
       /*Only first tensor (t0) is in subgraph input list=*/1);
 
-  TfLiteEvalTensor* eval_tensors = nullptr;
   tflite::ScratchBufferHandle* scratch_buffer_handles = nullptr;
   constexpr size_t arena_size = 4096;
   uint8_t arena[arena_size];
   tflite::MicroAllocator* allocator = tflite::MicroAllocator::Create(
       arena, arena_size, tflite::GetMicroErrorReporter());
 
+  tflite::SubgraphAllocations* subgraph_allocations =
+      allocator->StartModelAllocation(model);
+  TF_LITE_MICRO_EXPECT(nullptr != subgraph_allocations);
   TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteOk,
-      allocator->StartModelAllocation(model, op_resolver,
-                                      &node_and_registration, &eval_tensors));
-  TF_LITE_MICRO_EXPECT_EQ(
-      kTfLiteOk, allocator->FinishModelAllocation(model, eval_tensors,
+      kTfLiteOk, allocator->FinishModelAllocation(model, subgraph_allocations,
                                                   &scratch_buffer_handles));
 
-  uint8_t* start = eval_tensors[0].data.uint8;
-  TF_LITE_MICRO_EXPECT_EQ(0, eval_tensors[0].data.uint8 - start);
-  TF_LITE_MICRO_EXPECT_EQ(0, eval_tensors[1].data.uint8 - start);
-  TF_LITE_MICRO_EXPECT_EQ(0, eval_tensors[2].data.uint8 - start);
-  TF_LITE_MICRO_EXPECT_EQ(0, eval_tensors[3].data.uint8 - start);
-  TF_LITE_MICRO_EXPECT_EQ(48, eval_tensors[4].data.uint8 - start);
-  TF_LITE_MICRO_EXPECT_EQ(0, eval_tensors[5].data.uint8 - start);
+  uint8_t* start = subgraph_allocations[0].tensors[0].data.uint8;
+  TF_LITE_MICRO_EXPECT_EQ(
+      0, subgraph_allocations[0].tensors[0].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      0, subgraph_allocations[0].tensors[1].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      0, subgraph_allocations[0].tensors[2].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      0, subgraph_allocations[0].tensors[3].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      48, subgraph_allocations[0].tensors[4].data.uint8 - start);
+  TF_LITE_MICRO_EXPECT_EQ(
+      0, subgraph_allocations[0].tensors[5].data.uint8 - start);
 }
 
 TF_LITE_MICRO_TESTS_END
diff --git a/tensorflow/lite/micro/micro_graph.cc b/tensorflow/lite/micro/micro_graph.cc
new file mode 100644
index 0000000..7080d9d
--- /dev/null
+++ b/tensorflow/lite/micro/micro_graph.cc
@@ -0,0 +1,247 @@
+/* Copyright 2021 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_graph.h"
+
+#include "flatbuffers/flatbuffers.h"  // from @flatbuffers
+#include "tensorflow/lite/c/common.h"
+#include "tensorflow/lite/kernels/internal/compatibility.h"
+#include "tensorflow/lite/micro/memory_helpers.h"
+#include "tensorflow/lite/micro/micro_error_reporter.h"
+#include "tensorflow/lite/micro/micro_profiler.h"
+#include "tensorflow/lite/schema/schema_generated.h"
+
+namespace tflite {
+namespace {
+
+#ifndef TF_LITE_STRIP_ERROR_STRINGS
+const char* OpNameFromRegistration(const TfLiteRegistration* registration) {
+  if (registration->builtin_code == BuiltinOperator_CUSTOM) {
+    return registration->custom_name;
+  } else {
+    return EnumNameBuiltinOperator(BuiltinOperator(registration->builtin_code));
+  }
+}
+#endif  // !defined(TF_LITE_STRIP_ERROR_STRINGS)
+
+}  // namespace
+
+MicroGraph::MicroGraph(TfLiteContext* context, const Model* model,
+                       MicroAllocator* allocator)
+    : context_(context),
+      model_(model),
+      allocator_(allocator),
+      current_subgraph_index_(0) {
+  if (model != nullptr) {
+    subgraphs_ = model->subgraphs();
+  }
+}
+
+MicroGraph::~MicroGraph() {}
+
+TfLiteStatus MicroGraph::InitSubgraphs() {
+  int previous_subgraph_idx = current_subgraph_index_;
+
+  for (size_t subgraph_idx = 0; subgraph_idx < subgraphs_->size();
+       subgraph_idx++) {
+    current_subgraph_index_ = subgraph_idx;
+
+    const SubGraph* subgraph = (*subgraphs_)[subgraph_idx];
+    for (size_t i = 0; i < subgraph->operators()->size(); ++i) {
+      TfLiteNode* node =
+          &(subgraph_allocations_[subgraph_idx].node_and_registrations[i].node);
+      const TfLiteRegistration* registration =
+          subgraph_allocations_[subgraph_idx]
+              .node_and_registrations[i]
+              .registration;
+      size_t init_data_size;
+      const char* init_data;
+      if (registration->builtin_code == BuiltinOperator_CUSTOM) {
+        init_data = reinterpret_cast<const char*>(node->custom_initial_data);
+        init_data_size = node->custom_initial_data_size;
+      } else {
+        init_data = reinterpret_cast<const char*>(node->builtin_data);
+        init_data_size = 0;
+      }
+      if (registration->init) {
+        node->user_data =
+            registration->init(context_, init_data, init_data_size);
+      }
+    }
+  }
+  current_subgraph_index_ = previous_subgraph_idx;
+
+  return kTfLiteOk;
+}
+
+TfLiteStatus MicroGraph::PrepareSubgraphs() {
+  int previous_subgraph_idx = current_subgraph_index_;
+
+  for (size_t subgraph_idx = 0; subgraph_idx < subgraphs_->size();
+       subgraph_idx++) {
+    current_subgraph_index_ = subgraph_idx;
+
+    const SubGraph* subgraph = (*subgraphs_)[subgraph_idx];
+    for (size_t i = 0; i < subgraph->operators()->size(); ++i) {
+      TfLiteNode* node =
+          &(subgraph_allocations_[subgraph_idx].node_and_registrations[i].node);
+      const TfLiteRegistration* registration =
+          subgraph_allocations_[subgraph_idx]
+              .node_and_registrations[i]
+              .registration;
+      if (registration->prepare != nullptr) {
+        TfLiteStatus prepare_status = registration->prepare(context_, node);
+        if (prepare_status != kTfLiteOk) {
+          MicroPrintf("Node %s (number %df) failed to prepare with status %d",
+                      OpNameFromRegistration(registration), i, prepare_status);
+          return kTfLiteError;
+        }
+      }
+      allocator_->FinishPrepareNodeAllocations(/*node_id=*/i);
+    }
+  }
+  current_subgraph_index_ = previous_subgraph_idx;
+
+  return kTfLiteOk;
+}
+
+TfLiteStatus MicroGraph::FreeSubgraphs() {
+  int previous_subgraph_idx = current_subgraph_index_;
+
+  for (size_t subgraph_idx = 0; subgraph_idx < subgraphs_->size();
+       subgraph_idx++) {
+    current_subgraph_index_ = subgraph_idx;
+    const SubGraph* subgraph = (*subgraphs_)[subgraph_idx];
+    for (size_t i = 0; i < subgraph->operators()->size(); ++i) {
+      TfLiteNode* node =
+          &(subgraph_allocations_[subgraph_idx].node_and_registrations[i].node);
+      const TfLiteRegistration* registration =
+          subgraph_allocations_[subgraph_idx]
+              .node_and_registrations[i]
+              .registration;
+      // registration is allocated outside the interpreter, so double check to
+      // make sure it's not nullptr;
+      if (registration != nullptr && registration->free != nullptr) {
+        registration->free(context_, node->user_data);
+      }
+    }
+  }
+  current_subgraph_index_ = previous_subgraph_idx;
+
+  return kTfLiteOk;
+}
+
+TfLiteStatus MicroGraph::InvokeSubgraph(int subgraph_idx) {
+  int previous_subgraph_idx = current_subgraph_index_;
+  current_subgraph_index_ = subgraph_idx;
+
+  if (static_cast<size_t>(subgraph_idx) >= subgraphs_->size()) {
+    MicroPrintf("Accessing subgraph %d but only %d subgraphs found",
+                subgraph_idx, subgraphs_->size());
+    return kTfLiteError;
+  }
+  const SubGraph* subgraph = (*subgraphs_)[subgraph_idx];
+
+  for (size_t i = 0; i < subgraph->operators()->size(); ++i) {
+    TfLiteNode* node =
+        &(subgraph_allocations_[subgraph_idx].node_and_registrations[i].node);
+    const TfLiteRegistration* registration = subgraph_allocations_[subgraph_idx]
+                                                 .node_and_registrations[i]
+                                                 .registration;
+
+// This ifdef is needed (even though ScopedMicroProfiler itself is a no-op with
+// -DTF_LITE_STRIP_ERROR_STRINGS) because the function OpNameFromRegistration is
+// only defined for builds with the error strings.
+#if !defined(TF_LITE_STRIP_ERROR_STRINGS)
+    ScopedMicroProfiler scoped_profiler(
+        OpNameFromRegistration(registration),
+        reinterpret_cast<MicroProfiler*>(context_->profiler));
+#endif
+
+    TFLITE_DCHECK(registration->invoke);
+    TfLiteStatus invoke_status = registration->invoke(context_, node);
+
+    // All TfLiteTensor structs used in the kernel are allocated from temp
+    // memory in the allocator. This creates a chain of allocations in the
+    // temp section. The call below resets the chain of allocations to
+    // prepare for the next call.
+    allocator_->ResetTempAllocations();
+
+    if (invoke_status == kTfLiteError) {
+      MicroPrintf("Node %s (number %d) failed to invoke with status %d",
+                  OpNameFromRegistration(registration), i, invoke_status);
+      return kTfLiteError;
+    } else if (invoke_status != kTfLiteOk) {
+      return invoke_status;
+    }
+  }
+  current_subgraph_index_ = previous_subgraph_idx;
+  return kTfLiteOk;
+}
+
+TfLiteStatus MicroGraph::ResetVariableTensors() {
+  for (size_t subgraph_idx = 0; subgraph_idx < subgraphs_->size();
+       subgraph_idx++) {
+    const SubGraph* subgraph = (*subgraphs_)[subgraph_idx];
+    for (size_t i = 0; i < subgraph->tensors()->size(); ++i) {
+      auto* tensor = subgraph->tensors()->Get(i);
+      if (tensor->is_variable()) {
+        size_t buffer_size;
+        TF_LITE_ENSURE_STATUS(TfLiteEvalTensorByteLength(
+            &subgraph_allocations_[subgraph_idx].tensors[i], &buffer_size));
+
+        int value = 0;
+        if (tensor->type() == tflite::TensorType_INT8) {
+          value = tensor->quantization()->zero_point()->Get(0);
+        }
+        memset(subgraph_allocations_[subgraph_idx].tensors[i].data.raw, value,
+               buffer_size);
+      }
+    }
+  }
+
+  return kTfLiteOk;
+}
+
+int MicroGraph::NumSubgraphs() { return model_->subgraphs()->size(); }
+
+void MicroGraph::SetSubgraphAllocations(
+    SubgraphAllocations* subgraph_allocations) {
+  subgraph_allocations_ = subgraph_allocations;
+}
+
+size_t MicroGraph::NumSubgraphInputs(int subgraph_idx) {
+  return model_->subgraphs()->Get(subgraph_idx)->inputs()->size();
+}
+
+TfLiteEvalTensor* MicroGraph::GetSubgraphInput(int subgraph_idx,
+                                               int input_idx) {
+  int tensor_idx =
+      model_->subgraphs()->Get(subgraph_idx)->inputs()->Get(input_idx);
+  return &subgraph_allocations_[subgraph_idx].tensors[tensor_idx];
+}
+
+size_t MicroGraph::NumSubgraphOutputs(int subgraph_idx) {
+  return model_->subgraphs()->Get(subgraph_idx)->outputs()->size();
+}
+
+TfLiteEvalTensor* MicroGraph::GetSubgraphOutput(int subgraph_idx,
+                                                int output_idx) {
+  int tensor_idx =
+      model_->subgraphs()->Get(subgraph_idx)->outputs()->Get(output_idx);
+  return &subgraph_allocations_[subgraph_idx].tensors[tensor_idx];
+}
+
+}  // namespace tflite
diff --git a/tensorflow/lite/micro/micro_graph.h b/tensorflow/lite/micro/micro_graph.h
new file mode 100644
index 0000000..62316c7
--- /dev/null
+++ b/tensorflow/lite/micro/micro_graph.h
@@ -0,0 +1,97 @@
+/* Copyright 2021 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_GRAPH_H_
+#define TENSORFLOW_LITE_MICRO_MICRO_GRAPH_H_
+
+#include "tensorflow/lite/c/common.h"
+#include "tensorflow/lite/micro/micro_allocator.h"
+#include "tensorflow/lite/schema/schema_generated.h"
+
+namespace tflite {
+
+// Abstracts the details of interacting with the tflite::Model.
+//
+// Provides methods to access, initialize, prepare, invoke and free any
+// subgraph in the tflite::Graph.
+class MicroGraph {
+ public:
+  // The lifetime of the context, model, and allocator must be at least as long
+  // as that of the graph object, since the this class may need to access them
+  // at any time.
+  MicroGraph(TfLiteContext* context, const Model* model,
+             MicroAllocator* allocator);
+  virtual ~MicroGraph();
+
+  // Sets up builtin data and calls TfLiteRegistration->Init for every operator
+  // in every subgraph in the model.
+  virtual TfLiteStatus InitSubgraphs();
+
+  // Calls TfLiteRegistration->Prepare for every operator in every subgraph in
+  // the model.
+  virtual TfLiteStatus PrepareSubgraphs();
+
+  // Calls TfLiteRegistration->Free for every operator in every subgraph in the
+  // model.
+  virtual TfLiteStatus FreeSubgraphs();
+
+  // Calls TfLiteRegistration->Invoke for every operator in a single subgraph in
+  // the model.
+  virtual TfLiteStatus InvokeSubgraph(int subgraph_idx);
+
+  // Zeros out all variable tensors in all subgraphs in the model.
+  virtual TfLiteStatus ResetVariableTensors();
+
+  // Number of tensor inputs to a specified subgraph in the model.
+  virtual size_t NumSubgraphInputs(int subgraph_idx);
+
+  // Get the specified input tensor of a specified subgraph in the model.
+  virtual TfLiteEvalTensor* GetSubgraphInput(int subgraph_idx, int input_idx);
+
+  // Number of tensor outputs to a specified subgraph in the model.
+  virtual size_t NumSubgraphOutputs(int subgraph_idx);
+
+  // Get the specified output tensor of a specified subgraph in the model.
+  virtual TfLiteEvalTensor* GetSubgraphOutput(int subgraph_idx, int output_idx);
+
+  // Number of subgraphs in the model.
+  virtual int NumSubgraphs();
+
+  // Hook to pass in subgraph allocations tracked within the interpreter,
+  // allowing MicroGraph to init / prepare / invoke subgraphs in the model.
+  void SetSubgraphAllocations(SubgraphAllocations* subgraph_allocations);
+
+  // Get the current subgraph index. Within an on operator, this is guaranteed
+  // to be the subgraph of that operator.
+  int GetCurrentSubgraphIndex() { return current_subgraph_index_; }
+
+  // Gets the list of alloctions for each subgraph. This is the source of truth
+  // for all per-subgraph allocation data.
+  SubgraphAllocations* GetAllocations() { return subgraph_allocations_; }
+
+ private:
+  TfLiteContext* context_;
+  const Model* model_;
+  MicroAllocator* allocator_;
+  SubgraphAllocations* subgraph_allocations_ = nullptr;
+  int current_subgraph_index_;
+  const flatbuffers::Vector<flatbuffers::Offset<SubGraph>>* subgraphs_;
+
+  TF_LITE_REMOVE_VIRTUAL_DELETE
+};
+
+}  // namespace tflite
+
+#endif  // TENSORFLOW_LITE_MICRO_MICRO_GRAPH_H_
diff --git a/tensorflow/lite/micro/micro_interpreter.cc b/tensorflow/lite/micro/micro_interpreter.cc
index e05a35a..5b7ba0b 100644
--- a/tensorflow/lite/micro/micro_interpreter.cc
+++ b/tensorflow/lite/micro/micro_interpreter.cc
@@ -28,21 +28,9 @@
 #include "tensorflow/lite/micro/micro_op_resolver.h"
 #include "tensorflow/lite/micro/micro_profiler.h"
 #include "tensorflow/lite/schema/schema_generated.h"
+#include "tensorflow/lite/schema/schema_utils.h"
 
 namespace tflite {
-namespace {
-
-#ifndef TF_LITE_STRIP_ERROR_STRINGS
-const char* OpNameFromRegistration(const TfLiteRegistration* registration) {
-  if (registration->builtin_code == BuiltinOperator_CUSTOM) {
-    return registration->custom_name;
-  } else {
-    return EnumNameBuiltinOperator(BuiltinOperator(registration->builtin_code));
-  }
-}
-#endif  // !defined(TF_LITE_STRIP_ERROR_STRINGS)
-
-}  // namespace
 
 MicroInterpreter::MicroInterpreter(const Model* model,
                                    const MicroOpResolver& op_resolver,
@@ -55,9 +43,10 @@
       error_reporter_(error_reporter),
       allocator_(*MicroAllocator::Create(tensor_arena, tensor_arena_size,
                                          error_reporter)),
+
+      graph_(&context_, model, &allocator_),
       tensors_allocated_(false),
       initialization_status_(kTfLiteError),
-      eval_tensors_(nullptr),
       input_tensors_(nullptr),
       output_tensors_(nullptr) {
   Init(profiler);
@@ -72,103 +61,148 @@
       op_resolver_(op_resolver),
       error_reporter_(error_reporter),
       allocator_(*allocator),
+      graph_(&context_, model, allocator),
       tensors_allocated_(false),
       initialization_status_(kTfLiteError),
-      eval_tensors_(nullptr),
       input_tensors_(nullptr),
       output_tensors_(nullptr) {
   Init(profiler);
 }
 
 MicroInterpreter::~MicroInterpreter() {
-  if (node_and_registrations_ != nullptr) {
-    for (size_t i = 0; i < subgraph_->operators()->size(); ++i) {
-      TfLiteNode* node = &(node_and_registrations_[i].node);
-      const TfLiteRegistration* registration =
-          node_and_registrations_[i].registration;
-      // registration is allocated outside the interpreter, so double check to
-      // make sure it's not nullptr;
-      if (registration != nullptr && registration->free != nullptr) {
-        registration->free(&context_, node->user_data);
-      }
-    }
+  if (graph_.GetAllocations() != nullptr) {
+    graph_.FreeSubgraphs();
   }
 }
 
 void MicroInterpreter::Init(MicroProfiler* profiler) {
-  const flatbuffers::Vector<flatbuffers::Offset<SubGraph>>* subgraphs =
-      model_->subgraphs();
-  if (subgraphs->size() != 1) {
-    TF_LITE_REPORT_ERROR(error_reporter_,
-                         "Only 1 subgraph is currently supported.\n");
-    initialization_status_ = kTfLiteError;
-    return;
-  }
-  subgraph_ = (*subgraphs)[0];
-
   context_.impl_ = static_cast<void*>(this);
   context_.ReportError = ReportOpError;
   context_.GetTensor = GetTensor;
+  context_.ReportError = ReportOpError;
+  context_.GetTensor = GetTensor;
   context_.GetEvalTensor = GetEvalTensor;
-  context_.recommended_num_threads = 1;
   context_.profiler = profiler;
 
   initialization_status_ = kTfLiteOk;
 }
 
+TfLiteStatus MicroInterpreter::PrepareNodeAndRegistrationDataFromFlatbuffer() {
+  for (int subgraph_idx = 0; subgraph_idx < graph_.NumSubgraphs();
+       subgraph_idx++) {
+    const SubGraph* subgraph = model_->subgraphs()->Get(subgraph_idx);
+    TFLITE_DCHECK(subgraph != nullptr);
+
+    auto* opcodes = model_->operator_codes();
+    BuiltinDataAllocator* builtin_data_allocator =
+        allocator_.GetBuiltinDataAllocator();
+    for (size_t i = 0; i < subgraph->operators()->size(); ++i) {
+      const auto* op = subgraph->operators()->Get(i);
+      const size_t index = op->opcode_index();
+      if (index >= opcodes->size()) {
+        MicroPrintf("Missing registration for opcode_index %d\n", index);
+        return kTfLiteError;
+      }
+      const auto* opcode = opcodes->Get(index);
+      TfLiteStatus status =
+          GetRegistrationFromOpCode(opcode, op_resolver_, error_reporter_,
+                                    &(graph_.GetAllocations()[subgraph_idx]
+                                          .node_and_registrations[i]
+                                          .registration));
+      if (status != kTfLiteOk) {
+        MicroPrintf("Failed to get registration from op code %s\n ",
+                    EnumNameBuiltinOperator(GetBuiltinCode(opcode)));
+        return status;
+      }
+      const auto* registration = graph_.GetAllocations()[subgraph_idx]
+                                     .node_and_registrations[i]
+                                     .registration;
+      if (registration == nullptr) {
+        MicroPrintf("Skipping op for opcode_index %d\n", index);
+        return kTfLiteError;
+      }
+      BuiltinOperator op_type =
+          static_cast<BuiltinOperator>(registration->builtin_code);
+
+      const char* custom_data = nullptr;
+      size_t custom_data_size = 0;
+      unsigned char* builtin_data = nullptr;
+
+      if (op_type == BuiltinOperator_CUSTOM) {
+        // Custom Ops may or may not have a non-null custom_options field.
+        if (op->custom_options() != nullptr) {
+          custom_data =
+              reinterpret_cast<const char*>(op->custom_options()->data());
+          custom_data_size = op->custom_options()->size();
+        }
+      } else {
+        if (op->custom_options() != nullptr) {
+          MicroPrintf(
+              "Unsupported behavior: found builtin operator %s with custom "
+              "options.\n",
+              EnumNameBuiltinOperator(op_type));
+          return kTfLiteError;
+        }
+
+        MicroOpResolver::BuiltinParseFunction parser =
+            op_resolver_.GetOpDataParser(op_type);
+        if (parser == nullptr) {
+          MicroPrintf("Did not find a parser for %s",
+                      EnumNameBuiltinOperator(op_type));
+
+          return kTfLiteError;
+        }
+        TF_LITE_ENSURE_STATUS(parser(op, error_reporter_,
+                                     builtin_data_allocator,
+                                     (void**)(&builtin_data)));
+      }
+
+      TfLiteIntArray* inputs_array;
+      TF_LITE_ENSURE_STATUS(allocator_.FlatBufferVectorToTfLiteTypeArray(
+          op->inputs(), &inputs_array));
+
+      TfLiteIntArray* outputs_array;
+      TF_LITE_ENSURE_STATUS(allocator_.FlatBufferVectorToTfLiteTypeArray(
+          op->outputs(), &outputs_array));
+
+      TfLiteNode* node = &(
+          graph_.GetAllocations()[subgraph_idx].node_and_registrations[i].node);
+      *node = {};
+      node->inputs = inputs_array;
+      node->outputs = outputs_array;
+      node->builtin_data = reinterpret_cast<void*>(builtin_data);
+      node->custom_initial_data = custom_data;
+      node->custom_initial_data_size = custom_data_size;
+    }
+  }
+  return kTfLiteOk;
+}
+
 TfLiteStatus MicroInterpreter::AllocateTensors() {
-  if (allocator_.StartModelAllocation(model_, op_resolver_,
-                                      &node_and_registrations_,
-                                      &eval_tensors_) != kTfLiteOk) {
+  SubgraphAllocations* allocations = allocator_.StartModelAllocation(model_);
+
+  if (allocations == nullptr) {
     TF_LITE_REPORT_ERROR(error_reporter_,
                          "Failed starting model allocation.\n");
     initialization_status_ = kTfLiteError;
     return kTfLiteError;
   }
 
-  context_.tensors_size = subgraph_->tensors()->size();
+  graph_.SetSubgraphAllocations(allocations);
+
+  TF_LITE_ENSURE_STATUS(PrepareNodeAndRegistrationDataFromFlatbuffer());
 
   // Only allow AllocatePersistentBuffer in Init stage.
   context_.AllocatePersistentBuffer = AllocatePersistentBuffer;
   context_.RequestScratchBufferInArena = nullptr;
   context_.GetScratchBuffer = nullptr;
-
-  for (size_t i = 0; i < subgraph_->operators()->size(); ++i) {
-    auto* node = &(node_and_registrations_[i].node);
-    auto* registration = node_and_registrations_[i].registration;
-    size_t init_data_size;
-    const char* init_data;
-    if (registration->builtin_code == BuiltinOperator_CUSTOM) {
-      init_data = reinterpret_cast<const char*>(node->custom_initial_data);
-      init_data_size = node->custom_initial_data_size;
-    } else {
-      init_data = reinterpret_cast<const char*>(node->builtin_data);
-      init_data_size = 0;
-    }
-    if (registration->init) {
-      node->user_data =
-          registration->init(&context_, init_data, init_data_size);
-    }
-  }
+  context_.GetExecutionPlan = GetGraph;
+  graph_.InitSubgraphs();
 
   // Both AllocatePersistentBuffer and RequestScratchBufferInArena is
   // available in Prepare stage.
   context_.RequestScratchBufferInArena = RequestScratchBufferInArena;
-  for (size_t i = 0; i < subgraph_->operators()->size(); ++i) {
-    auto* node = &(node_and_registrations_[i].node);
-    auto* registration = node_and_registrations_[i].registration;
-    if (registration->prepare) {
-      TfLiteStatus prepare_status = registration->prepare(&context_, node);
-      if (prepare_status != kTfLiteOk) {
-        TF_LITE_REPORT_ERROR(
-            error_reporter_,
-            "Node %s (number %df) failed to prepare with status %d",
-            OpNameFromRegistration(registration), i, prepare_status);
-        return kTfLiteError;
-      }
-    }
-    allocator_.FinishPrepareNodeAllocations(/*node_id=*/i);
-  }
+  graph_.PrepareSubgraphs();
 
   // Prepare is done, we're ready for Invoke. Memory allocation is no longer
   // allowed. Kernels can only fetch scratch buffers via GetScratchBuffer.
@@ -176,9 +210,9 @@
   context_.RequestScratchBufferInArena = nullptr;
   context_.GetScratchBuffer = GetScratchBuffer;
 
-  TF_LITE_ENSURE_OK(&context_,
-                    allocator_.FinishModelAllocation(model_, eval_tensors_,
-                                                     &scratch_buffer_handles_));
+  TF_LITE_ENSURE_OK(&context_, allocator_.FinishModelAllocation(
+                                   model_, graph_.GetAllocations(),
+                                   &scratch_buffer_handles_));
 
   // TODO(b/162311891): Drop these allocations when the interpreter supports
   // handling buffers from TfLiteEvalTensor.
@@ -196,7 +230,7 @@
 
   for (size_t i = 0; i < inputs_size(); ++i) {
     input_tensors_[i] = allocator_.AllocatePersistentTfLiteTensor(
-        model_, eval_tensors_, inputs().Get(i));
+        model_, graph_.GetAllocations(), inputs().Get(i), 0);
     if (input_tensors_[i] == nullptr) {
       TF_LITE_REPORT_ERROR(error_reporter_,
                            "Failed to initialize input tensor %d", i);
@@ -220,7 +254,7 @@
 
   for (size_t i = 0; i < outputs_size(); ++i) {
     output_tensors_[i] = allocator_.AllocatePersistentTfLiteTensor(
-        model_, eval_tensors_, outputs().Get(i));
+        model_, graph_.GetAllocations(), outputs().Get(i), 0);
     if (output_tensors_[i] == nullptr) {
       TF_LITE_REPORT_ERROR(error_reporter_,
                            "Failed to initialize output tensor %d", i);
@@ -246,41 +280,7 @@
   if (!tensors_allocated_) {
     TF_LITE_ENSURE_OK(&context_, AllocateTensors());
   }
-
-  for (size_t i = 0; i < subgraph_->operators()->size(); ++i) {
-    auto* node = &(node_and_registrations_[i].node);
-    auto* registration = node_and_registrations_[i].registration;
-
-// This ifdef is needed (even though ScopedMicroProfiler itself is a no-op with
-// -DTF_LITE_STRIP_ERROR_STRINGS) because the function OpNameFromRegistration is
-// only defined for builds with the error strings.
-#if !defined(TF_LITE_STRIP_ERROR_STRINGS)
-    ScopedMicroProfiler scoped_profiler(
-        OpNameFromRegistration(registration),
-        reinterpret_cast<MicroProfiler*>(context_.profiler));
-#endif
-
-    TFLITE_DCHECK(registration->invoke);
-    TfLiteStatus invoke_status = registration->invoke(&context_, node);
-
-    // All TfLiteTensor structs used in the kernel are allocated from temp
-    // memory in the allocator. This creates a chain of allocations in the
-    // temp section. The call below resets the chain of allocations to
-    // prepare for the next call.
-    allocator_.ResetTempAllocations();
-
-    if (invoke_status == kTfLiteError) {
-      TF_LITE_REPORT_ERROR(
-          error_reporter_,
-          "Node %s (number %d) failed to invoke with status %d",
-          OpNameFromRegistration(registration), i, invoke_status);
-      return kTfLiteError;
-    } else if (invoke_status != kTfLiteOk) {
-      return invoke_status;
-    }
-  }
-
-  return kTfLiteOk;
+  return graph_.InvokeSubgraph(0);
 }
 
 TfLiteTensor* MicroInterpreter::input(size_t index) {
@@ -306,42 +306,27 @@
 }
 
 TfLiteStatus MicroInterpreter::ResetVariableTensors() {
-  for (size_t i = 0; i < subgraph_->tensors()->size(); ++i) {
-    auto* tensor = subgraph_->tensors()->Get(i);
-    if (tensor->is_variable()) {
-      size_t buffer_size;
-      TF_LITE_ENSURE_STATUS(
-          TfLiteEvalTensorByteLength(&eval_tensors_[i], &buffer_size));
-
-      int value = 0;
-      if (tensor->type() == tflite::TensorType_INT8) {
-        value = tensor->quantization()->zero_point()->Get(0);
-      }
-      memset(eval_tensors_[i].data.raw, value, buffer_size);
-    }
-  }
-
-  return kTfLiteOk;
+  return graph_.ResetVariableTensors();
 }
 
-void* MicroInterpreter::AllocatePersistentBuffer(TfLiteContext* context,
+void* MicroInterpreter::AllocatePersistentBuffer(TfLiteContext* ctx,
                                                  size_t bytes) {
-  return reinterpret_cast<MicroInterpreter*>(context->impl_)
+  return reinterpret_cast<MicroInterpreter*>(ctx->impl_)
       ->allocator_.AllocatePersistentBuffer(bytes);
 }
 
-TfLiteStatus MicroInterpreter::RequestScratchBufferInArena(
-    TfLiteContext* context, size_t bytes, int* buffer_idx) {
-  // All scratch buffer requests are managed in the allocator. Simply route the
-  // request and let the allocator manage allocations.
-  return static_cast<MicroInterpreter*>(context->impl_)
-      ->allocator_.RequestScratchBufferInArena(bytes, buffer_idx);
+TfLiteStatus MicroInterpreter::RequestScratchBufferInArena(TfLiteContext* ctx,
+                                                           size_t bytes,
+                                                           int* buffer_idx) {
+  MicroInterpreter* interpreter =
+      reinterpret_cast<MicroInterpreter*>(ctx->impl_);
+  return interpreter->allocator_.RequestScratchBufferInArena(
+      bytes, interpreter->graph_.GetCurrentSubgraphIndex(), buffer_idx);
 }
 
-void* MicroInterpreter::GetScratchBuffer(TfLiteContext* context,
-                                         int buffer_idx) {
+void* MicroInterpreter::GetScratchBuffer(TfLiteContext* ctx, int buffer_idx) {
   MicroInterpreter* interpreter =
-      static_cast<MicroInterpreter*>(context->impl_);
+      reinterpret_cast<MicroInterpreter*>(ctx->impl_);
   ScratchBufferHandle* handle =
       interpreter->scratch_buffer_handles_ + buffer_idx;
   return handle->data;
@@ -364,14 +349,25 @@
   MicroInterpreter* interpreter =
       static_cast<MicroInterpreter*>(context->impl_);
   return interpreter->allocator_.AllocateTempTfLiteTensor(
-      interpreter->model_, interpreter->eval_tensors_, tensor_idx);
+      interpreter->model_, interpreter->graph_.GetAllocations(), tensor_idx,
+      interpreter->get_subgraph_index());
 }
 
 TfLiteEvalTensor* MicroInterpreter::GetEvalTensor(
     const struct TfLiteContext* context, int tensor_idx) {
   MicroInterpreter* interpreter =
-      static_cast<MicroInterpreter*>(context->impl_);
-  return &interpreter->eval_tensors_[tensor_idx];
+      reinterpret_cast<MicroInterpreter*>(context->impl_);
+  return &interpreter->graph_
+              .GetAllocations()[interpreter->get_subgraph_index()]
+              .tensors[tensor_idx];
+}
+
+TfLiteStatus MicroInterpreter::GetGraph(struct TfLiteContext* context,
+                                        TfLiteIntArray** args) {
+  MicroInterpreter* interpreter =
+      reinterpret_cast<MicroInterpreter*>(context->impl_);
+  *args = reinterpret_cast<TfLiteIntArray*>(&interpreter->graph_);
+  return kTfLiteOk;
 }
 
 }  // namespace tflite
diff --git a/tensorflow/lite/micro/micro_interpreter.h b/tensorflow/lite/micro/micro_interpreter.h
index d34015a..67d5420 100644
--- a/tensorflow/lite/micro/micro_interpreter.h
+++ b/tensorflow/lite/micro/micro_interpreter.h
@@ -23,6 +23,7 @@
 #include "tensorflow/lite/core/api/error_reporter.h"
 #include "tensorflow/lite/kernels/internal/tensor_ctypes.h"
 #include "tensorflow/lite/micro/micro_allocator.h"
+#include "tensorflow/lite/micro/micro_graph.h"
 #include "tensorflow/lite/micro/micro_op_resolver.h"
 #include "tensorflow/lite/micro/micro_profiler.h"
 #include "tensorflow/lite/portable_type_to_tflitetype.h"
@@ -69,9 +70,11 @@
   TfLiteStatus Invoke();
 
   TfLiteTensor* input(size_t index);
-  size_t inputs_size() const { return subgraph_->inputs()->Length(); }
+  size_t inputs_size() const {
+    return model_->subgraphs()->Get(0)->inputs()->size();
+  }
   const flatbuffers::Vector<int32_t>& inputs() const {
-    return *subgraph_->inputs();
+    return *model_->subgraphs()->Get(0)->inputs();
   }
   TfLiteTensor* input_tensor(size_t index) { return input(index); }
   template <class T>
@@ -85,9 +88,11 @@
   }
 
   TfLiteTensor* output(size_t index);
-  size_t outputs_size() const { return subgraph_->outputs()->Length(); }
+  size_t outputs_size() const {
+    return model_->subgraphs()->Get(0)->outputs()->size();
+  }
   const flatbuffers::Vector<int32_t>& outputs() const {
-    return *subgraph_->outputs();
+    return *model_->subgraphs()->Get(0)->outputs();
   }
   TfLiteTensor* output_tensor(size_t index) { return output(index); }
   template <class T>
@@ -105,13 +110,16 @@
 
   TfLiteStatus initialization_status() const { return initialization_status_; }
 
-  size_t operators_size() const { return subgraph_->operators()->size(); }
-
-  // For debugging only.
-  const NodeAndRegistration node_and_registration(int node_index) const {
-    return node_and_registrations_[node_index];
+  size_t operators_size() const {
+    return model_->subgraphs()->Get(0)->operators()->size();
   }
 
+  // Populates node and registration pointers representing the inference graph
+  // of the model from values inside the flatbuffer (loaded from the TfLiteModel
+  // instance). Persistent data (e.g. operator data) is allocated from the
+  // arena.
+  TfLiteStatus PrepareNodeAndRegistrationDataFromFlatbuffer();
+
   // For debugging only.
   // Returns the actual used arena in bytes. This method gives the optimal arena
   // size. It's only available after `AllocateTensors` has been called.
@@ -129,32 +137,34 @@
   // error reporting during initialization.
   void Init(MicroProfiler* profiler);
 
+  // Gets the current subgraph index used from within context methods.
+  int get_subgraph_index() { return graph_.GetCurrentSubgraphIndex(); }
+
   // Static functions that are bound to the TfLiteContext instance:
-  static void* AllocatePersistentBuffer(TfLiteContext* Context, size_t bytes);
-  static TfLiteStatus RequestScratchBufferInArena(TfLiteContext* context,
+  static void* AllocatePersistentBuffer(TfLiteContext* ctx, size_t bytes);
+  static TfLiteStatus RequestScratchBufferInArena(TfLiteContext* ctx,
                                                   size_t bytes,
                                                   int* buffer_idx);
-  static void* GetScratchBuffer(TfLiteContext* context, int buffer_idx);
+  static void* GetScratchBuffer(TfLiteContext* ctx, int buffer_idx);
   static void ReportOpError(struct TfLiteContext* context, const char* format,
                             ...);
   static TfLiteTensor* GetTensor(const struct TfLiteContext* context,
                                  int tensor_idx);
   static TfLiteEvalTensor* GetEvalTensor(const struct TfLiteContext* context,
                                          int tensor_idx);
-
-  NodeAndRegistration* node_and_registrations_ = nullptr;
+  static TfLiteStatus GetGraph(struct TfLiteContext* context,
+                               TfLiteIntArray** args);
 
   const Model* model_;
   const MicroOpResolver& op_resolver_;
   ErrorReporter* error_reporter_;
   TfLiteContext context_ = {};
   MicroAllocator& allocator_;
+  MicroGraph graph_;
   bool tensors_allocated_;
 
   TfLiteStatus initialization_status_;
 
-  const SubGraph* subgraph_ = nullptr;
-  TfLiteEvalTensor* eval_tensors_ = nullptr;
   ScratchBufferHandle* scratch_buffer_handles_ = nullptr;
 
   // TODO(b/162311891): Clean these pointers up when this class supports buffers
diff --git a/tensorflow/lite/micro/micro_interpreter_test.cc b/tensorflow/lite/micro/micro_interpreter_test.cc
index c0f8667..6ff6233 100644
--- a/tensorflow/lite/micro/micro_interpreter_test.cc
+++ b/tensorflow/lite/micro/micro_interpreter_test.cc
@@ -302,7 +302,7 @@
 
   tflite::AllOpsResolver op_resolver = tflite::testing::GetOpResolver();
 
-  constexpr size_t allocator_buffer_size = 512;
+  constexpr size_t allocator_buffer_size = 528;
   uint8_t allocator_buffer[allocator_buffer_size];
 
   tflite::RecordingMicroAllocator* allocator =
diff --git a/tensorflow/lite/micro/micro_utils.h b/tensorflow/lite/micro/micro_utils.h
index b9a3121..afa50a3 100644
--- a/tensorflow/lite/micro/micro_utils.h
+++ b/tensorflow/lite/micro/micro_utils.h
@@ -19,6 +19,7 @@
 #include <algorithm>
 #include <cmath>
 #include <cstdint>
+#include <limits>
 
 #include "tensorflow/lite/c/common.h"
 
diff --git a/tensorflow/lite/micro/recording_micro_allocator.cc b/tensorflow/lite/micro/recording_micro_allocator.cc
index 6bb5297..1e32e23 100644
--- a/tensorflow/lite/micro/recording_micro_allocator.cc
+++ b/tensorflow/lite/micro/recording_micro_allocator.cc
@@ -130,58 +130,48 @@
 }
 
 TfLiteStatus RecordingMicroAllocator::AllocateNodeAndRegistrations(
-    const Model* model, NodeAndRegistration** node_and_registrations) {
-  RecordedAllocation allocations = SnapshotAllocationUsage();
-
-  TfLiteStatus status = MicroAllocator::AllocateNodeAndRegistrations(
-      model, node_and_registrations);
-
-  RecordAllocationUsage(allocations,
-                        recorded_node_and_registration_array_data_);
-  // The allocation count in SimpleMemoryAllocator will only be 1. To provide
-  // better logging, decrement by 1 and add in the actual number of operators
-  // used in the graph:
-  // The allocation for this recording will always be 1. This is because the
-  // parent class mallocs one large allocation for the number of nodes in the
-  // graph (e.g. sizeof(NodeAndRegistration) * num_nodes).
-  // To prevent extra overhead and potential for fragmentation, manually adjust
-  // the accounting by decrementing by 1 and adding the actual number of nodes
-  // used in the graph:
-  recorded_node_and_registration_array_data_.count +=
-      GetSubGraphFromModel(model)->operators()->size() - 1;
-  return status;
-}
-
-TfLiteStatus
-RecordingMicroAllocator::PrepareNodeAndRegistrationDataFromFlatbuffer(
-    const Model* model, const MicroOpResolver& op_resolver,
-    NodeAndRegistration* node_and_registrations) {
+    const Model* model, SubgraphAllocations* subgraph_allocations) {
   RecordedAllocation allocations = SnapshotAllocationUsage();
 
   TfLiteStatus status =
-      MicroAllocator::PrepareNodeAndRegistrationDataFromFlatbuffer(
-          model, op_resolver, node_and_registrations);
-
-  RecordAllocationUsage(allocations, recorded_op_data_);
+      MicroAllocator::AllocateNodeAndRegistrations(model, subgraph_allocations);
+  for (size_t subgraph_idx = 0; subgraph_idx < model->subgraphs()->size();
+       subgraph_idx++) {
+    RecordAllocationUsage(allocations,
+                          recorded_node_and_registration_array_data_);
+    // The allocation count in SimpleMemoryAllocator will only be 1. To provide
+    // better logging, decrement by 1 and add in the actual number of operators
+    // used in the graph:
+    // The allocation for this recording will always be 1. This is because the
+    // parent class mallocs one large allocation for the number of nodes in the
+    // graph (e.g. sizeof(NodeAndRegistration) * num_nodes).
+    // To prevent extra overhead and potential for fragmentation, manually
+    // adjust the accounting by decrementing by 1 and adding the actual number
+    // of nodes used in the graph:
+    recorded_node_and_registration_array_data_.count +=
+        model->subgraphs()->Get(subgraph_idx)->operators()->size() - 1;
+  }
   return status;
 }
 
 TfLiteStatus RecordingMicroAllocator::AllocateTfLiteEvalTensors(
-    const Model* model, TfLiteEvalTensor** eval_tensors) {
+    const Model* model, SubgraphAllocations* subgraph_allocations) {
   RecordedAllocation allocations = SnapshotAllocationUsage();
 
   TfLiteStatus status =
-      MicroAllocator::AllocateTfLiteEvalTensors(model, eval_tensors);
-
-  RecordAllocationUsage(allocations, recorded_tflite_eval_tensor_data_);
-  // The allocation for this recording will always be 1. This is because the
-  // parent class mallocs one large allocation for the number of tensors in the
-  // graph (e.g. sizeof(TfLiteEvalTensor) * num_tensors).
-  // To prevent extra overhead and potential for fragmentation, manually adjust
-  // the accounting by decrementing by 1 and adding the actual number of tensors
-  // used in the graph:
-  recorded_tflite_eval_tensor_data_.count +=
-      GetSubGraphFromModel(model)->tensors()->size() - 1;
+      MicroAllocator::AllocateTfLiteEvalTensors(model, subgraph_allocations);
+  for (size_t subgraph_idx = 0; subgraph_idx < model->subgraphs()->size();
+       subgraph_idx++) {
+    RecordAllocationUsage(allocations, recorded_tflite_eval_tensor_data_);
+    // The allocation for this recording will always be 1. This is because the
+    // parent class mallocs one large allocation for the number of tensors in
+    // the graph (e.g. sizeof(TfLiteEvalTensor) * num_tensors). To prevent extra
+    // overhead and potential for fragmentation, manually adjust the accounting
+    // by decrementing by 1 and adding the actual number of tensors used in the
+    // graph:
+    recorded_tflite_eval_tensor_data_.count +=
+        model->subgraphs()->Get(subgraph_idx)->tensors()->size() - 1;
+  }
   return status;
 }
 
@@ -197,24 +187,24 @@
   return status;
 }
 
-TfLiteTensor* RecordingMicroAllocator::AllocatePersistentTfLiteTensorInternal(
-    const Model* model, TfLiteEvalTensor* eval_tensors, int tensor_index) {
+TfLiteTensor*
+RecordingMicroAllocator::AllocatePersistentTfLiteTensorInternal() {
   RecordedAllocation allocations = SnapshotAllocationUsage();
 
-  TfLiteTensor* result = MicroAllocator::AllocatePersistentTfLiteTensorInternal(
-      model, eval_tensors, tensor_index);
+  TfLiteTensor* result =
+      MicroAllocator::AllocatePersistentTfLiteTensorInternal();
 
   RecordAllocationUsage(allocations, recorded_persistent_tflite_tensor_data_);
   return result;
 }
 
 TfLiteStatus RecordingMicroAllocator::PopulateTfLiteTensorFromFlatbuffer(
-    const Model* model, const SubGraph* subgraph, TfLiteTensor* tensor,
-    int tensor_index, bool allocate_temp) {
+    const Model* model, TfLiteTensor* tensor, int tensor_index,
+    int subgraph_index, bool allocate_temp) {
   RecordedAllocation allocations = SnapshotAllocationUsage();
 
   TfLiteStatus status = MicroAllocator::PopulateTfLiteTensorFromFlatbuffer(
-      model, subgraph, tensor, tensor_index, allocate_temp);
+      model, tensor, tensor_index, subgraph_index, allocate_temp);
 
   RecordAllocationUsage(allocations,
                         recorded_persistent_tflite_tensor_quantization_data_);
diff --git a/tensorflow/lite/micro/recording_micro_allocator.h b/tensorflow/lite/micro/recording_micro_allocator.h
index 47246e1..c3f4223 100644
--- a/tensorflow/lite/micro/recording_micro_allocator.h
+++ b/tensorflow/lite/micro/recording_micro_allocator.h
@@ -72,27 +72,22 @@
 
  protected:
   TfLiteStatus AllocateNodeAndRegistrations(
-      const Model* model,
-      NodeAndRegistration** node_and_registrations) override;
-  TfLiteStatus PrepareNodeAndRegistrationDataFromFlatbuffer(
-      const Model* model, const MicroOpResolver& op_resolver,
-      NodeAndRegistration* node_and_registrations) override;
+      const Model* model, SubgraphAllocations* subgraph_allocations) override;
   TfLiteStatus AllocateTfLiteEvalTensors(
-      const Model* model, TfLiteEvalTensor** eval_tensors) override;
+      const Model* model, SubgraphAllocations* subgraph_allocations) override;
   TfLiteStatus AllocateVariables(const SubGraph* subgraph,
                                  TfLiteEvalTensor* eval_tensors) override;
   // TODO(b/162311891): Once all kernels have been updated to the new API drop
   // this method. It is only used to record TfLiteTensor persistent allocations.
-  TfLiteTensor* AllocatePersistentTfLiteTensorInternal(
-      const Model* model, TfLiteEvalTensor* eval_tensors,
-      int tensor_index) override;
+  TfLiteTensor* AllocatePersistentTfLiteTensorInternal() override;
+
   // TODO(b/162311891): Once all kernels have been updated to the new API drop
   // this function since all allocations for quantized data will take place in
   // the temp section.
   TfLiteStatus PopulateTfLiteTensorFromFlatbuffer(const Model* model,
-                                                  const SubGraph* subgraph,
                                                   TfLiteTensor* tensor,
                                                   int tensor_index,
+                                                  int subgraph_index,
                                                   bool allocate_temp) override;
 
  private:
@@ -115,6 +110,8 @@
   RecordedAllocation recorded_persistent_buffer_data_ = {};
   RecordedAllocation recorded_tflite_tensor_variable_buffer_data_ = {};
   RecordedAllocation recorded_node_and_registration_array_data_ = {};
+
+  // TODO(b/187993291): Re-enable OpData allocating tracking.
   RecordedAllocation recorded_op_data_ = {};
 
   TF_LITE_REMOVE_VIRTUAL_DELETE
diff --git a/tensorflow/lite/micro/recording_micro_allocator_test.cc b/tensorflow/lite/micro/recording_micro_allocator_test.cc
index b5f4080..1733726 100644
--- a/tensorflow/lite/micro/recording_micro_allocator_test.cc
+++ b/tensorflow/lite/micro/recording_micro_allocator_test.cc
@@ -16,6 +16,7 @@
 #include "tensorflow/lite/micro/recording_micro_allocator.h"
 
 #include "tensorflow/lite/micro/all_ops_resolver.h"
+#include "tensorflow/lite/micro/micro_allocator.h"
 #include "tensorflow/lite/micro/micro_error_reporter.h"
 #include "tensorflow/lite/micro/test_helpers.h"
 #include "tensorflow/lite/micro/testing/micro_test.h"
@@ -36,10 +37,8 @@
 TF_LITE_MICRO_TESTS_BEGIN
 
 TF_LITE_MICRO_TEST(TestRecordsTfLiteEvalTensorArrayData) {
-  TfLiteEvalTensor* eval_tensors = nullptr;
   tflite::ScratchBufferHandle* scratch_buffer_handles = nullptr;
   tflite::AllOpsResolver all_ops_resolver;
-  tflite::NodeAndRegistration* node_and_registration;
   const tflite::Model* model = tflite::GetModel(kTestConvModelData);
   uint8_t arena[kTestConvArenaSize];
 
@@ -51,14 +50,13 @@
   TF_LITE_MICRO_EXPECT_NE(micro_allocator, nullptr);
   if (micro_allocator == nullptr) return 1;
 
-  TfLiteStatus status;
-  status = micro_allocator->StartModelAllocation(
-      model, all_ops_resolver, &node_and_registration, &eval_tensors);
-  TF_LITE_MICRO_EXPECT_EQ(status, kTfLiteOk);
-  if (status != kTfLiteOk) return 1;
+  tflite::SubgraphAllocations* subgraph_allocations =
+      micro_allocator->StartModelAllocation(model);
+  TF_LITE_MICRO_EXPECT(nullptr != subgraph_allocations);
+  if (subgraph_allocations == nullptr) return 1;
 
-  status = micro_allocator->FinishModelAllocation(model, eval_tensors,
-                                                  &scratch_buffer_handles);
+  TfLiteStatus status = micro_allocator->FinishModelAllocation(
+      model, subgraph_allocations, &scratch_buffer_handles);
   TF_LITE_MICRO_EXPECT_EQ(status, kTfLiteOk);
   if (status != kTfLiteOk) return 1;
 
@@ -80,10 +78,8 @@
 }
 
 TF_LITE_MICRO_TEST(TestRecordsNodeAndRegistrationArrayData) {
-  TfLiteEvalTensor* eval_tensors = nullptr;
   tflite::ScratchBufferHandle* scratch_buffer_handles = nullptr;
   tflite::AllOpsResolver all_ops_resolver;
-  tflite::NodeAndRegistration* node_and_registration;
   const tflite::Model* model = tflite::GetModel(kTestConvModelData);
   uint8_t arena[kTestConvArenaSize];
 
@@ -93,14 +89,13 @@
   TF_LITE_MICRO_EXPECT_NE(micro_allocator, nullptr);
   if (micro_allocator == nullptr) return 1;
 
-  TfLiteStatus status;
-  status = micro_allocator->StartModelAllocation(
-      model, all_ops_resolver, &node_and_registration, &eval_tensors);
-  TF_LITE_MICRO_EXPECT_EQ(status, kTfLiteOk);
-  if (status != kTfLiteOk) return 1;
+  tflite::SubgraphAllocations* subgraph_allocations =
+      micro_allocator->StartModelAllocation(model);
+  TF_LITE_MICRO_EXPECT(nullptr != subgraph_allocations);
+  if (subgraph_allocations == nullptr) return 1;
 
-  status = micro_allocator->FinishModelAllocation(model, eval_tensors,
-                                                  &scratch_buffer_handles);
+  TfLiteStatus status = micro_allocator->FinishModelAllocation(
+      model, subgraph_allocations, &scratch_buffer_handles);
   TF_LITE_MICRO_EXPECT_EQ(status, kTfLiteOk);
   if (status != kTfLiteOk) return 1;
 
@@ -108,6 +103,7 @@
   tflite::RecordedAllocation recorded_allocation =
       micro_allocator->GetRecordedAllocation(
           tflite::RecordedAllocationType::kNodeAndRegistrationArray);
+
   TF_LITE_MICRO_EXPECT_EQ(recorded_allocation.count, num_ops);
   TF_LITE_MICRO_EXPECT_EQ(recorded_allocation.requested_bytes,
                           num_ops * NODE_AND_REGISTRATION_STRUCT_SIZE);
@@ -116,10 +112,8 @@
 }
 
 TF_LITE_MICRO_TEST(TestRecordsMultiTenantAllocations) {
-  TfLiteEvalTensor* eval_tensors = nullptr;
   tflite::ScratchBufferHandle* scratch_buffer_handles = nullptr;
   tflite::AllOpsResolver all_ops_resolver;
-  tflite::NodeAndRegistration* node_and_registration;
   const tflite::Model* model = tflite::GetModel(kTestConvModelData);
 
   // Double the arena size to allocate two models inside of it:
@@ -134,24 +128,23 @@
   if (micro_allocator == nullptr) return 1;
 
   // First allocation with the model in the arena:
-  status = micro_allocator->StartModelAllocation(
-      model, all_ops_resolver, &node_and_registration, &eval_tensors);
-  TF_LITE_MICRO_EXPECT_EQ(status, kTfLiteOk);
-  if (status != kTfLiteOk) return 1;
+  tflite::SubgraphAllocations* subgraph_allocations =
+      micro_allocator->StartModelAllocation(model);
+  TF_LITE_MICRO_EXPECT(nullptr != subgraph_allocations);
+  if (subgraph_allocations == nullptr) return 1;
 
-  status = micro_allocator->FinishModelAllocation(model, eval_tensors,
+  status = micro_allocator->FinishModelAllocation(model, subgraph_allocations,
                                                   &scratch_buffer_handles);
   TF_LITE_MICRO_EXPECT_EQ(status, kTfLiteOk);
   if (status != kTfLiteOk) return 1;
 
   // Second allocation with the same model in the arena:
-  status = micro_allocator->StartModelAllocation(
-      model, all_ops_resolver, &node_and_registration, &eval_tensors);
-  TF_LITE_MICRO_EXPECT_EQ(status, kTfLiteOk);
-  if (status != kTfLiteOk) return 1;
+  subgraph_allocations = micro_allocator->StartModelAllocation(model);
+  TF_LITE_MICRO_EXPECT(nullptr != subgraph_allocations);
+  if (subgraph_allocations == nullptr) return 1;
 
   status = kTfLiteOk, micro_allocator->FinishModelAllocation(
-                          model, eval_tensors, &scratch_buffer_handles);
+                          model, subgraph_allocations, &scratch_buffer_handles);
   TF_LITE_MICRO_EXPECT_EQ(status, kTfLiteOk);
   if (status != kTfLiteOk) return 1;
 
@@ -160,6 +153,8 @@
   tflite::RecordedAllocation recorded_allocation =
       micro_allocator->GetRecordedAllocation(
           tflite::RecordedAllocationType::kTfLiteEvalTensorData);
+
+  // Node and tensor arrays must be allocated as well as each node and tensor.
   TF_LITE_MICRO_EXPECT_EQ(recorded_allocation.count, tensors_count * 2);
   TF_LITE_MICRO_EXPECT_EQ(recorded_allocation.requested_bytes,
                           tensors_count * TF_LITE_EVAL_TENSOR_STRUCT_SIZE * 2);
@@ -178,7 +173,7 @@
   if (micro_allocator == nullptr) return 1;
 
   TfLiteTensor* tensor = micro_allocator->AllocatePersistentTfLiteTensor(
-      model, /*eval_tensors=*/nullptr, 0);
+      model, /*subgraph_allocations=*/nullptr, 0, 0);
   TF_LITE_MICRO_EXPECT_NE(tensor, nullptr);
   if (tensor == nullptr) return 1;
 
@@ -204,7 +199,7 @@
   if (micro_allocator == nullptr) return 1;
 
   TfLiteTensor* tensor = micro_allocator->AllocatePersistentTfLiteTensor(
-      model, /*eval_tensors=*/nullptr, 0);
+      model, /*subgraph_allocations=*/nullptr, 0, 0);
   TF_LITE_MICRO_EXPECT_NE(tensor, nullptr);
   if (tensor == nullptr) return 1;