/**
 * Copyright (c) 2026 Huawei Technologies Co., Ltd.
 * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
 * CANN Open Software License Agreement Version 2.0 (the "License").
 * Please refer to the License for details. You may not use this file except in compliance with the License.
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
 * See LICENSE in the root of the software repository for the full text of the License.
 */

#include <cinttypes>
#include <string>
#include <fstream>
#include <regex>
#include <sys/syscall.h>
#include <unistd.h>
#include "acl/acl_rt.h"
#include "registry/op_impl_space_registry_v2.h"
#include "framework/runtime/rt_session.h"
#include "framework/runtime/dump/model_dump_manager.h"
#include "framework/common/framework_types_internal.h"
#include "runtime/om2_model_executor.h"
#include "common/checker.h"
#include "mmpa/mmpa_api.h"
#include "../../inc/framework/runtime/om2_context.h"
#include "graph/utils/type_utils_inner.h"
#include "graph_metadef/common/ge_common/util.h"
#include "rt_external_mem.h"
#include "common/helper/om2/json_file.h"
#include "nlohmann/json.hpp"
#include "common/compile_profiling/ge_call_wrapper.h"
#include "file_const_loader.h"
#include "om2_external_weight_manager.h"
#include "om2_file_utils.h"
#include "om2_malloc_helper.h"
#include "om2_var_manager.h"
#include "zip_archive_reader.h"
#include "common/om2/om2_model_data.h"
#include "om2_aipp_utils.h"

