Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/dom/onnx/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 23 kB image not shown  

Quelle  InferenceSession.cpp

  Sprache: C
 

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "mozilla/dom/InferenceSession.h"

#include <prlink.h>

#include <thread>

#include "ErrorList.h"
#include "GeckoProfiler.h"
#include "fmt/format.h"
#include "mozilla/Attributes.h"
#include "mozilla/FileUtils.h"
#include "mozilla/Logging.h"
#include "mozilla/RefPtr.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ONNXBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/Tensor.h"
#include "nsString.h"
#include "nsXPCOMPrivate.h"
mozilla::LazyLogModule gONNXLog("GeckoMLONNXNative");
#define LOGV(fmt, ...) \
  MOZ_LOG_FMT(gONNXLog, LogLevel::Verbose, fmt, ##__VA_ARGS__)
#define LOGD(fmt, ...) \
  MOZ_LOG_FMT(gONNXLog, LogLevel::Debug, fmt, ##__VA_ARGS__)
#define LOGE(fmt, ...) \
  MOZ_LOG_FMT(gONNXLog, LogLevel::Error, fmt, ##__VA_ARGS__)

namespace mozilla::dom {

// Initialized when the first InferenceSession is initialized,
// valid until the shutdown of the inference process.
static OrtEnv* sEnv = nullptr;
static OrtApi* sAPI = nullptr;

// RAII wrapper over OrtStatus.
// Takes ownership of a externally allocated OrtStatus* passed at construction.
// Move-only. OrtStatus released through OrtApi::ReleaseStatus.
class AutoOrtStatus {
 public:
  MOZ_IMPLICIT AutoOrtStatus(OrtStatus* aStatus = nullptr) : mStatus(aStatus) {
    MOZ_ASSERT(sAPI);
  }
  // Prevent copies
  AutoOrtStatus(const AutoOrtStatus&) = delete;
  AutoOrtStatus& operator=(const AutoOrtStatus&) = delete;
  // Move semantics
  AutoOrtStatus(AutoOrtStatus&& aOther) noexcept
      : mStatus(std::exchange(aOther.mStatus, nullptr)) {}
  AutoOrtStatus& operator=(AutoOrtStatus&& aOther) noexcept {
    if (this != &aOther) {
      Release();
      mStatus = std::exchange(aOther.mStatus, nullptr);
    }
    return *this;
  }
  ~AutoOrtStatus() { Release(); }
  explicit operator bool() const { return !!mStatus; }
  const char* Message() const { return sAPI->GetErrorMessage(mStatus); }
  void Release() {
    if (mStatus) {
      sAPI->ReleaseStatus(mStatus);
      mStatus = nullptr;
    }
  }

  OrtStatus* mStatus;
};

NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(InferenceSession);

NS_IMPL_CYCLE_COLLECTING_ADDREF(InferenceSession)
NS_IMPL_CYCLE_COLLECTING_RELEASE(InferenceSession)

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(InferenceSession)
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END

#define DYLIB_PATH "onnxruntime"

OrtSessionOptions* ToOrtSessionOption(
    const InferenceSessionSessionOptions& aOptions) {
  OrtSessionOptions* sessionOptions = nullptr;
  AutoOrtStatus status = sAPI->CreateSessionOptions(&sessionOptions);
  if (status) {
    LOGD("CreateSessionOptions error: {}", status.Message());
    return nullptr;
  }
#define SET_BOOL_ON_SESSION(x)                                       \
  do {                                                               \
    if (aOptions.mEnable##x) {                                       \
      status = sAPI->Enable##x(sessionOptions);                      \
    } else {                                                         \
      status = sAPI->Disable##x(sessionOptions);                     \
    }                                                                \
    if (status) {                                                    \
      LOGE("Setter {} (val: {}) error: {}"#x, aOptions.mEnable##x, \
           status.Message());                                        \
      return nullptr;                                                \
    }                                                                \
  } while (0)

  LOGD("CpuMemArena: {}", aOptions.mEnableCpuMemArena);
  SET_BOOL_ON_SESSION(CpuMemArena);
  LOGD("MemPattern: {}", aOptions.mEnableMemPattern);
  SET_BOOL_ON_SESSION(MemPattern);

#define CALL_API(x, ...)                                           \
  do {                                                             \
    status = sAPI->x(sessionOptions, __VA_ARGS__);                 \
    if (status) {                                                  \
      LOGD("SetSessionExecutionMode error: {}", status.Message()); \
      return nullptr;                                              \
    }                                                              \
  } while (0);

  LOGD("Session execution mode: {}", aOptions.mExecutionMode);
  CALL_API(SetSessionExecutionMode,
           aOptions.mExecutionMode.EqualsASCII("parallel")
               ? ExecutionMode::ORT_PARALLEL
               : ExecutionMode::ORT_SEQUENTIAL);

  LOGD("Inter op num threads: {}", aOptions.mInterOpNumThreads);
  CALL_API(SetInterOpNumThreads, aOptions.mInterOpNumThreads);
  LOGD("Intra op num threads: {}", aOptions.mIntraOpNumThreads);
  CALL_API(SetIntraOpNumThreads, aOptions.mIntraOpNumThreads);
  CALL_API(SetSessionLogId, aOptions.mLogId.get());
  CALL_API(SetSessionLogSeverityLevel, aOptions.mLogSeverityLevel);
  CALL_API(SetSessionLogVerbosityLevel, aOptions.mLogVerbosityLevel);
  PathString path;
#ifdef XP_WIN
  path = NS_ConvertUTF8toUTF16(aOptions.mOptimizedModelFilePath.get());

#else
  path = aOptions.mOptimizedModelFilePath.get();
#endif
  CALL_API(SetOptimizedModelFilePath, path.get());
  GraphOptimizationLevel level = ORT_ENABLE_BASIC;
  LOGD("Graph optimization level: {}", aOptions.mGraphOptimizationLevel);
  if (aOptions.mGraphOptimizationLevel.EqualsASCII("all")) {
    level = ORT_ENABLE_ALL;
  } else if (aOptions.mGraphOptimizationLevel.EqualsASCII("basic")) {
    level = ORT_ENABLE_BASIC;
  } else if (aOptions.mGraphOptimizationLevel.EqualsASCII("extended")) {
    level = ORT_ENABLE_EXTENDED;
  } else if (aOptions.mGraphOptimizationLevel.EqualsASCII("all")) {
    level = ORT_ENABLE_ALL;
  }
  CALL_API(SetSessionGraphOptimizationLevel, level);

  if (aOptions.mFreeDimensionOverrides.WasPassed()) {
    for (const auto& rec : aOptions.mFreeDimensionOverrides.Value().Entries()) {
      LOGD("Adding free dimension override for key: {}, value: {}", rec.mKey,
           rec.mValue);
      CALL_API(AddFreeDimensionOverride, rec.mKey.get(), rec.mValue);
    }
  }

  return sessionOptions;
}  // namespace mozilla::dom

OrtApi* GetOrtAPI() {
#ifdef XP_WIN
  PathString path = GetLibraryFilePathname(LXUL_DLL, (PRFuncPtr)&GetOrtAPI);
#else
  PathString path = GetLibraryFilePathname(XUL_DLL, (PRFuncPtr)&GetOrtAPI);
#endif
  if (path.IsEmpty()) {
    LOGE("Could not locate XUL library when loading onnxruntime");
    return nullptr;
  }
  nsCOMPtr<nsIFile> libFile;
  if (NS_FAILED(NS_NewPathStringLocalFile(path, getter_AddRefs(libFile)))) {
    LOGE("Could not get path string for local file when loading onnxruntime");
    return nullptr;
  }

  if (NS_FAILED(libFile->SetNativeLeafName(
          MOZ_DLL_PREFIX "onnxruntime" MOZ_DLL_SUFFIX ""_ns))) {
    LOGE("SetNativeLeavName error when loading onnxruntime");
    return nullptr;
  }
  PRLibSpec lspec;
  PathString nativePath = libFile->NativePath();
#ifdef XP_WIN
  lspec.type = PR_LibSpec_PathnameU;
  lspec.value.pathname_u = nativePath.get();
#else
  lspec.type = PR_LibSpec_Pathname;
  lspec.value.pathname = nativePath.get();
#endif
#ifdef MOZ_WIDGET_ANDROID
  PRLibrary* handle = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_GLOBAL);
#else
  PRLibrary* handle = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL);
#endif
  if (!handle) {
    PRErrorCode code = PR_GetError();
    const char* msg = PR_ErrorToString(code, PR_LANGUAGE_I_DEFAULT);
    LOGE("Couldn't load onnxruntime shared library ({:x}: {})", PR_GetOSError(),
         msg);
    return nullptr;
  }

  using OrtApiBaseFn = const OrtApiBase* (*)();
  auto ortGetApiBaseFnPtr =
      reinterpret_cast<OrtApiBaseFn>(PR_FindSymbol(handle, "OrtGetApiBase"));
  if (!ortGetApiBaseFnPtr) {
    LOGE("Couldn't fetch symbol OrgGetApiBase");
    PR_UnloadLibrary(handle);
    return nullptr;
  }
  const OrtApiBase* apiBase = ortGetApiBaseFnPtr();
  OrtApi* ortAPI = const_cast<OrtApi*>(apiBase->GetApi(ORT_API_VERSION));
  if (!ortAPI) {
    LOGE("Couldn't get ahold of the OrtApi pointer");
    PR_UnloadLibrary(handle);
    return nullptr;
  }

  return ortAPI;
}

bool InferenceSession::InInferenceProcess(JSContext*, JSObject*) {
  if (!ContentChild::GetSingleton()) {
    return false;
  }
  return ContentChild::GetSingleton()->GetRemoteType().Equals(
      INFERENCE_REMOTE_TYPE);
}

nsCString InferenceSessionSessionOptionsToString(
    const InferenceSessionSessionOptions& aOptions) {
  return nsFmtCString(
      "EnableCpuMemArena: {}, "
      "EnableGraphCapture: {}, "
      "EnableMemPattern: {}, "
      "EnableProfiling: {}, "
      "ExecutionMode: {}, "
      "ExecutionProviders: {}, "
      "Extra: {}, "
      "FreeDimensionOverrides: {}, "
      "GraphOptimizationLevel: {}, "
      "InterOpNumThreads: {}, "
      "IntraOpNumThreads: {}, "
      "LogId: {}, "
      "LogSeverityLevel: {}, "
      "LogVerbosityLevel: {}, "
      "OptimizedModelFilePath: {}, "
      "PreferredOutputLocation: {}, "
      "ProfileFilePrefix: {}",
      aOptions.mEnableCpuMemArena, aOptions.mEnableGraphCapture,
      aOptions.mEnableMemPattern, aOptions.mEnableProfiling,
      aOptions.mExecutionMode,
      aOptions.mExecutionProviders.WasPassed() ? "<passed>" : "<not passed>",
      aOptions.mExtra.WasPassed() ? "<passed>" : "<not passed>",
      aOptions.mFreeDimensionOverrides.WasPassed() ? "<passed>"
                                                   : "<not passed>",
      aOptions.mGraphOptimizationLevel, aOptions.mInterOpNumThreads,
      aOptions.mIntraOpNumThreads, aOptions.mLogId, aOptions.mLogSeverityLevel,
      aOptions.mLogVerbosityLevel, aOptions.mOptimizedModelFilePath,
      aOptions.mPreferredOutputLocation.WasPassed() ? "<passed>"
                                                    : "<not passed>",
      aOptions.mProfileFilePrefix);
}

OrtCustomThreadHandle WrapProfilerRegister(void* options, void (*func)(void*),
                                           void* param) {
  // We don't use options for now
  MOZ_ASSERT(!options);
  auto wrapperFunc = [func](void* param) {
    PROFILER_REGISTER_THREAD("onnx_worker");
    LOGD("Starting thread");
    (static_cast<OrtThreadWorkerFn>(func))(param);
  };

  auto* t = new std::thread(wrapperFunc, param);

  return reinterpret_cast<OrtCustomThreadHandle>(t);
}

void WrapProfilerUnregister(OrtCustomThreadHandle thread) {
  LOGD("Joining thread");
  std::thread* t = (std::thread*)thread;
  t->join();
  delete t;
}

RefPtr<Promise> InferenceSession::Create(
    GlobalObject& aGlobal, const UTF8StringOrUint8Array& aUriOrBuffer,
    const InferenceSessionSessionOptions& aOptions, ErrorResult& aRv) {
  LOGD("{}", __PRETTY_FUNCTION__);
  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
  RefPtr<Promise> p = Promise::Create(global, aRv);
  RefPtr<InferenceSession> session = new InferenceSession(aGlobal);
  session->Init(p, aUriOrBuffer, aOptions);
  return p;
}

void InferenceSession::Init(const RefPtr<Promise>& aPromise,
                            const UTF8StringOrUint8Array& aUriOrBuffer,
                            const InferenceSessionSessionOptions& aOptions) {
  LOGD("InferenceSession::Init called with a {}",
       aUriOrBuffer.IsUTF8String() ? "string" : "buffer");

  if (!sEnv) {
    sAPI = GetOrtAPI();
    if (!sAPI) {
      LOGD("Couldn't get ahold of ORT API");
      // Use a distinguishable error so JS callers can recognize that the
      // native runtime is unavailable on this machine and fall back to the
      // wasm onnx backend (see MLEngineChild's best-onnx handling).
      // KEEP IN SYNC: MLEngineChild.sys.mjs matches this message string to
      // cache the wasm fallback decision.
      aPromise->MaybeRejectWithNotSupportedError(
          "onnxruntime shared library could not be loaded");
      return;
    }
    OrtThreadingOptions* threadingOptions;

    AutoOrtStatus status = sAPI->CreateThreadingOptions(&threadingOptions);
    if (status) {
      LOGD("CreateThreadingOptions error");
      aPromise->MaybeRejectWithUndefined();
      return;
    }
    status = sAPI->SetGlobalCustomCreateThreadFn(threadingOptions,
                                                 WrapProfilerRegister);
    if (status) {
      LOGD("SetGlobalCustomCreateThreadFn error");
      aPromise->MaybeRejectWithUndefined();
      return;
    }

    status = sAPI->SetGlobalCustomJoinThreadFn(threadingOptions,
                                               WrapProfilerUnregister);
    if (status) {
      LOGD("SetGlobalCustomJoinThreadFn error");
      aPromise->MaybeRejectWithUndefined();
      return;
    }

    status = sAPI->SetGlobalInterOpNumThreads(
        threadingOptions, AssertedCast<int>(aOptions.mInterOpNumThreads));
    if (status) {
      LOGD("SetGlobalInterOpNumThreads error");
      aPromise->MaybeRejectWithUndefined();
      return;
    }

    status = sAPI->SetGlobalIntraOpNumThreads(
        threadingOptions, AssertedCast<int>(aOptions.mIntraOpNumThreads));
    if (status) {
      LOGD("SetGlobalIntraOpNumThreads error");
      aPromise->MaybeRejectWithUndefined();
      return;
    }

    status = sAPI->SetGlobalDenormalAsZero(threadingOptions);
    if (status) {
      LOGD("SetGlobalDenormalsAreZero error");
      aPromise->MaybeRejectWithUndefined();
      return;
    }

    status = sAPI->SetGlobalSpinControl(threadingOptions, 0);
    if (status) {
      LOGD("SetGlobalSpinControl error");
      aPromise->MaybeRejectWithUndefined();
      return;
    }

    status = sAPI->CreateEnvWithGlobalThreadPools(
        ORT_LOGGING_LEVEL_FATAL, "my_env", threadingOptions, &sEnv);
    if (status) {
      LOGD("CreateEnv error: {}", status.Message());
      MOZ_CRASH("Init CreateEnv");
    }
    LOGD("CreateEnv OK");
  }

  mOptions = ToOrtSessionOption(aOptions);
  AutoOrtStatus status = sAPI->DisablePerSessionThreads(mOptions);
  if (status) {
    LOGD("DisablePerSessionThreads error: {}", status.Message());
  }

  OrtSession* session = nullptr;
  if (aUriOrBuffer.IsUTF8String()) {
    LOGE("Passing a URI to a model isn't implemented, pass the bytes directly");
    aPromise->MaybeRejectWithNotSupportedError("Not implemented");
    return;
  }
  aUriOrBuffer.GetAsUint8Array().ProcessFixedData(
      [&](const Span<uint8_t>& aData) {
        AUTO_PROFILER_MARKER_UNTYPED("CreateSessionFromArray", ML_SETUP, {});
        status = sAPI->CreateSessionFromArray(
            sEnv, aData.data(), aData.Length(), mOptions, &session);
      });
  if (status) {
    LOGD("CreateSession error: {}", status.Message());
    MOZ_CRASH("CreateSession error");
  }
  LOGD("Successfully created ONNX Runtime session.");
  mSession = session;
  aPromise->MaybeResolve(this);
}

nsCString FeedsToString(
    const Record<nsCString, OwningNonNull<Tensor>>& aFeeds) {
  nsCString rv;
  for (const auto& input : aFeeds.Entries()) {
    rv.AppendFmt("[{}: {}],", input.mKey, input.mValue->ToString().get());
  }
  return rv;
}

already_AddRefed<Promise> InferenceSession::Run(
    const Record<nsCString, OwningNonNull<Tensor>>& feeds,
    const InferenceSessionRunOptions& options, ErrorResult& aRv) {
  LOGD("{} {}", __PRETTY_FUNCTION__, fmt::ptr(this));
  RefPtr<Promise> p = Promise::Create(GetParentObject(), aRv);

  if (!mSession) {
    LOGD("runInference: session pointer is null.");
  }
  if (!sAPI || !sEnv) {
    LOGD("Need API {} and Env {} here", fmt::ptr(sAPI), fmt::ptr(sEnv));
    MOZ_CRASH("In run");
    p->MaybeReject(NS_ERROR_UNEXPECTED);
    return p.forget();
  }

  OrtMemoryInfo* memoryInfo = nullptr;
  auto guard = MakeScopeExit([&] { sAPI->ReleaseMemoryInfo(memoryInfo); });
  AutoOrtStatus status = sAPI->CreateCpuMemoryInfo(
      OrtArenaAllocator, OrtMemTypeDefault, &memoryInfo);
  if (status) {
    LOGD("CreateCpuMemoryInfo failed: {}", status.Message());
    p->MaybeReject(NS_ERROR_UNEXPECTED);
    return p.forget();
  }

  LOGD("Inputs:");
  nsTArray<OrtValue*> inputValues;
  auto scope = MakeScopeExit([&] {
    for (auto& v : inputValues) {
      sAPI->ReleaseValue(v);
    }
  });
  for (const auto& input : feeds.Entries()) {
    OrtValue* inputOrt = nullptr;
    const auto& val = input.mValue;
    AutoTArray<int64_t, 16> dims64;
    for (uint32_t i = 0; i < val->DimsSize(); i++) {
      dims64.AppendElement(val->Dims()[i]);
    }
    LOGD("{}: {}", input.mKey.get(), val->ToString().get());
    AUTO_PROFILER_MARKER_FMT("CreateTensorWithDataAsOrtValue", ML_INFERENCE, {},
                             "{}", input.mKey.get());
    status = sAPI->CreateTensorWithDataAsOrtValue(
        memoryInfo, val->Data(), val->Size(), dims64.Elements(),
        val->DimsSize(), val->Type(), &inputOrt);
    if (status) {
      LOGD("CreateTensorWithDataAsOrtValue for input_ids {} failed: {}",
           input.mKey, status.Message());
      p->MaybeReject(NS_ERROR_UNEXPECTED);
      return p.forget();
    }

    inputValues.AppendElement(inputOrt);
  }

  nsTArray<nsCString> inputNames;
  nsTArray<const char*> inputNamesPtrs;
  GetNames(inputNames, NameDirection::Input);
  for (const auto& name : inputNames) {
    inputNamesPtrs.AppendElement(name.get());
  }
  nsTArray<nsCString> outputNames;
  nsTArray<const char*> outputNamesPtrs;
  GetNames(outputNames, NameDirection::Output);
  LOGD("Outputs names:");
  for (const auto& name : outputNames) {
    LOGD("- {}", name.get());
    outputNamesPtrs.AppendElement(name.get());
  }
  nsTArray<OrtValue*> outputs;
  outputs.SetLength(outputNames.Length());
  for (uint32_t i = 0; i < outputNames.Length(); i++) {
    outputs[i] = nullptr;
  }
  OrtValue** ptr = outputs.Elements();

  {
    AUTO_PROFILER_MARKER_UNTYPED("Ort::Run", ML_INFERENCE, {});
    status = sAPI->Run(mSession,
                       nullptr,  // Run options
                       inputNamesPtrs.Elements(), inputValues.Elements(),
                       inputNamesPtrs.Length(), outputNamesPtrs.Elements(),
                       outputNamesPtrs.Length(), ptr);
  }
  if (status) {
    LOGD("Session Run failed: {}", status.Message());
    p->MaybeReject(NS_ERROR_UNEXPECTED);
    return p.forget();
  }

  Record<nsCString, OwningNonNull<Tensor>> rv;
  for (size_t i = 0; i < outputs.Length(); i++) {
    TimeStamp start = TimeStamp::Now();
    // outputData has the same lifetime as output[i]. For now, the actual data
    // is copied into the Tensor object below. This copy will be removed in the
    // future.
    uint8_t* outputData = nullptr;
    status = sAPI->GetTensorMutableData(outputs[i], (void**)&outputData);
    if (status) {
      LOGD("GetTensorMutableData failed: {}", status.Message());
      p->MaybeReject(NS_ERROR_UNEXPECTED);
      return p.forget();
    }

    OrtTypeInfo* typeInfo;
    status = sAPI->SessionGetOutputTypeInfo(mSession, i, &typeInfo);
    if (status) {
      LOGD("GetOutputTypeInfo failed: {}", status.Message());
      p->MaybeReject(NS_ERROR_UNEXPECTED);
      return p.forget();
    }

    OrtTensorTypeAndShapeInfo* typeAndShapeInfo;
    status = sAPI->GetTensorTypeAndShape(outputs[i], &typeAndShapeInfo);
    if (status) {
      LOGD("GetTensorTypeAndShape failed: {}", status.Message());
      p->MaybeReject(NS_ERROR_UNEXPECTED);
      return p.forget();
    }

    ONNXType type;
    status = sAPI->GetOnnxTypeFromTypeInfo(typeInfo, &type);
    if (status) {
      LOGD("GetOnnxTypeFromTypeInfo failed: {}", status.Message());
      p->MaybeReject(NS_ERROR_UNEXPECTED);
      return p.forget();
    }
    MOZ_ASSERT(type == ONNX_TYPE_TENSOR);

    ONNXTensorElementDataType outputTensorType;
    status = sAPI->GetTensorElementType(typeAndShapeInfo, &outputTensorType);
    if (status) {
      LOGD("GetTensorElementType failed: {}", status.Message());
      p->MaybeReject(NS_ERROR_UNEXPECTED);
      return p.forget();
    }

    size_t dimCount;
    status = sAPI->GetDimensionsCount(typeAndShapeInfo, &dimCount);
    if (status) {
      LOGD("GetDimensionsCount failed: {}", status.Message());
      p->MaybeReject(NS_ERROR_UNEXPECTED);
      return p.forget();
    }

    AutoTArray<int64_t, 16> dims;
    dims.SetLength(dimCount);
    status = sAPI->GetDimensions(typeAndShapeInfo, dims.Elements(), dimCount);

    size_t outputSize = 1;
    for (size_t d = 0; d < dimCount; ++d) {
      outputSize *= dims[d];
    }

    // TODO skip this copy by using CreateTensorWithDataAsOrtValue
    nsTArray<uint8_t> output;
    output.AppendElements(outputData,
                          outputSize * Tensor::DataTypeSize(outputTensorType));
    GlobalObject global(mCtx, GetParentObject()->GetGlobalJSObject());
    auto outputTensor = MakeRefPtr<Tensor>(global, outputTensorType,
                                           std::move(output), std::move(dims));
    AUTO_PROFILER_MARKER_FMT(
        "Output tensor", ML_INFERENCE,
        MarkerOptions(MarkerTiming::IntervalUntilNowFrom(start)), "{}: {}",
        outputNames[i], outputTensor->ToString().get());

    sAPI->ReleaseTensorTypeAndShapeInfo(typeAndShapeInfo);

    auto elem = rv.Entries().AppendElement();
    elem->mKey = outputNames[i];
    elem->mValue = outputTensor;
  }

  p->MaybeResolve(rv);

  return p.forget();
}

void InferenceSession::Destroy() {
  LOGD("{} {}", __PRETTY_FUNCTION__, fmt::ptr(this));
  if (mSession) {
    sAPI->ReleaseSession(mSession);
    mSession = nullptr;
  }
  if (mOptions) {
    sAPI->ReleaseSessionOptions(mOptions);
    mOptions = nullptr;
  }
}

already_AddRefed<Promise> InferenceSession::ReleaseSession() {
  LOGD("{} {}", __PRETTY_FUNCTION__, fmt::ptr(this));

  Destroy();
  RefPtr<Promise> p = Promise::CreateInfallible(mGlobal);
  p->MaybeResolveWithUndefined();
  return p.forget();
}

void InferenceSession::StartProfiling() {
  LOGD("{} {}", __PRETTY_FUNCTION__, fmt::ptr(this));
}

void InferenceSession::EndProfiling() {
  LOGD("{} {}", __PRETTY_FUNCTION__, fmt::ptr(this));
}

void InferenceSession::GetNames(nsTArray<nsCString>& aRetVal,
                                NameDirection aDirection) const {
  const char* NameDirection2String[2] = {"Input""Output"};

  if (!mSession) {
    return;
  }
  size_t nameCount = 0;
  AutoOrtStatus status;
  if (aDirection == NameDirection::Input) {
    status = sAPI->SessionGetInputCount(mSession, &nameCount);
  } else {
    status = sAPI->SessionGetOutputCount(mSession, &nameCount);
  }
  if (status) {
    LOGD("SessionGet{}Count failed: ",
         NameDirection2String[static_cast<int>(aDirection)], status.Message());
    return;
  }

  OrtAllocator* allocator = nullptr;
  status = sAPI->GetAllocatorWithDefaultOptions(&allocator);
  if (status) {
    LOGD("GetAllocatorWithDefaultOptions failed: {}", status.Message());
    return;
  }
  aRetVal.SetCapacity(nameCount);
  for (size_t i = 0; i < nameCount; i++) {
    // Allocated by onnxruntiem, must be freed by AllocatorFree
    char* name = nullptr;

    if (aDirection == NameDirection::Input) {
      status = sAPI->SessionGetInputName(mSession, i, allocator, &name);
    } else {
      status = sAPI->SessionGetOutputName(mSession, i, allocator, &name);
    }
    if (status) {
      LOGD("SessionGet{}Name failed: ",
           NameDirection2String[static_cast<int>(aDirection)],
           status.Message());
      continue;
    }
    aRetVal.AppendElement(name);
    status = sAPI->AllocatorFree(allocator, name);
    if (status) {
      LOGD("AllocatorFree failed: ", status.Message());
      continue;
    }
  }
}

void InferenceSession::GetInputNames(nsTArray<nsCString>& aRetVal) const {
  LOGD("{} {}", __PRETTY_FUNCTION__, fmt::ptr(this));
  GetNames(aRetVal, NameDirection::Input);
  if (MOZ_LOG_TEST(gONNXLog, LogLevel::Debug)) {
    for (auto& name : aRetVal) {
      LOGD("- {}", name);
    }
  }
}

void InferenceSession::GetOutputNames(nsTArray<nsCString>& aRetVal) const {
  LOGD("{} {}", __PRETTY_FUNCTION__, fmt::ptr(this));
  GetNames(aRetVal, NameDirection::Output);
  if (MOZ_LOG_TEST(gONNXLog, LogLevel::Debug)) {
    for (auto& name : aRetVal) {
      LOGD("- {}", name);
    }
  }
}

JSObject* InferenceSession::WrapObject(JSContext* aCx,
                                       JS::Handle<JSObject*> aGivenProto) {
  return InferenceSession_Binding::Wrap(aCx, this, aGivenProto);
}

}  // namespace mozilla::dom

Messung V0.5 in Prozent
C=87 H=93 G=89

¤ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet am  2026-08-25) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.