Skip to content

Commit

Permalink
[js/node] support manually dispose session (#18655)
Browse files Browse the repository at this point in the history
### Description
support manually dispose session in onnxruntime-node

feature request: #16796
  • Loading branch information
fs-eire authored Dec 20, 2023
1 parent 98510fb commit ffa6602
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 2 deletions.
2 changes: 1 addition & 1 deletion js/node/lib/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class OnnxruntimeSessionHandler implements InferenceSessionHandler {
}

async dispose(): Promise<void> {
return Promise.resolve();
this.#inferenceSession.dispose();
}

readonly inputNames: string[];
Expand Down
2 changes: 2 additions & 0 deletions js/node/lib/binding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ export declare namespace Binding {
readonly outputNames: string[];

run(feeds: FeedsType, fetches: FetchesType, options: RunOptions): ReturnType;

dispose(): void;
}

export interface InferenceSessionConstructor {
Expand Down
19 changes: 18 additions & 1 deletion js/node/src/inference_session_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Napi::Object InferenceSessionWrap::Init(Napi::Env env, Napi::Object exports) {
Napi::Function func = DefineClass(
env, "InferenceSession",
{InstanceMethod("loadModel", &InferenceSessionWrap::LoadModel), InstanceMethod("run", &InferenceSessionWrap::Run),
InstanceMethod("dispose", &InferenceSessionWrap::Dispose),
InstanceAccessor("inputNames", &InferenceSessionWrap::GetInputNames, nullptr, napi_default, nullptr),
InstanceAccessor("outputNames", &InferenceSessionWrap::GetOutputNames, nullptr, napi_default, nullptr)});

Expand All @@ -45,14 +46,15 @@ Napi::Object InferenceSessionWrap::Init(Napi::Env env, Napi::Object exports) {
}

InferenceSessionWrap::InferenceSessionWrap(const Napi::CallbackInfo &info)
: Napi::ObjectWrap<InferenceSessionWrap>(info), initialized_(false), session_(nullptr),
: Napi::ObjectWrap<InferenceSessionWrap>(info), initialized_(false), disposed_(false), session_(nullptr),
defaultRunOptions_(nullptr) {}

Napi::Value InferenceSessionWrap::LoadModel(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
Napi::HandleScope scope(env);

ORT_NAPI_THROW_ERROR_IF(this->initialized_, env, "Model already loaded. Cannot load model multiple times.");
ORT_NAPI_THROW_ERROR_IF(this->disposed_, env, "Session already disposed.");

size_t argsLength = info.Length();
ORT_NAPI_THROW_TYPEERROR_IF(argsLength == 0, env, "Expect argument: model file path or buffer.");
Expand Down Expand Up @@ -129,6 +131,7 @@ Napi::Value InferenceSessionWrap::LoadModel(const Napi::CallbackInfo &info) {
Napi::Value InferenceSessionWrap::GetInputNames(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
ORT_NAPI_THROW_ERROR_IF(!this->initialized_, env, "Session is not initialized.");
ORT_NAPI_THROW_ERROR_IF(this->disposed_, env, "Session already disposed.");

Napi::EscapableHandleScope scope(env);
return scope.Escape(CreateNapiArrayFrom(env, inputNames_));
Expand All @@ -137,6 +140,7 @@ Napi::Value InferenceSessionWrap::GetInputNames(const Napi::CallbackInfo &info)
Napi::Value InferenceSessionWrap::GetOutputNames(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
ORT_NAPI_THROW_ERROR_IF(!this->initialized_, env, "Session is not initialized.");
ORT_NAPI_THROW_ERROR_IF(this->disposed_, env, "Session already disposed.");

Napi::EscapableHandleScope scope(env);
return scope.Escape(CreateNapiArrayFrom(env, outputNames_));
Expand All @@ -145,6 +149,7 @@ Napi::Value InferenceSessionWrap::GetOutputNames(const Napi::CallbackInfo &info)
Napi::Value InferenceSessionWrap::Run(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
ORT_NAPI_THROW_ERROR_IF(!this->initialized_, env, "Session is not initialized.");
ORT_NAPI_THROW_ERROR_IF(this->disposed_, env, "Session already disposed.");
ORT_NAPI_THROW_TYPEERROR_IF(info.Length() < 2, env, "Expect argument: inputs(feed) and outputs(fetch).");
ORT_NAPI_THROW_TYPEERROR_IF(!info[0].IsObject() || !info[1].IsObject(), env,
"Expect inputs(feed) and outputs(fetch) to be objects.");
Expand Down Expand Up @@ -209,6 +214,18 @@ Napi::Value InferenceSessionWrap::Run(const Napi::CallbackInfo &info) {
}
}

Napi::Value InferenceSessionWrap::Dispose(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
ORT_NAPI_THROW_ERROR_IF(!this->initialized_, env, "Session is not initialized.");
ORT_NAPI_THROW_ERROR_IF(this->disposed_, env, "Session already disposed.");

this->defaultRunOptions_.reset(nullptr);
this->session_.reset(nullptr);

this->disposed_ = true;
return env.Undefined();
}

Napi::Value InferenceSessionWrap::ListSupportedBackends(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
Napi::EscapableHandleScope scope(env);
Expand Down
9 changes: 9 additions & 0 deletions js/node/src/inference_session_wrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,22 @@ class InferenceSessionWrap : public Napi::ObjectWrap<InferenceSessionWrap> {
*/
Napi::Value Run(const Napi::CallbackInfo &info);

/**
* [sync] dispose the session.
* @param nothing
* @returns nothing
* @throw nothing
*/
Napi::Value Dispose(const Napi::CallbackInfo &info);

// private members

// persistent constructor
static Napi::FunctionReference constructor;

// session objects
bool initialized_;
bool disposed_;
std::unique_ptr<Ort::Session> session_;
std::unique_ptr<Ort::RunOptions> defaultRunOptions_;

Expand Down

0 comments on commit ffa6602

Please sign in to comment.