namespace gert {
namespace {
constexpr size_t kMaxErrorStringLen = 128U;
constexpr size_t FILE_MAGIC_HEADER_SIZE = 4U;
constexpr uint8_t OM2_MAGIC[] = {0x50, 0x4B, 0x03, 0x04};

using Om2ModelHandle = void *;
using CreateFunc = ge::graphStatus (*)(Om2ModelHandle *, rtModel_t *, const char **, const void **, size_t *, int,
                                       void **, void *, uint64_t *, uint32_t, void *);
using LoadFunc = ge::graphStatus (*)(Om2ModelHandle *);
using DestroyFunc = ge::graphStatus (*)(Om2ModelHandle *);
using RunFunc = ge::graphStatus (*)(Om2ModelHandle *, int, void **, int, void **, int32_t, Om2ProfInfos *);
using RunAsyncFunc = ge::graphStatus (*)(Om2ModelHandle *, rtStream_t, int, void **, int, void **, Om2ProfInfos *);

struct RunModelInfo {
  std::string so_file;
  int32_t so_fd = -1;
  std::map<std::string, std::map<std::string, std::string>> op_attr_map;  // 直接使用 map,避免 JSON 序列化开销
  void *so_handle = nullptr;
  std::string model_name;
  std::string root_graph_name;
  Om2ModelHandle model_handle = nullptr;
  rtModel_t rt_model_handle = nullptr;
  CreateFunc create_func = nullptr;
  LoadFunc load_func = nullptr;
  DestroyFunc destroy_func = nullptr;
  RunFunc run_func = nullptr;
  RunAsyncFunc run_async_func = nullptr;
};

struct ModelMetaInfo {
  size_t work_size = 0U;
  size_t zero_copy_size = 0U;
  std::vector<ge::Om2TensorDesc> input_desc;
  std::vector<ge::Om2TensorDesc> output_desc;
  std::vector<ge::Om2TensorDesc> input_desc_v2;
  std::vector<ge::Om2TensorDesc> output_desc_v2;
  std::vector<std::vector<int64_t>> dynamic_batch_info;
  int32_t dynamic_type = 0;
  std::vector<std::string> dynamic_output_shape;
  std::vector<std::string> user_designate_shape_order;
  std::vector<std::vector<int64_t>> origin_input_dims;  // 原始shape(含-1标识动态轴)
};

struct KernelBinInfo {
  std::string file;
  ge::ReadonlyByteBuffer data;
  size_t data_size;
};

struct ClassifiedConstItems {
  std::vector<Om2ConstItem> internal_consts;
  std::vector<Om2ConstItem> combined_consts;
  std::vector<Om2ConstItem> individual_consts;
  size_t max_index = 0U;
};

std::pair<std::string, std::string> ExtractParentDirAndFileName(const std::string &abs_path) {
  if (abs_path.empty()) {
    return {"", ""};
  }
  size_t last_slash = abs_path.find_last_of('/');
  if (last_slash == std::string::npos) {
    return {"", abs_path};
  }
  if (last_slash == 0) {
    return {"/", abs_path.substr(1)};
  }
  return {abs_path.substr(0, last_slash + 1), abs_path.substr(last_slash + 1)};
}

void CloseMemFd(int32_t &fd) {
  if (fd >= 0) {
    (void)mmClose(fd);
    fd = -1;
  }
}

ge::Status CreateSoMemFd(const std::string &file_name, const void *data, const size_t size, std::string &fd_path,
                         int32_t &fd) {
  GE_ASSERT_NOTNULL(data);
  GE_ASSERT_TRUE(size > 0U);
  CloseMemFd(fd);

  const auto short_name = ExtractParentDirAndFileName(file_name).second;
  fd = static_cast<int32_t>(syscall(__NR_memfd_create, short_name.c_str(), 0));
  GE_ASSERT_TRUE(fd >= 0, "[OM2][Create][MemFd] Failed, file=%s", file_name.c_str());
  GE_DISMISSABLE_GUARD(memfd_cleanup, [&fd]() { CloseMemFd(fd); });

  const auto write_count = mmWrite(fd, const_cast<void *>(data), size);
  GE_ASSERT_TRUE(write_count == static_cast<mmSsize_t>(size),
                 "[OM2][Write][MemFd] Failed, file=%s, size=%zu, write_count=%lld", file_name.c_str(), size,
                 static_cast<long long>(write_count));
  GE_ASSERT_TRUE(lseek(fd, 0, SEEK_SET) >= 0, "[OM2][Seek][MemFd] Failed, file=%s", file_name.c_str());

  fd_path = "/proc/" + std::to_string(getpid()) + "/fd/" + std::to_string(fd);
  GE_DISMISS_GUARD(memfd_cleanup);
  return ge::SUCCESS;
}

bool IsFileNameEndsWith(const std::string &file_name, const std::string &ext) {
  return file_name.size() >= ext.size() && file_name.compare(file_name.size() - ext.size(), ext.size(), ext) == 0;
}

ge::Status ExtractEntryToString(const ge::RAIIZipArchive &archive, const std::string &entry_name, std::string &out) {
  size_t buffer_size{0U};
  const auto buffer = archive.ExtractToMem(entry_name, buffer_size);
  GE_ASSERT_NOTNULL(buffer, "[OM2] Failed to extract entry %s", entry_name.c_str());
  GE_ASSERT_TRUE(buffer_size > 0U, "[OM2] Empty archive entry %s", entry_name.c_str());
  out.assign(reinterpret_cast<const char *>(buffer.get()), buffer_size);
  return ge::SUCCESS;
}

ge::Status ExtractEntryToBytes(const ge::RAIIZipArchive &archive, const std::string &entry_name,
                               std::vector<uint8_t> &out) {
  size_t buffer_size{0U};
  const auto buffer = archive.ExtractToMem(entry_name, buffer_size);
  GE_ASSERT_NOTNULL(buffer, "[OM2] Failed to extract entry %s", entry_name.c_str());
  GE_ASSERT_TRUE(buffer_size > 0U, "[OM2] Empty archive entry %s", entry_name.c_str());
  out.assign(buffer.get(), buffer.get() + buffer_size);
  return ge::SUCCESS;
}

ge::Status ParseTensorDescFromJson(const ge::JsonFile &json_file, ge::Om2TensorDesc &desc) {
  ge::JsonFile::TryGetAndApply<std::string>(json_file, "name", [&](const std::string &v) { desc.SetName(v); });
  ge::JsonFile::TryGetAndApply<std::vector<int64_t>>(json_file, "shape",
                                                     [&](const std::vector<int64_t> &v) { desc.SetShape(v); });
  ge::JsonFile::TryGetAndApply<std::string>(json_file, "data_type", [&](const std::string &v) {
    desc.SetDataType(ge::TypeUtilsInner::SerialStringToDataType(v));
  });
  ge::JsonFile::TryGetAndApply<std::string>(
      json_file, "format", [&](const std::string &v) { desc.SetFormat(ge::TypeUtilsInner::SerialStringToFormat(v)); });
  ge::JsonFile::TryGetAndApply<size_t>(json_file, "size", [&](const size_t &v) { desc.SetSize(v); });
  ge::JsonFile::TryGetAndApply<std::vector<std::pair<int64_t, int64_t>>>(
      json_file, "shape_range", [&](const std::vector<std::pair<int64_t, int64_t>> &v) { desc.SetShapeRange(v); });
  return ge::SUCCESS;
}

ge::Status ParseOpAttrMapJson(const uint8_t *data, size_t data_size,
                              std::map<std::string, std::map<std::string, std::string>> &op_attr_map) {
  try {
    const auto json_obj = ge::JsonFile::json::parse(data, data + data_size);
    if (!json_obj.is_object()) {
      GELOGW("[OM2] op_attr.json root is not an object");
      return ge::FAILED;
    }

    for (auto &[op_name, attrs] : json_obj.items()) {
      if (!attrs.is_object()) {
        GELOGW("[OM2] op_attr for %s is not an object", op_name.c_str());
        continue;
      }
      std::map<std::string, std::string> op_attrs;
      for (auto &[attr_name, value] : attrs.items()) {
        if (value.is_string()) {
          op_attrs[attr_name] = value.get<std::string>();
        } else {
          op_attrs[attr_name] = value.dump();
        }
      }
      op_attr_map[op_name] = op_attrs;
    }
    return ge::SUCCESS;
  } catch (const ge::JsonFile::json::exception &e) {
    GELOGE(ge::FAILED, "[OM2] Failed to parse op_attr.json: %s", e.what());
    return ge::FAILED;
  }
}

ge::Status DeserializeCodegenEntry(const ge::RAIIZipArchive &archive, const std::string &entry,
                                   gert::Om2ModelData &model_data) {
  ge::Om2CodegenArtifact artifact;
  artifact.file_name = ExtractParentDirAndFileName(entry).second;
  std::string content;
  GE_ASSERT_SUCCESS(ExtractEntryToString(archive, entry, content));
  artifact.data = std::move(content);
  model_data.program_body.so_artifact = std::move(artifact);
  return ge::SUCCESS;
}

ge::Status DeserializeWeightEntry(const ge::RAIIZipArchive &archive, const std::string &entry,
                                  gert::Om2ModelData &model_data) {
  GE_ASSERT_SUCCESS(ExtractEntryToBytes(archive, entry, model_data.constants_data.weight_data));
  return ge::SUCCESS;
}

ge::Status DeserializeConstantsConfigEntry(const ge::RAIIZipArchive &archive, const std::string &entry,
                                           gert::Om2ModelData &model_data) {
  size_t buff_size = 0U;
  auto buff_data = archive.ExtractToMem(entry, buff_size);
  GE_ASSERT_NOTNULL(buff_data, "[OM2] Failed to extract %s", entry.c_str());
  GE_ASSERT_TRUE(buff_size > 0U);
  const ge::JsonFile json_file(buff_data.get(), buff_size);
  GE_ASSERT_TRUE(json_file.IsValid(), "[OM2] Invalid constants config JSON from entry %s", entry.c_str());

  size_t internal_weight_size{0U};
  (void)json_file.Get("internal_weight_size", internal_weight_size);
  model_data.constants_data.internal_weight_size = internal_weight_size;

  ge::JsonFile::json consts_json;
  if (json_file.Get("consts", consts_json) && consts_json.is_object()) {
    for (auto &[key, val] : consts_json.items()) {
      (void)key;
      const ge::JsonFile val_file(val);
      ge::Om2ConstMeta meta;
      (void)val_file.Get("index", meta.index);
      (void)val_file.Get("type", meta.type);
      (void)val_file.Get("file_name", meta.file_name);
      (void)val_file.Get("file_path", meta.file_path);
      (void)val_file.Get("offset", meta.offset);
      (void)val_file.Get("size", meta.size);
      (void)val_file.Get("op_name", meta.op_name);
      (void)model_data.constants_data.consts.emplace_back(std::move(meta));
    }
  }
  return ge::SUCCESS;
}

ge::Status DeserializeKernelEntry(const ge::RAIIZipArchive &archive, const std::string &entry,
                                  gert::Om2ModelData &model_data) {
  gert::Om2KernelBinary kernel_binary;
  kernel_binary.name = ExtractParentDirAndFileName(entry).second;
  GE_ASSERT_SUCCESS(ExtractEntryToBytes(archive, entry, kernel_binary.data));
  (void)model_data.kernel_binaries.emplace_back(std::move(kernel_binary));
  return ge::SUCCESS;
}

ge::Status DeserializeModelMetaEntry(const ge::RAIIZipArchive &archive, const std::string &entry,
                                     gert::Om2ModelData &model_data) {
  size_t buff_size = 0U;
  auto buff_data = archive.ExtractToMem(entry, buff_size);
  GE_ASSERT_NOTNULL(buff_data, "[OM2] Failed to extract %s", entry.c_str());
  GE_ASSERT_TRUE(buff_size > 0U);
  const ge::JsonFile json_file(buff_data.get(), buff_size);
  GE_ASSERT_TRUE(json_file.IsValid(), "[OM2] Invalid model_meta.json");

  ge::JsonFile::json inputs_json;
  if (json_file.Get("inputs", inputs_json) && inputs_json.is_array()) {
    for (const auto &input_json : inputs_json) {
      const ge::JsonFile input_file(input_json);
      std::vector<int64_t> shape_v2;
      GE_ASSERT_TRUE(input_file.Get("shape_v2", shape_v2), "[OM2] input shape_v2 not found in model_meta.json");
      ge::Om2TensorDesc desc;
      GE_ASSERT_SUCCESS(ParseTensorDescFromJson(input_file, desc));
      model_data.model_meta.input_desc.emplace_back(desc);
      ge::Om2TensorDesc desc_v2 = desc;
      desc_v2.SetShape(shape_v2);
      model_data.model_meta.input_desc_v2.emplace_back(desc_v2);
      std::vector<int64_t> origin_input_dims;
      if (input_file.Get("origin_input_dims", origin_input_dims)) {
        model_data.model_meta.origin_input_dims.emplace_back(std::move(origin_input_dims));
      } else {
        (void)model_data.model_meta.origin_input_dims.emplace_back(desc.GetShape());
      }
    }
  }

  ge::JsonFile::json outputs_json;
  if (json_file.Get("outputs", outputs_json) && outputs_json.is_array()) {
    for (const auto &output_json : outputs_json) {
      const ge::JsonFile output_file(output_json);
      ge::Om2TensorDesc desc;
      GE_ASSERT_SUCCESS(ParseTensorDescFromJson(output_file, desc));
      model_data.model_meta.output_desc.emplace_back(desc);
      model_data.model_meta.output_desc_v2.emplace_back(desc);
    }
  }

  (void)json_file.Get("dynamic_output_shape", model_data.model_meta.dynamic_output_shape);
  (void)json_file.Get("dynamic_batch_info", model_data.model_meta.dynamic_batch_info);
  (void)json_file.Get("user_designate_shape_order", model_data.model_meta.user_designate_shape_order);
  (void)json_file.Get("dynamic_type", model_data.model_meta.dynamic_type);
  (void)json_file.Get("work_size", model_data.model_meta.work_size);
  (void)json_file.Get("zero_copy_size", model_data.model_meta.zero_copy_size);
  (void)json_file.Get("name", model_data.model_meta.model_name);
  (void)json_file.Get("root_graph_name", model_data.model_meta.root_graph_name);

  // 读取 aipp 字段
  ge::JsonFile aipp_json;
  if (json_file.Get("aipp", aipp_json) && aipp_json.IsValid()) {
    const ge::Status aipp_ret =
        om2::ParseAippJson(aipp_json, model_data.model_meta.aipp_infos, model_data.model_meta.has_aipp);
    if (aipp_ret != ge::SUCCESS) {
      GELOGW("[OM2][AIPP] ParseAippJson failed, ret=%u", aipp_ret);
    }
  }
  return ge::SUCCESS;
}

ge::Status DeserializeOpAttrEntry(const ge::RAIIZipArchive &archive, const std::string &entry,
                                  gert::Om2ModelData &model_data) {
  size_t buff_size = 0U;
  auto buff_data = archive.ExtractToMem(entry, buff_size);
  GE_ASSERT_NOTNULL(buff_data, "[OM2] Failed to extract %s", entry.c_str());
  GE_ASSERT_TRUE(buff_size > 0U);
  if (ParseOpAttrMapJson(buff_data.get(), buff_size, model_data.debug_info.op_attr_map) != ge::SUCCESS) {
    GELOGW("[OM2] Failed to parse op_attr.json, using empty map");
    model_data.debug_info.op_attr_map.clear();
  }
  return ge::SUCCESS;
}

ge::Status DeserializeVisualEntry(const ge::RAIIZipArchive &archive, const std::string &entry,
                                  gert::Om2ModelData &model_data) {
  GE_ASSERT_SUCCESS(ExtractEntryToString(archive, entry, model_data.debug_info.visual_json));
  return ge::SUCCESS;
}

ge::Status HandleArchiveEntry(const ge::RAIIZipArchive &archive, const std::string &entry,
                              gert::Om2ModelData &model_data) {
  if (entry.find("/runtime/") != std::string::npos && IsFileNameEndsWith(entry, ".so")) {
    GE_ASSERT_SUCCESS(DeserializeCodegenEntry(archive, entry, model_data));
    return ge::SUCCESS;
  }
  if (entry.find("/debug/") != std::string::npos) {
    if (IsFileNameEndsWith(entry, "op_attr.json")) {
      GE_ASSERT_SUCCESS(DeserializeOpAttrEntry(archive, entry, model_data));
    } else {
      const std::string debug_file = ExtractParentDirAndFileName(entry).second;
      if ((debug_file.find("ge_visual_") != std::string::npos) && IsFileNameEndsWith(debug_file, ".json")) {
        GE_ASSERT_SUCCESS(DeserializeVisualEntry(archive, entry, model_data));
      }
    }
    return ge::SUCCESS;
  }
  if (IsFileNameEndsWith(entry, "model_meta.json")) {
    GE_ASSERT_SUCCESS(DeserializeModelMetaEntry(archive, entry, model_data));
    return ge::SUCCESS;
  }
  if (entry.find("data/constants/") != std::string::npos) {
    if (IsFileNameEndsWith(entry, "_constants_config.json")) {
      GE_ASSERT_SUCCESS(DeserializeConstantsConfigEntry(archive, entry, model_data));
    } else if (entry.find("data/constants/constant_") != std::string::npos) {
      GE_ASSERT_SUCCESS(DeserializeWeightEntry(archive, entry, model_data));
    }
    return ge::SUCCESS;
  }
  if (entry.find("data/kernels_") != std::string::npos && IsFileNameEndsWith(entry, ".o")) {
    GE_ASSERT_SUCCESS(DeserializeKernelEntry(archive, entry, model_data));
  }
  return ge::SUCCESS;
}

ge::Status DeserializeOm2ModelDataFromArchive(ge::RAIIZipArchive &archive, gert::Om2ModelData &model_data) {
  const auto &entries = archive.ListFiles();
  if (entries.empty()) {
    GELOGE(ACL_ERROR_GE_PARAM_INVALID, "[OM2] ZIP archive is empty");
    return ACL_ERROR_GE_PARAM_INVALID;
  }

  for (const auto &entry : entries) {
    GE_ASSERT_SUCCESS(HandleArchiveEntry(archive, entry, model_data));
  }

  GE_ASSERT_TRUE(!model_data.model_meta.model_name.empty(), "[OM2] model_meta.json not found in ZIP archive.");
  GE_ASSERT_TRUE(!model_data.program_body.so_artifact.file_name.empty(),
                 "[OM2] Compiled .so not found in ZIP archive.");
  return ge::SUCCESS;
}

template <typename T>
ge::Status GetModelJsonValue(const std::string &key, T &out, const ge::JsonFile &json_file) {
  GE_ASSERT_TRUE(json_file.IsValid());
  GE_ASSERT_TRUE(json_file.Get(key, out));
  return ge::SUCCESS;
}

ge::Status SetTensorDesc(ge::JsonFile::json &tensor_array_json, std::vector<ge::Om2TensorDesc> &tensor_desc_array,
                         const bool new_model_desc = false) {
  for (ge::JsonFile::json &tensor : tensor_array_json) {
    ge::JsonFile tensor_obj{tensor};
    ge::Om2TensorDesc tensor_desc;
    std::string name;
    GE_ASSERT_TRUE(tensor_obj.Get("name", name));
    tensor_desc.SetName(name);
    std::string data_type;
    GE_ASSERT_TRUE(tensor_obj.Get("data_type", data_type));
    tensor_desc.SetDataType(ge::TypeUtilsInner::SerialStringToDataType(data_type));
    std::string format;
    GE_ASSERT_TRUE(tensor_obj.Get("format", format));
    tensor_desc.SetFormat(ge::TypeUtilsInner::SerialStringToFormat(format));
    int64_t size;
    GE_ASSERT_TRUE(tensor_obj.Get("size", size));
    tensor_desc.SetSize(static_cast<size_t>(size));
    std::string shape_key = new_model_desc ? "shape_v2" : "shape";
    std::vector<int64_t> shape_dims;
    GE_ASSERT_TRUE(tensor_obj.Get(shape_key, shape_dims));
    tensor_desc.SetShape(shape_dims);
    std::vector<std::pair<int64_t, int64_t>> shape_range;
    GE_ASSERT_TRUE(tensor_obj.Get("shape_range", shape_range));
    tensor_desc.SetShapeRange(shape_range);
    tensor_desc_array.emplace_back(tensor_desc);
  }
  return ge::SUCCESS;
}

uint64_t GetNextSessionId() {
  static std::atomic<uint64_t> atomic_session_id(0);
  return atomic_session_id.fetch_add(1);
}

uint64_t ResolveSessionId(const Om2ModelLoadArg &load_arg) {
  return (load_arg.rt_session == nullptr) ? GetNextSessionId() : load_arg.rt_session->GetSessionId();
}

ge::Status GetOm2MemAndWeightSizeFromArchive(ge::RAIIZipArchive &archive, size_t &work_size,
                                             size_t &internal_weight_size) {
  work_size = 0U;
  internal_weight_size = 0U;
  const auto file_names = archive.ListFiles();
  for (const auto &file_name : file_names) {
    if (IsFileNameEndsWith(file_name, "model_meta.json")) {
      size_t buff_size = 0UL;
      auto buff_data = archive.ExtractToMem(file_name, buff_size);
      GE_ASSERT_TRUE(buff_data != nullptr && buff_size != 0U);
      const ge::JsonFile model_meta_json(buff_data.get(), buff_size);
      GE_ASSERT_TRUE(model_meta_json.IsValid());
      GE_ASSERT_SUCCESS(GetModelJsonValue("work_size", work_size, model_meta_json));
      continue;
    }
    if (IsFileNameEndsWith(file_name, "_constants_config.json")) {
      size_t buff_size = 0UL;
      auto buff_data = archive.ExtractToMem(file_name, buff_size);
      GE_ASSERT_TRUE(buff_data != nullptr && buff_size != 0U);
      const ge::JsonFile constants_json(buff_data.get(), buff_size);
      GE_ASSERT_TRUE(constants_json.IsValid());
      (void)constants_json.Get("internal_weight_size", internal_weight_size);
      continue;
    }
  }
  return ge::SUCCESS;
}

ge::Status GetOm2ModelMetadataFromArchive(ge::RAIIZipArchive &archive, std::vector<ge::Om2TensorDesc> &input_desc,
                                          std::vector<ge::Om2TensorDesc> &input_desc_v2,
                                          std::vector<ge::Om2TensorDesc> &output_desc,
                                          std::vector<ge::Om2TensorDesc> &output_desc_v2) {
  const auto file_names = archive.ListFiles();
  for (const auto &file_name : file_names) {
    if (!IsFileNameEndsWith(file_name, "model_meta.json")) {
      continue;
    }
    size_t buff_size = 0UL;
    auto buff_data = archive.ExtractToMem(file_name, buff_size);
    GE_ASSERT_TRUE(buff_data != nullptr && buff_size != 0U);
    const ge::JsonFile model_meta_json(buff_data.get(), buff_size);
    GE_ASSERT_TRUE(model_meta_json.IsValid());

    ge::JsonFile::json inputs;
    GE_ASSERT_TRUE(model_meta_json.Get("inputs", inputs));
    GE_ASSERT_SUCCESS(SetTensorDesc(inputs, input_desc));
    GE_ASSERT_SUCCESS(SetTensorDesc(inputs, input_desc_v2, true));

    ge::JsonFile::json outputs;
    GE_ASSERT_TRUE(model_meta_json.Get("outputs", outputs));
    GE_ASSERT_SUCCESS(SetTensorDesc(outputs, output_desc));
    output_desc_v2 = output_desc;
    return ge::SUCCESS;
  }
  GE_ASSERT_TRUE(false, "[OM2] model_meta.json not found in archive.");
  return ge::FAILED;
}

ge::Status RtMallocBuffer(size_t size, void *&ptr) {
  ptr = nullptr;
  if (size == 0U) {
    return ge::SUCCESS;
  }
  const auto rt_ret = Om2Malloc(&ptr, size, RT_MEMORY_HBM, 0);
  if (rt_ret != ACL_SUCCESS) {
    GELOGE(ge::FAILED, "[OM2][Alloc] aclrtMalloc failed, size=%zu, rt_ret=%u", size, rt_ret);
    return ge::FAILED;
  }
  return ge::SUCCESS;
}

ge::Status RtMemcpyH2D(void *dst, size_t dst_size, const void *src, size_t size) {
  if (size == 0U) {
    return ge::SUCCESS;
  }
  const auto rt_ret = aclrtMemcpy(dst, dst_size, src, size, ACL_MEMCPY_HOST_TO_DEVICE);
  if (rt_ret != ACL_SUCCESS) {
    GELOGE(ge::FAILED, "[OM2][Memcpy] rtMemcpy H2D failed, size=%zu, rt_ret=%u", size, rt_ret);
    return ge::FAILED;
  }
  return ge::SUCCESS;
}

ge::Status ParseConstItems(const gert::Om2ConstantsData &config, std::vector<Om2ConstItem> &const_items,
                           size_t &internal_weight_size) {
  const_items.clear();
  internal_weight_size = config.internal_weight_size;

  for (const auto &meta : config.consts) {
    Om2ConstItem const_item;
    const_item.index = meta.index;
    const_item.type = meta.type;
    const_item.file_name = meta.file_name;
    if (const_item.type != "INTERNAL") {
      GE_ASSERT_TRUE(!const_item.file_name.empty());
    }
    const_item.offset = static_cast<size_t>(meta.offset);
    const_item.size = static_cast<size_t>(meta.size);
    const_items.emplace_back(const_item);
  }

  return ge::SUCCESS;
}

ge::Status ClassifyConstItems(const std::vector<Om2ConstItem> &const_items, ClassifiedConstItems &classified_items) {
  classified_items = ClassifiedConstItems();
  for (const auto &const_item : const_items) {
    classified_items.max_index = std::max(classified_items.max_index, const_item.index);
    if (const_item.type == "INTERNAL") {
      classified_items.internal_consts.emplace_back(const_item);
      continue;
    }
    if (const_item.type == "COMBINED") {
      classified_items.combined_consts.emplace_back(const_item);
      continue;
    }
    if (const_item.type == "INDIVIDUAL") {
      classified_items.individual_consts.emplace_back(const_item);
      continue;
    }
    GELOGE(ge::FAILED, "[OM2][Check] Unsupported const type, type=%s", const_item.type.c_str());
    return ge::FAILED;
  }
  return ge::SUCCESS;
}

}  // namespace

class Om2ModelExecutor::Impl {
 public:
  ge::Status LoadFromOm2ModelData(const gert::Om2ModelData &om2_data, ge::ReadonlyByteBuffer &weight_buf,
                                  std::vector<KernelBinInfo> &kernel_bin_info) {
    has_model_ = false;
    CloseMemFd(run_model_info_.so_fd);
    run_model_info_ = RunModelInfo();
    model_meta_info_ = ModelMetaInfo();
    weight_buf.reset(nullptr);
    kernel_bin_info.clear();

    GE_ASSERT_SUCCESS(LoadModelMetaFromStruct(om2_data.model_meta));
    has_model_ = true;

    GE_ASSERT_SUCCESS(BuildKernelBinInfoFromStruct(om2_data.kernel_binaries, kernel_bin_info));
    GE_ASSERT_SUCCESS(LoadSoFromBuffer(om2_data.program_body.so_artifact));
    GE_ASSERT_TRUE(!run_model_info_.so_file.empty(), "[OM2] Om2 compiled so not found in Om2ModelData.");

    // Set up op_attr_map from debug_info
    if (!om2_data.debug_info.op_attr_map.empty()) {
      run_model_info_.op_attr_map = om2_data.debug_info.op_attr_map;
    }

    // Create a non-owning ReadonlyByteBuffer from the weight_data vector
    if (!om2_data.constants_data.weight_data.empty()) {
      weight_buf = ge::ReadonlyByteBuffer(om2_data.constants_data.weight_data.data(), ge::ConditionalDeleter{false});
    }

    return ge::SUCCESS;
  }

 private:
  ge::Status LoadModelMetaFromStruct(const gert::Om2ModelMeta &meta) {
    run_model_info_.model_name = meta.model_name;
    run_model_info_.root_graph_name = meta.root_graph_name.empty() ? meta.model_name : meta.root_graph_name;
    model_meta_info_.work_size = meta.work_size;
    GE_ASSERT_TRUE(meta.zero_copy_size >= 0, "[OM2][Check] Invalid zero_copy_size=%ld.", meta.zero_copy_size);
    const auto zero_copy_size = static_cast<size_t>(meta.zero_copy_size);
    GE_ASSERT_TRUE(zero_copy_size <= meta.work_size,
                   "[OM2][Check] zero_copy_size exceeds work_size, zero_copy_size=%zu, work_size=%zu.", zero_copy_size,
                   meta.work_size);
    model_meta_info_.zero_copy_size = zero_copy_size;
    model_meta_info_.dynamic_batch_info = meta.dynamic_batch_info;
    model_meta_info_.dynamic_type = meta.dynamic_type;
    model_meta_info_.dynamic_output_shape = meta.dynamic_output_shape;
    model_meta_info_.user_designate_shape_order = meta.user_designate_shape_order;
    model_meta_info_.input_desc = meta.input_desc;
    model_meta_info_.input_desc_v2 = meta.input_desc_v2;
    model_meta_info_.origin_input_dims = meta.origin_input_dims;
    model_meta_info_.output_desc = meta.output_desc;
    model_meta_info_.output_desc_v2 = meta.output_desc_v2;
    has_aipp_ = meta.has_aipp;
    aipp_infos_ = meta.aipp_infos;
    return ge::SUCCESS;
  }

  ge::Status BuildKernelBinInfoFromStruct(const std::vector<gert::Om2KernelBinary> &kernels,
                                          std::vector<KernelBinInfo> &info) {
    info.clear();
    for (const auto &k : kernels) {
      KernelBinInfo bin_info;
      bin_info.file = k.name;
      // 创建非拥有引用:指向 Om2KernelBinary::data (vector<uint8_t>) 的内部缓冲区。
      // 生命周期约束:调用方必须保证 Om2ModelData 在 kernel 二进制使用期间保持存活。
      // 当前调用链:LoadOm2Graph → Om2ModelManager::LoadModel → executor->Load(model_data, ...)
      // 其中 model_data 通过 const & 传递,指向 GeRootModel 持有的 shared_ptr<Om2ModelData>,
      // 因此只要 GeRootModel 存活(通常在整个 Session 生命周期内),数据就安全。
      if (!k.data.empty()) {
        bin_info.data = ge::ReadonlyByteBuffer(k.data.data(), ge::ConditionalDeleter{false});
        bin_info.data_size = k.data.size();
      } else {
        bin_info.data_size = 0U;
      }
      info.push_back(std::move(bin_info));
    }
    return ge::SUCCESS;
  }

  ge::Status LoadSoFromBuffer(const ge::Om2CodegenArtifact &so) {
    if (so.data.empty() || so.file_name.empty()) {
      GELOGE(ge::FAILED, "[OM2] SO artifact data or file_name is empty.");
      return ge::FAILED;
    }
    GE_ASSERT_SUCCESS(
        CreateSoMemFd(so.file_name, so.data.data(), so.data.size(), run_model_info_.so_file, run_model_info_.so_fd));
    return ge::SUCCESS;
  }

 public:
  ge::Status LoadSharedObject() {
    GELOGI("[OM2] Begin loading so file %s", run_model_info_.so_file.c_str());
    GE_ASSERT_TRUE(!run_model_info_.so_file.empty());
    run_model_info_.so_handle = mmDlopen(run_model_info_.so_file.c_str(), MMPA_RTLD_NOW);
    if (run_model_info_.so_handle == nullptr) {
      const char_t *error = mmDlerror();
      error = (error == nullptr) ? "" : error;
      GELOGE(ge::FAILED, "[OM2][Invoke][DlOpen] Failed to  load so, path = [%s], error = [%s]",
             run_model_info_.so_file.c_str(), error);
      return ge::FAILED;
    }
    return ge::SUCCESS;
  }

  ge::Status ResolveSymbols() {
    GE_ASSERT_TRUE(run_model_info_.so_handle != nullptr);
    run_model_info_.create_func = reinterpret_cast<CreateFunc>(mmDlsym(run_model_info_.so_handle, "Om2ModelCreate"));
    GE_ASSERT_NOTNULL(run_model_info_.create_func);
    run_model_info_.load_func = reinterpret_cast<LoadFunc>(mmDlsym(run_model_info_.so_handle, "Om2ModelLoad"));
    GE_ASSERT_NOTNULL(run_model_info_.load_func);
    run_model_info_.destroy_func = reinterpret_cast<DestroyFunc>(mmDlsym(run_model_info_.so_handle, "Om2ModelDestroy"));
    GE_ASSERT_NOTNULL(run_model_info_.destroy_func);
    run_model_info_.run_func = reinterpret_cast<RunFunc>(mmDlsym(run_model_info_.so_handle, "Om2ModelRun"));
    GE_ASSERT_NOTNULL(run_model_info_.run_func);
    run_model_info_.run_async_func =
        reinterpret_cast<RunAsyncFunc>(mmDlsym(run_model_info_.so_handle, "Om2ModelRunAsync"));
    GE_ASSERT_NOTNULL(run_model_info_.run_async_func);
    return ge::SUCCESS;
  }

  ge::Status PrepareConstantsFromStruct(const gert::Om2ConstantsData &constants_data,
                                        const ge::ReadonlyByteBuffer &weight_buf, const Om2ModelLoadArg &load_arg,
                                        std::vector<void *> &constants) {
    std::vector<Om2ConstItem> const_items;
    size_t internal_weight_size = 0U;
    GE_ASSERT_SUCCESS(ParseConstItems(constants_data, const_items, internal_weight_size));
    if (const_items.empty()) {
      return ge::SUCCESS;
    }
    ClassifiedConstItems classified_items;
    GE_ASSERT_SUCCESS(ClassifyConstItems(const_items, classified_items));
    constants.resize(classified_items.max_index + 1U, nullptr);
    std::map<std::string, ge::FileConstantMem> user_file_const_mems;
    GE_ASSERT_SUCCESS(BuildUserFileConstMemMap(load_arg.file_constant_mems, user_file_const_mems));
    GE_ASSERT_SUCCESS(
        PrepareInternalConsts(weight_buf, load_arg, classified_items.internal_consts, internal_weight_size, constants));
    GE_ASSERT_SUCCESS(PrepareCombinedConsts(load_arg.weight_path, load_arg.om_path, user_file_const_mems,
                                            classified_items.combined_consts, constants));
    GE_ASSERT_SUCCESS(PrepareIndividualConsts(load_arg.weight_path, load_arg.om_path, user_file_const_mems,
                                              classified_items.individual_consts, constants));
    return ge::SUCCESS;
  }

  ge::Status CreateModelFromStruct(const gert::Om2ConstantsData &constants_data, ge::ReadonlyByteBuffer &weight_buf,
                                   std::vector<KernelBinInfo> &kernel_bin_info, const Om2ModelLoadArg &load_arg,
                                   uint64_t session_id, std::vector<void *> &constants) {
    GE_ASSERT_TRUE(has_model_);
    GE_ASSERT_TRUE(load_arg.device_id >= 0, "[OM2][Check] Invalid device id.");
    device_id_ = load_arg.device_id;
    std::vector<const char *> bin_files(kernel_bin_info.size());
    std::vector<const void *> bin_data(kernel_bin_info.size());
    std::vector<size_t> bin_sizes(kernel_bin_info.size());
    void *work_ptr = nullptr;
    for (auto i = 0U; i < kernel_bin_info.size(); ++i) {
      bin_files[i] = kernel_bin_info[i].file.c_str();
      bin_data[i] = kernel_bin_info[i].data.get();
      bin_sizes[i] = kernel_bin_info[i].data_size;
    }
    session_id_ = session_id;
    GE_ASSERT_SUCCESS(PrepareWorkPtr(load_arg, work_ptr));
    GE_ASSERT_SUCCESS(PrepareConstantsFromStruct(constants_data, weight_buf, load_arg, constants));
    GE_ASSERT_SUCCESS(run_model_info_.create_func(
        &run_model_info_.model_handle, &run_model_info_.rt_model_handle, bin_files.data(), bin_data.data(),
        bin_sizes.data(), static_cast<int>(bin_data.size()), constants.empty() ? nullptr : constants.data(), work_ptr,
        &session_id_, load_arg.model_id, dump_manager_.get()));
    return ge::GRAPH_SUCCESS;
  }

  ge::Status CreateAndLoadModelFromStruct(const gert::Om2ConstantsData &constants_data,
                                          ge::ReadonlyByteBuffer &weight_buf,
                                          std::vector<KernelBinInfo> &kernel_bin_info, const Om2ModelLoadArg &load_arg,
                                          uint64_t session_id) {
    // The generated model consumes this pointer array during create/load, so keep it alive until LoadModel returns.
    std::vector<void *> constants;
    GE_ASSERT_SUCCESS(
        CreateModelFromStruct(constants_data, weight_buf, kernel_bin_info, load_arg, session_id, constants));
    GE_ASSERT_SUCCESS(InitModelDumpInfo(load_arg));
    ReportModelLoadBegin();
    GE_ASSERT_SUCCESS(LoadModel());
    ReportModelLoadEnd();
    GE_ASSERT_SUCCESS(DispatchDumpInfo());
    weight_buf.reset(nullptr);
    kernel_bin_info.clear();
    return ge::GRAPH_SUCCESS;
  }

  ge::Status CreateDumpManager(const Om2ModelLoadArg &load_arg) {
    model_id_ = load_arg.model_id;
    dump_manager_ =
        std::unique_ptr<ge::dump::ModelDumpManager>(new (std::nothrow) ge::dump::ModelDumpManager(load_arg.model_id));
    GE_ASSERT_TRUE(dump_manager_ != nullptr);
    dump_manager_->SetClearDfxCacheFlagAfterLoad(load_arg.need_clear_dfx_cache);
    return ge::SUCCESS;
  }

  ge::Status InitModelDumpInfo(const Om2ModelLoadArg &load_arg) {
    GE_ASSERT_NOTNULL(run_model_info_.rt_model_handle);
    GE_ASSERT_TRUE(dump_manager_ != nullptr);
    ge::dump::ModelDumpInfo model_dump_info{};
    model_dump_info.model_id = load_arg.model_id;
    model_dump_info.model_name = run_model_info_.model_name.c_str();
    model_dump_info.root_graph_name = run_model_info_.root_graph_name.c_str();
    model_dump_info.device_id = static_cast<uint32_t>(load_arg.device_id);
    model_dump_info.rt_model_handle = run_model_info_.rt_model_handle;
    model_dump_info.step_id_addr = 0U;
    model_dump_info.loop_cond_addr = 0U;
    model_dump_info.iterations_per_loop_addr = 0U;
    GELOGI(
        "[OM2][Dump] Set model dump info: model_id=%u, model_name=%s, root_graph_name=%s, device_id=%u, "
        "rt_model_handle=%p, step_id_addr=%" PRIu64 ", loop_cond_addr=%" PRIu64 ", iterations_per_loop_addr=%" PRIu64
        ".",
        model_dump_info.model_id, model_dump_info.model_name, model_dump_info.root_graph_name,
        model_dump_info.device_id, model_dump_info.rt_model_handle, model_dump_info.step_id_addr,
        model_dump_info.loop_cond_addr, model_dump_info.iterations_per_loop_addr);
    GE_ASSERT_SUCCESS(dump_manager_->SetModelDumpInfo(model_dump_info));
    GELOGI("[OM2][Dump] Set model dump info success, model_id=%u.", model_dump_info.model_id);
    return ge::SUCCESS;
  }

  void ReportModelLoadBegin() const {
    if (dump_manager_ == nullptr) {
      return;
    }
    const ge::Status ret = dump_manager_->ReportModelLoadBegin();
    if (ret != ge::SUCCESS) {
      GELOGW("[OM2][Profiling] Report model load begin failed, model_id=%u, ret=%u.", model_id_, ret);
    }
  }

  void ReportModelLoadEnd() const {
    if (dump_manager_ == nullptr) {
      return;
    }
    const ge::Status ret = dump_manager_->ReportModelLoadEnd();
    if (ret != ge::SUCCESS) {
      GELOGW("[OM2][Profiling] Report model load end failed, model_id=%u, ret=%u.", model_id_, ret);
    }
  }

  ge::Status LoadModel() {
    GE_ASSERT_NOTNULL(run_model_info_.load_func);
    GE_ASSERT_NOTNULL(run_model_info_.model_handle);
    GE_ASSERT_SUCCESS(run_model_info_.load_func(&run_model_info_.model_handle));
    return ge::SUCCESS;
  }

  ge::Status DispatchDumpInfo() {
    GE_ASSERT_TRUE(dump_manager_ != nullptr);
    GELOGI("[OM2][Dump] Dispatch dump info begin, model_id=%u, model_name=%s, root_graph_name=%s.", model_id_,
           run_model_info_.model_name.c_str(), run_model_info_.root_graph_name.c_str());
    GE_ASSERT_SUCCESS(dump_manager_->DispatchDumpInfo());
    GELOGI("[OM2][Dump] Dispatch dump info success, model_id=%u, model_name=%s, root_graph_name=%s.", model_id_,
           run_model_info_.model_name.c_str(), run_model_info_.root_graph_name.c_str());
    return ge::SUCCESS;
  }

  ge::Status Run(std::vector<gert::Tensor *> &inputs, std::vector<gert::Tensor *> &outputs) {
    GE_ASSERT_TRUE(has_model_);
    GE_ASSERT_NOTNULL(run_model_info_.run_func);
    GE_ASSERT_NOTNULL(run_model_info_.model_handle);
    int32_t timeout = GetOm2ThreadLocalContext().StreamSyncTimeout();
    Om2ProfUnit prof_units[OM2_PROF_TYPE_COUNT];
    Om2ProfInfos prof_info = {kOm2ProfInfosVersion, 0, prof_units, step_id_};
    Om2ProfInfos *prof_info_ptr = dump_manager_ != nullptr ? &prof_info : nullptr;
    GE_ASSERT_SUCCESS(run_model_info_.run_func(&run_model_info_.model_handle, inputs.size(),
                                               reinterpret_cast<void **>(inputs.data()), outputs.size(),
                                               reinterpret_cast<void **>(outputs.data()), timeout, prof_info_ptr));
    if (prof_info_ptr != nullptr) {
      GELOGD("[OM2][Prof] Run done, model_id=%u, prof_count=%u, step_id=%lu", model_id_, prof_info.count, step_id_);
      dump_manager_->ReportModelLevelProf(prof_info);
    } else {
      GELOGD("[OM2][Prof] Run skip, dump_manager is null, model_id=%u", model_id_);
    }
    ++step_id_;
    return ge::GRAPH_SUCCESS;
  }

  ge::Status RunAsync(void *const stream, std::vector<gert::Tensor *> &inputs, std::vector<gert::Tensor *> &outputs) {
    GE_ASSERT_TRUE(has_model_);
    GE_ASSERT_NOTNULL(run_model_info_.run_async_func);
    GE_ASSERT_NOTNULL(run_model_info_.model_handle);
    Om2ProfUnit prof_units[OM2_PROF_TYPE_COUNT];
    Om2ProfInfos prof_info = {kOm2ProfInfosVersion, 0, prof_units, step_id_};
    Om2ProfInfos *prof_info_ptr = dump_manager_ != nullptr ? &prof_info : nullptr;
    GE_ASSERT_SUCCESS(run_model_info_.run_async_func(&run_model_info_.model_handle, stream, inputs.size(),
                                                     reinterpret_cast<void **>(inputs.data()), outputs.size(),
                                                     reinterpret_cast<void **>(outputs.data()), prof_info_ptr));
    if (prof_info_ptr != nullptr) {
      GELOGD("[OM2][Prof] RunAsync done, model_id=%u, prof_count=%u, step_id=%lu", model_id_, prof_info.count,
             step_id_);
      dump_manager_->ReportModelLevelProf(prof_info);
    } else {
      GELOGD("[OM2][Prof] RunAsync skip, dump_manager is null, model_id=%u", model_id_);
    }
    ++step_id_;
    return ge::GRAPH_SUCCESS;
  }

  ge::Status GetDynamicBatchInfo(std::vector<std::vector<int64_t>> &dynamic_batch_info, int32_t &dynamic_type) const {
    GE_ASSERT_TRUE(has_model_);
    dynamic_batch_info = model_meta_info_.dynamic_batch_info;
    dynamic_type = model_meta_info_.dynamic_type;
    return ge::SUCCESS;
  }

  ge::Status GetModelAttrs(std::vector<std::string> &dynamic_output_shape) const {
    GE_ASSERT_TRUE(has_model_);
    dynamic_output_shape = model_meta_info_.dynamic_output_shape;
    return ge::SUCCESS;
  }

  ge::Status GetModelDescInfo(const std::vector<ge::Om2TensorDesc> *&input_desc,
                              const std::vector<ge::Om2TensorDesc> *&output_desc, const bool new_model_desc) const {
    GE_ASSERT_TRUE(has_model_);
    if (new_model_desc) {
      input_desc = &model_meta_info_.input_desc_v2;
      output_desc = &model_meta_info_.output_desc_v2;
    } else {
      input_desc = &model_meta_info_.input_desc;
      output_desc = &model_meta_info_.output_desc;
    }
    return ge::SUCCESS;
  }

  ge::Status GetUserDesignateShapeOrder(std::vector<std::string> &user_designate_shape_order) const {
    GE_ASSERT_TRUE(has_model_);
    user_designate_shape_order = model_meta_info_.user_designate_shape_order;
    return ge::SUCCESS;
  }

  const std::vector<std::vector<int64_t>> &GetOriginInputDims() const {
    return model_meta_info_.origin_input_dims;
  }

  ge::Status GetOpAttr(std::map<std::string, std::map<std::string, std::string>> &op_attr_map) const {
    GE_ASSERT_TRUE(has_model_);
    op_attr_map.clear();

    if (run_model_info_.op_attr_map.empty()) {
      return ge::SUCCESS;  // Empty map
    }

    op_attr_map = run_model_info_.op_attr_map;
    return ge::SUCCESS;
  }

  ge::Status GetOpDescInfo(const uint32_t device_id, const uint32_t stream_id, const uint32_t task_id,
                           ge::OpDescInfo &op_desc_info) const {
    GE_ASSERT_TRUE(has_model_);
    if (device_id_ != static_cast<int32_t>(device_id)) {
      GELOGD("[OM2][Get][OpDescInfo] Device id not match, input=%u, model=%d.", device_id, device_id_);
      return ge::FAILED;
    }
    GE_ASSERT_NOTNULL(dump_manager_);
    return dump_manager_->GetOpDescInfo(ge::OpDescInfoId(task_id, stream_id, static_cast<int32_t>(device_id)),
                                        op_desc_info)
               ? ge::SUCCESS
               : ge::FAILED;
  }

  ge::Status SetDynamicSize(const std::vector<uint64_t> &batch_num, const int32_t dynamic_type) {
    GE_ASSERT_TRUE(has_model_);

    int32_t model_dynamic_type = static_cast<int32_t>(ge::FIXED);
    std::vector<std::vector<int64_t>> dynamic_batch_info;
    ge::Status ret = GetDynamicBatchInfo(dynamic_batch_info, model_dynamic_type);
    if (ret != ge::SUCCESS) {
      GELOGE(ge::FAILED, "[OM2][SetDynamicSize] GetDynamicBatchInfo failed, ret=%u.", ret);
      return ge::FAILED;
    }

    if (dynamic_type != model_dynamic_type) {
      GELOGE(ge::FAILED, "[OM2][SetDynamicSize] dynamic_type mismatch: requested %d, model compiled with %d.",
             dynamic_type, model_dynamic_type);
      return ge::FAILED;
    }

    std::vector<int64_t> requested_gear;
    requested_gear.reserve(batch_num.size());
    for (const auto v : batch_num) {
      requested_gear.push_back(static_cast<int64_t>(v));
    }

    bool gear_found = false;
    for (const auto &gear : dynamic_batch_info) {
      if (gear == requested_gear) {
        gear_found = true;
        break;
      }
    }

    if (!gear_found) {
      GELOGE(ge::FAILED, "[OM2][SetDynamicSize] Requested gear not found in dynamic_batch_info.");
      return ge::FAILED;
    }

    cur_batch_size_ = batch_num;
    dynamic_type_ = dynamic_type;
    GELOGI("[OM2][SetDynamicSize] Set dynamic size success, type=%d, size=%zu.", dynamic_type_, cur_batch_size_.size());
    return ge::SUCCESS;
  }

  ge::Status GetCurrentShape(std::vector<int64_t> &batch_info, int32_t &dynamic_type) const {
    GE_ASSERT_TRUE(has_model_);
    batch_info.clear();
    if (cur_batch_size_.empty()) {
      GELOGD("[OM2][GetCurrentShape] User has not set dynamic size.");
      dynamic_type = static_cast<int32_t>(ge::FIXED);
      return ge::SUCCESS;
    }
    for (const auto v : cur_batch_size_) {
      batch_info.emplace_back(static_cast<int64_t>(v));
    }
    dynamic_type = dynamic_type_;
    return ge::SUCCESS;
  }

  ge::Status GetAippInfo(const uint32_t index, ge::AippConfigInfo &aipp_info) const {
    if (!has_aipp_ || index >= aipp_infos_.size()) {
      return ACL_ERROR_GE_AIPP_NOT_EXIST;
    }
    if (aipp_infos_[index].aipp_type == ge::DATA_WITHOUT_AIPP) {
      return ACL_ERROR_GE_AIPP_NOT_EXIST;
    }
    aipp_info = aipp_infos_[index].aipp_config_info;
    return ge::SUCCESS;
  }

  ge::Status GetAippType(const uint32_t index, ge::InputAippType &aipp_type, size_t &aipp_data_index) const {
    if (!has_aipp_ || index >= aipp_infos_.size()) {
      aipp_type = ge::DATA_WITHOUT_AIPP;
      aipp_data_index = 0xFFFFFFFFU;
      return ge::SUCCESS;
    }
    aipp_type = aipp_infos_[index].aipp_type;
    aipp_data_index = aipp_infos_[index].aipp_data_index;
    return ge::SUCCESS;
  }

  ge::Status GetOrigInputInfo(const uint32_t index, ge::OriginInputInfo &orig_input_info) const {
    if (!has_aipp_ || index >= aipp_infos_.size()) {
      return ACL_ERROR_GE_AIPP_NOT_EXIST;
    }
    if (aipp_infos_[index].aipp_type == ge::DATA_WITHOUT_AIPP) {
      return ACL_ERROR_GE_AIPP_NOT_EXIST;
    }
    const auto &input_info = aipp_infos_[index].orig_input_info;
    if ((input_info.format != ge::FORMAT_RESERVED) || (input_info.data_type != ge::DT_UNDEFINED)) {
      orig_input_info = input_info;
    }
    return ge::SUCCESS;
  }

  ge::Status GetAllAippInputOutputDims(const uint32_t index, std::vector<ge::InputOutputDims> &input_dims,
                                       std::vector<ge::InputOutputDims> &output_dims) const {
    if (!has_aipp_ || index >= aipp_infos_.size()) {
      return ACL_ERROR_GE_AIPP_NOT_EXIST;
    }
    if (aipp_infos_[index].aipp_type == ge::DATA_WITHOUT_AIPP) {
      return ACL_ERROR_GE_AIPP_NOT_EXIST;
    }
    input_dims = aipp_infos_[index].aipp_input_dims;
    output_dims = aipp_infos_[index].aipp_output_dims;
    return ge::SUCCESS;
  }

  ge::Status GetBatchInfoSize(size_t &shape_count) const {
    std::vector<std::vector<int64_t>> batch_info;
    int32_t dynamic_type = 0;
    const auto ret = GetDynamicBatchInfo(batch_info, dynamic_type);
    if (ret != ge::SUCCESS) {
      return ret;
    }
    if (batch_info.empty()) {
      shape_count = 1U;
    } else {
      shape_count = batch_info.size();
    }
    return ge::SUCCESS;
  }

  ge::Status SetDynamicAippData(void *dynamic_input_addr, const uint64_t length,
                                const std::vector<kAippDynamicBatchPara> &aipp_batch_para,
                                const kAippDynamicPara &aipp_parms) {
    if (dynamic_input_addr == nullptr) {
      REPORT_INNER_ERR_MSG("E19999", "Param dynamic_input_addr is nullptr, check invalid");
      GELOGE(ACL_ERROR_GE_DYNAMIC_INPUT_ADDR_INVALID, "[Check][Param] Dynamic aipp input addr is nullptr");
      return ACL_ERROR_GE_DYNAMIC_INPUT_ADDR_INVALID;
    }
    if (aipp_batch_para.empty()) {
      REPORT_INNER_ERR_MSG("E19999", "Param aipp_batch_para is empty, check invalid");
      GELOGE(ACL_ERROR_GE_AIPP_BATCH_EMPTY, "[Check][Param] aipp_batch_para is empty");
      return ACL_ERROR_GE_AIPP_BATCH_EMPTY;
    }
    const uint64_t batch_num = aipp_batch_para.size();
    constexpr uint64_t real_aipp_params_size = sizeof(kAippDynamicPara) - sizeof(kAippDynamicBatchPara);
    const uint64_t struct_len = (batch_num * sizeof(kAippDynamicBatchPara)) + real_aipp_params_size;
    if (struct_len > length) {
      REPORT_INNER_ERR_MSG("E19999", "input dynamic aipp param len:%" PRIu64 " is larger than aipp_data size:%" PRIu64,
                           struct_len, length);
      GELOGE(ACL_ERROR_GE_DYNAMIC_INPUT_LENGTH_INVALID,
             "[Check][Param] input dynamic aipp param len [%" PRIu64 "] is larger than aipp_data size [%" PRIu64 "]",
             struct_len, length);
      return ACL_ERROR_GE_DYNAMIC_INPUT_LENGTH_INVALID;
    }
    aclError rt_ret =
        aclrtMemcpy(dynamic_input_addr, length, &aipp_parms, real_aipp_params_size, ACL_MEMCPY_HOST_TO_DEVICE);
    if (rt_ret != ACL_SUCCESS) {
      REPORT_INNER_ERR_MSG("E19999", "Call aclrtMemcpy failed, size:%" PRIu64 ", ret:%d", length, rt_ret);
      GELOGE(ge::FAILED, "[Call][aclrtMemcpy] memcpy aipp_parms failed! size:%" PRIu64 ", ret:%d", length, rt_ret);
      return ge::FAILED;
    }
    for (uint64_t i = 0U; i < batch_num; ++i) {
      const uint64_t offset = real_aipp_params_size + (i * sizeof(kAippDynamicBatchPara));
      rt_ret = aclrtMemcpy(static_cast<uint8_t *>(dynamic_input_addr) + offset, length - offset, &aipp_batch_para[i],
                           sizeof(kAippDynamicBatchPara), ACL_MEMCPY_HOST_TO_DEVICE);
      if (rt_ret != ACL_SUCCESS) {
        REPORT_INNER_ERR_MSG("E19999", "Call aclrtMemcpy failed, ret:%d", rt_ret);
        GELOGE(ge::FAILED, "[Call][aclrtMemcpy] memcpy kAippDynamicBatchPara input data failed! ret:%d", rt_ret);
        return ge::FAILED;
      }
    }
    return ge::SUCCESS;
  }

  void Cleanup() {
    if (dump_manager_ != nullptr) {
      dump_manager_.reset();
    }
    if (run_model_info_.destroy_func != nullptr && run_model_info_.model_handle != nullptr) {
      const auto destroy_ret = run_model_info_.destroy_func(&run_model_info_.model_handle);
      if (destroy_ret != ge::GRAPH_SUCCESS) {
        GELOGI("[OM2] Resource release issue for so file: %s", run_model_info_.so_file.c_str());
      }
    } else {
      GELOGI("[OM2] Destroy func not found or model not created, so file: %s", run_model_info_.so_file.c_str());
    }
    if (run_model_info_.so_handle != nullptr) {
      if (mmDlclose(run_model_info_.so_handle) != 0) {
        const char_t *error = mmDlerror();
        error = (error == nullptr) ? "" : error;
        GELOGI("[OM2][Dlclose] path = %s, error = %s", run_model_info_.so_file.c_str(), error);
      }
      run_model_info_.so_handle = nullptr;
    }
    CloseMemFd(run_model_info_.so_fd);
    ReleaseOwnedMemory();
    // Currently only the non-shared OM2 path is supported, so the executor releases session-level managers here.
    // When bundle model or shared RtSession is supported, add a condition to avoid releasing shared resources.
    Om2VarManagerPool::Instance().RemoveManager(session_id_);
    Om2ExternalWeightManagerPool::Instance().RemoveManager(session_id_);
  }

 private:
  ge::Status PrepareWorkPtr(const Om2ModelLoadArg &load_arg, void *&work_ptr) {
    const size_t required_work_size = load_arg.reuse_zero_copy
                                          ? model_meta_info_.work_size - model_meta_info_.zero_copy_size
                                          : model_meta_info_.work_size;
    if (load_arg.work_ptr != nullptr) {
      work_ptr = load_arg.work_ptr;
      return ge::SUCCESS;
    }
    void *inner_work_ptr = nullptr;
    GE_ASSERT_SUCCESS(RtMallocBuffer(required_work_size, inner_work_ptr));
    if (inner_work_ptr != nullptr) {
      owned_buffers_.push_back(inner_work_ptr);
    }
    work_ptr = inner_work_ptr;
    return ge::SUCCESS;
  }

  ge::Status PrepareInternalConsts(const ge::ReadonlyByteBuffer &weight_buf, const Om2ModelLoadArg &load_arg,
                                   const std::vector<Om2ConstItem> &const_items, size_t internal_weight_size,
                                   std::vector<void *> &constants) {
    if (const_items.empty()) {
      return ge::SUCCESS;
    }
    GE_ASSERT_TRUE(weight_buf != nullptr, "[OM2][Check] Missing internal host weight buffer.");
    const void *host_weight_base = weight_buf.get();
    void *device_weight_base = load_arg.weight_ptr;
    if (device_weight_base != nullptr) {
      GE_ASSERT_TRUE(load_arg.weight_size >= internal_weight_size, "[OM2][Check] Invalid external device weight size.");
    } else {
      GE_ASSERT_SUCCESS(RtMallocBuffer(internal_weight_size, device_weight_base));
      if (device_weight_base != nullptr) {
        owned_buffers_.push_back(device_weight_base);
      }
    }
    GE_ASSERT_SUCCESS(RtMemcpyH2D(device_weight_base, internal_weight_size, host_weight_base, internal_weight_size));
    auto *device_weight_bytes = static_cast<uint8_t *>(device_weight_base);
    for (const auto &const_item : const_items) {
      GE_ASSERT_TRUE((const_item.offset + const_item.size) <= internal_weight_size,
                     "[OM2][Check] Invalid INTERNAL const offset or size.");
      constants[const_item.index] = device_weight_bytes + const_item.offset;
    }
    return ge::SUCCESS;
  }

  ge::Status PrepareCombinedConsts(const std::string &weight_path, const std::string &om_path,
                                   const std::map<std::string, ge::FileConstantMem> &user_file_const_mems,
                                   const std::vector<Om2ConstItem> &const_items, std::vector<void *> &constants) {
    if (const_items.empty()) {
      return ge::SUCCESS;
    }
    FileConstContext file_const_ctx;
    GE_ASSERT_SUCCESS(BuildFileConstContext(weight_path, om_path, user_file_const_mems, file_const_ctx));
    GE_ASSERT_SUCCESS(gert::PrepareCombinedConsts(const_items, file_const_ctx, constants));
    return ge::SUCCESS;
  }

  ge::Status PrepareIndividualConsts(const std::string &weight_path, const std::string &om_path,
                                     const std::map<std::string, ge::FileConstantMem> &user_file_const_mems,
                                     const std::vector<Om2ConstItem> &const_items, std::vector<void *> &constants) {
    if (const_items.empty()) {
      return ge::SUCCESS;
    }
    FileConstContext file_const_ctx;
    GE_ASSERT_SUCCESS(BuildFileConstContext(weight_path, om_path, user_file_const_mems, file_const_ctx));
    GE_ASSERT_SUCCESS(gert::PrepareIndividualConsts(const_items, file_const_ctx, device_id_, constants));
    return ge::SUCCESS;
  }

  ge::Status BuildFileConstContext(const std::string &weight_path, const std::string &om_path,
                                   const std::map<std::string, ge::FileConstantMem> &user_file_const_mems,
                                   FileConstContext &file_const_ctx) {
    std::string weight_dir;
    GE_ASSERT_SUCCESS(ResolveFileConstWeightDir(weight_path, om_path, weight_dir));
    file_const_ctx.weight_dir = weight_dir;
    file_const_ctx.user_file_const_mems = &user_file_const_mems;
    file_const_ctx.owned_buffers = &owned_buffers_;
    file_const_ctx.session_id = session_id_;
    file_const_ctx.device_id = device_id_;
    return ge::SUCCESS;
  }

  void ReleaseOwnedMemory() {
    for (auto iter = owned_buffers_.rbegin(); iter != owned_buffers_.rend(); ++iter) {
      if (*iter != nullptr) {
        (void)aclrtFree(*iter);
      }
    }
    owned_buffers_.clear();
  }

  RunModelInfo run_model_info_;
  ModelMetaInfo model_meta_info_;
  std::unique_ptr<ge::dump::ModelDumpManager> dump_manager_;
  std::vector<void *> owned_buffers_;
  uint32_t model_id_ = 0U;
  int32_t device_id_ = -1;
  uint64_t session_id_ = 0U;
  bool has_model_ = false;
  uint64_t step_id_ = 1U;
  // 当前档位维度值,由 SetDynamicSize 写入,GetCurrentShape 读取
  std::vector<uint64_t> cur_batch_size_;
  int32_t dynamic_type_ = 0;  // 0=FIXED
  std::vector<Om2AippInfo> aipp_infos_;
  bool has_aipp_ = false;
};

Om2ModelExecutor::Om2ModelExecutor() : impl_(std::make_unique<Impl>()) {}

Om2ModelExecutor::~Om2ModelExecutor() {
  if (impl_) {
    impl_->Cleanup();
  }
}

ge::Status Om2ModelExecutor::Load(ge::ModelData &model_data, const Om2ModelLoadArg &load_arg,
                                  const uint64_t session_id) const {
  gert::Om2ModelData om2_data;
  ge::RAIIZipArchive archive(static_cast<const uint8_t *>(model_data.model_data), model_data.model_len);
  if (!archive.IsGood()) {
    GELOGE(ACL_ERROR_GE_PARAM_INVALID, "[OM2] Failed to open OM2 ZIP archive for deserialization");
    return ACL_ERROR_GE_PARAM_INVALID;
  }
  GE_ASSERT_SUCCESS(DeserializeOm2ModelDataFromArchive(archive, om2_data));
  Om2ModelLoadArg load_arg_with_path = load_arg;
  load_arg_with_path.om_path = model_data.om_path;
  load_arg_with_path.weight_path = model_data.weight_path;
  return Load(om2_data, load_arg_with_path, session_id);
}

ge::Status Om2ModelExecutor::Load(const gert::Om2ModelData &model_data, const Om2ModelLoadArg &load_arg,
                                  const uint64_t session_id) const {
  ge::ReadonlyByteBuffer weight_buf;
  std::vector<KernelBinInfo> kernel_bin_info;
  GE_CHK_STATUS_RET(impl_->LoadFromOm2ModelData(model_data, weight_buf, kernel_bin_info),
                    "[OM2][Load] Load from Om2ModelData failed.");
  GE_ASSERT_SUCCESS(impl_->LoadSharedObject());
  GE_ASSERT_SUCCESS(impl_->ResolveSymbols());
  GE_ASSERT_SUCCESS(impl_->CreateDumpManager(load_arg));
  GE_ASSERT_SUCCESS(impl_->CreateAndLoadModelFromStruct(model_data.constants_data, weight_buf, kernel_bin_info,
                                                        load_arg, session_id));
  return ge::SUCCESS;
}

ge::Status Om2ModelExecutor::Run(std::vector<gert::Tensor *> &inputs, std::vector<gert::Tensor *> &outputs) const {
  return impl_->Run(inputs, outputs);
}

ge::Status Om2ModelExecutor::RunAsync(void *const stream, std::vector<gert::Tensor *> &inputs,
                                      std::vector<gert::Tensor *> &outputs) const {
  return impl_->RunAsync(stream, inputs, outputs);
}

ge::Status Om2ModelExecutor::GetModelDescInfo(const std::vector<ge::Om2TensorDesc> *&input_desc,
                                              const std::vector<ge::Om2TensorDesc> *&output_desc,
                                              bool new_model_desc) const {
  return impl_->GetModelDescInfo(input_desc, output_desc, new_model_desc);
}

ge::Status Om2ModelExecutor::GetModelAttrs(std::vector<std::string> &dynamic_output_shape) const {
  return impl_->GetModelAttrs(dynamic_output_shape);
}

ge::Status Om2ModelExecutor::GetDynamicBatchInfo(std::vector<std::vector<int64_t>> &dynamic_batch_info,
                                                 int32_t &dynamic_type) const {
  return impl_->GetDynamicBatchInfo(dynamic_batch_info, dynamic_type);
}

ge::Status Om2ModelExecutor::GetUserDesignateShapeOrder(std::vector<std::string> &user_designate_shape_order) const {
  return impl_->GetUserDesignateShapeOrder(user_designate_shape_order);
}

ge::Status Om2ModelExecutor::SetDynamicSize(const std::vector<uint64_t> &batch_num, int32_t dynamic_type) {
  return impl_->SetDynamicSize(batch_num, dynamic_type);
}

ge::Status Om2ModelExecutor::GetCurrentShape(std::vector<int64_t> &batch_info, int32_t &dynamic_type) const {
  return impl_->GetCurrentShape(batch_info, dynamic_type);
}

const std::vector<std::vector<int64_t>> &Om2ModelExecutor::GetOriginInputDims() const {
  return impl_->GetOriginInputDims();
}

ge::Status Om2ModelExecutor::GetOpAttr(std::map<std::string, std::map<std::string, std::string>> &op_attr_map) const {
  return impl_->GetOpAttr(op_attr_map);
}

ge::Status Om2ModelExecutor::GetOpDescInfo(uint32_t device_id, uint32_t stream_id, uint32_t task_id,
                                           ge::OpDescInfo &op_desc_info) const {
  return impl_->GetOpDescInfo(device_id, stream_id, task_id, op_desc_info);
}

ge::Status Om2ModelExecutor::GetAippInfo(uint32_t index, ge::AippConfigInfo &aipp_info) const {
  return impl_->GetAippInfo(index, aipp_info);
}

ge::Status Om2ModelExecutor::GetAippType(uint32_t index, ge::InputAippType &aipp_type, size_t &aipp_data_index) const {
  return impl_->GetAippType(index, aipp_type, aipp_data_index);
}

ge::Status Om2ModelExecutor::GetOrigInputInfo(uint32_t index, ge::OriginInputInfo &orig_input_info) const {
  return impl_->GetOrigInputInfo(index, orig_input_info);
}

ge::Status Om2ModelExecutor::GetAllAippInputOutputDims(uint32_t index, std::vector<ge::InputOutputDims> &input_dims,
                                                       std::vector<ge::InputOutputDims> &output_dims) const {
  return impl_->GetAllAippInputOutputDims(index, input_dims, output_dims);
}

ge::Status Om2ModelExecutor::GetBatchInfoSize(size_t &shape_count) const {
  return impl_->GetBatchInfoSize(shape_count);
}

ge::Status Om2ModelExecutor::SetDynamicAippData(void *dynamic_input_addr, const uint64_t length,
                                                const std::vector<kAippDynamicBatchPara> &aipp_batch_para,
                                                const kAippDynamicPara &aipp_parms) {
  return impl_->SetDynamicAippData(dynamic_input_addr, length, aipp_batch_para, aipp_parms);
}

ge::Status LoadOm2DataFromFile(const std::string &model_path, ge::ModelData &model_data) {
  GELOGI("Begin to load om2 model data from file, path: [%s]", model_path.c_str());
  const std::string file_path = ge::om2::RealPath(model_path.c_str());
  if (file_path.empty()) {
    REPORT_PREDEFINED_ERR_MSG(
        "E13026", std::vector<const char_t *>({"pathname", "reason"}),
        std::vector<const char_t *>({model_path.c_str(), "It is not a real path. Please check your model path."}));
    GELOGE(ACL_ERROR_GE_EXEC_MODEL_PATH_INVALID,
           "[Call][RealPath] File path is invalid. Please check your text file '%s'.", model_path.c_str());
    return ACL_ERROR_GE_EXEC_MODEL_PATH_INVALID;
  }

  std::ifstream fs(file_path, std::ios::binary);
  if (!fs.is_open()) {
    std::array<char_t, kMaxErrorStringLen + 1U> err_buf = {};
    const auto err_msg = mmGetErrorFormatMessage(mmGetErrorCode(), &err_buf[0], kMaxErrorStringLen);
    const std::string reason = ge::FormatErrnoReason(mmGetErrorCode(), err_msg);
    GELOGE(ACL_ERROR_GE_EXEC_MODEL_PATH_INVALID, "[Open][File]Failed, file %s, error %s", model_path.c_str(), err_msg);
    REPORT_INNER_ERR_MSG("E19999", "Open file %s failed, reason:%s", model_path.c_str(), reason.c_str());
    return ACL_ERROR_GE_EXEC_MODEL_PATH_INVALID;
  }

  (void)fs.seekg(0, std::ifstream::end);
  const int64_t len = fs.tellg();
  GE_ASSERT_TRUE(len > 1U);
  (void)fs.seekg(0, std::ifstream::beg);

  auto *buffer = new (std::nothrow) char_t[static_cast<size_t>(len)];
  if (buffer == nullptr) {
    GELOGE(ge::FAILED, "[Alloc][Mem] Failed to alloc memory for om2, size: %lld", len);
    return ge::FAILED;
  }

  (void)fs.read(buffer, len);

  model_data.model_data = buffer;
  model_data.model_len = len;
  model_data.om_path = file_path;
  GELOGI("Load om2 model data success, path: %s, size: %zu", model_path.c_str(), static_cast<size_t>(len));

  return ge::SUCCESS;
}

std::unique_ptr<Om2ModelExecutor> LoadOm2ExecutorFromData(ge::ModelData &model_data, const Om2ModelLoadArg &load_arg,
                                                          ge::Status &error_code) {
  auto executor = std::unique_ptr<Om2ModelExecutor>(new (std::nothrow) Om2ModelExecutor());
  if (executor == nullptr) {
    error_code = ge::FAILED;
    GELOGE(ge::FAILED, "Constructing Om2ModelExecutor failed.");
    return executor;
  }
  const uint64_t session_id = ResolveSessionId(load_arg);
  error_code = executor->Load(model_data, load_arg, session_id);
  GE_ASSERT_SUCCESS(error_code);
  return executor;
}

ge::Status GetOm2MemAndWeightSize(const std::string &model_path, size_t &work_size, size_t &internal_weight_size) {
  ge::ModelData model_data;
  GE_CHK_STATUS_RET(LoadOm2DataFromFile(model_path, model_data), "[OM2][Query] Load model data from file failed.");
  std::shared_ptr<void> data_guarder(model_data.model_data, [](const void *const p) {
    if (p != nullptr) {
      delete[] static_cast<const uint8_t *>(p);
    }
  });
  ge::RAIIZipArchive archive(static_cast<uint8_t *>(model_data.model_data), model_data.model_len);
  GE_ASSERT_TRUE(archive.IsGood());
  GE_ASSERT_SUCCESS(GetOm2MemAndWeightSizeFromArchive(archive, work_size, internal_weight_size));
  return ge::SUCCESS;
}

ge::Status GetOm2MemAndWeightSize(const void *model_data, size_t model_size, size_t &work_size,
                                  size_t &internal_weight_size) {
  ge::RAIIZipArchive archive(static_cast<const uint8_t *>(model_data), model_size);
  GE_ASSERT_TRUE(archive.IsGood());
  GE_ASSERT_SUCCESS(GetOm2MemAndWeightSizeFromArchive(archive, work_size, internal_weight_size));
  return ge::SUCCESS;
}

ge::Status GetOm2ModelMetadata(const std::string &model_path, std::vector<ge::Om2TensorDesc> &input_desc,
                               std::vector<ge::Om2TensorDesc> &input_desc_v2,
                               std::vector<ge::Om2TensorDesc> &output_desc,
                               std::vector<ge::Om2TensorDesc> &output_desc_v2) {
  ge::ModelData model_data;
  GE_CHK_STATUS_RET(LoadOm2DataFromFile(model_path, model_data), "[OM2][Query] Load model data from file failed.");
  std::shared_ptr<void> data_guarder(model_data.model_data, [](const void *const p) {
    if (p != nullptr) {
      delete[] static_cast<const uint8_t *>(p);
    }
  });
  ge::RAIIZipArchive archive(static_cast<uint8_t *>(model_data.model_data), model_data.model_len);
  GE_ASSERT_TRUE(archive.IsGood());
  GE_ASSERT_SUCCESS(GetOm2ModelMetadataFromArchive(archive, input_desc, input_desc_v2, output_desc, output_desc_v2));
  return ge::SUCCESS;
}

ge::Status GetOm2ModelMetadata(const void *model_data, size_t model_size, std::vector<ge::Om2TensorDesc> &input_desc,
                               std::vector<ge::Om2TensorDesc> &input_desc_v2,
                               std::vector<ge::Om2TensorDesc> &output_desc,
                               std::vector<ge::Om2TensorDesc> &output_desc_v2) {
  ge::RAIIZipArchive archive(static_cast<const uint8_t *>(model_data), model_size);
  GE_ASSERT_TRUE(archive.IsGood());
  GE_ASSERT_SUCCESS(GetOm2ModelMetadataFromArchive(archive, input_desc, input_desc_v2, output_desc, output_desc_v2));
  return ge::SUCCESS;
}

ge::Status IsOm2Model(const void *data, size_t size, bool &is_support) {
  if (data == nullptr) {
    REPORT_PREDEFINED_ERR_MSG("E10001", std::vector<const char *>({"parameter", "value", "reason"}),
                              std::vector<const char *>({"data", "nullptr", "Model data cannot be nullptr."}));
    GELOGE(ACL_ERROR_GE_PARAM_INVALID, "[Check][Param] Invalid om2 model. Model data cannot be nullptr.");
    return ACL_ERROR_GE_PARAM_INVALID;
  }

  if (size < FILE_MAGIC_HEADER_SIZE) {
    const std::string err_msg =
        "Model data size must be greater than or equal to " + std::to_string(FILE_MAGIC_HEADER_SIZE);
    REPORT_PREDEFINED_ERR_MSG("E10001", std::vector<const char *>({"parameter", "value", "reason"}),
                              std::vector<const char *>({"size", std::to_string(size).c_str(), err_msg.c_str()}));
    GELOGE(ACL_ERROR_GE_EXEC_MODEL_DATA_SIZE_INVALID,
           "[Check][Param] Invalid om2 model. Model data size %zu must be greater than or equal to %zu.", size,
           FILE_MAGIC_HEADER_SIZE);
    return ACL_ERROR_GE_EXEC_MODEL_DATA_SIZE_INVALID;
  }

  is_support = std::memcmp(data, OM2_MAGIC, FILE_MAGIC_HEADER_SIZE) == 0;
  return ge::SUCCESS;
}

ge::Status IsOm2Model(const char *file_path, bool &is_support) {
  const std::string real_path = ge::om2::RealPath(file_path);
  if (real_path.empty()) {
    std::array<char_t, kMaxErrorStringLen + 1U> err_buf = {};
    const auto err_msg = mmGetErrorFormatMessage(mmGetErrorCode(), err_buf.data(), kMaxErrorStringLen);
    std::string reason = ge::FormatErrnoReason(mmGetErrorCode(), err_msg);
    REPORT_PREDEFINED_ERR_MSG("E13000", std::vector<const char *>({"path", "errmsg"}),
                              std::vector<const char *>({file_path, reason.c_str()}));
    GELOGE(ACL_ERROR_GE_EXEC_MODEL_PATH_INVALID, "[Check][Param]Model file path %s is invalid", file_path);
    return ACL_ERROR_GE_EXEC_MODEL_PATH_INVALID;
  }

  std::ifstream file(file_path, std::ios::binary);
  if (!file.is_open()) {
    std::array<char_t, kMaxErrorStringLen + 1U> err_buf = {};
    const auto err_msg = mmGetErrorFormatMessage(mmGetErrorCode(), &err_buf[0], kMaxErrorStringLen);
    const std::string reason = ge::FormatErrnoReason(mmGetErrorCode(), err_msg);
    GELOGE(ACL_ERROR_GE_EXEC_MODEL_PATH_INVALID, "[Open][File]Failed, file %s, error %s", file_path, err_msg);
    REPORT_INNER_ERR_MSG("E19999", "Open file %s failed, reason:%s", file_path, reason.c_str());
    return ACL_ERROR_GE_EXEC_MODEL_PATH_INVALID;
  }

  (void)file.seekg(0, std::ifstream::end);
  const size_t len = static_cast<size_t>(file.tellg());
  (void)file.seekg(0, std::ifstream::beg);
  if (len < FILE_MAGIC_HEADER_SIZE) {
    const std::string reason = "Invalid om2 file. The model data size " + std::to_string(len) + " is smaller than " +
                               std::to_string(FILE_MAGIC_HEADER_SIZE) + ".";
    (void)REPORT_PREDEFINED_ERR_MSG("E10001", std::vector<const char *>({"parameter", "value", "reason"}),
                                    std::vector<const char *>({"file_path", file_path, reason.c_str()}));
    GELOGE(ACL_ERROR_GE_EXEC_MODEL_DATA_SIZE_INVALID,
           "[Check][Param] Invalid om2 model. Model data size %" PRIu64 " must be greater than or equal to %zu.", len,
           FILE_MAGIC_HEADER_SIZE);
    return ACL_ERROR_GE_EXEC_MODEL_DATA_SIZE_INVALID;
  }

  uint8_t magic[FILE_MAGIC_HEADER_SIZE] = {};
  file.read(reinterpret_cast<char *>(magic), FILE_MAGIC_HEADER_SIZE);
  const auto read_len = static_cast<size_t>(file.gcount());

  GE_ASSERT_SUCCESS(IsOm2Model(magic, read_len, is_support));
  return ge::SUCCESS;
}
}  // namespace gert