onnxruntime/js/common/lib/backend-impl.ts
Yulong Wang 009f342caf
[JS] refactor Javascript/Typescript libraries in ONNX Runtime (#7308)
* working on re-organizing js code for ortweb

* remove dup files

* move folder

* fix common references

* fix common es5

* add webpack to common

* split interfact/impl

* use cjs for node

* add npmignore for common

* update sourcemap config for common

* update node

* adjust folder/path in CI and build

* update folder

* nit: readme

* add bundle for dev

* correct nodejs paths

* enable ORT_API_MANUAL_INIT

* set name for umd library

* correct name for commonjs export

* add priority into registerBackend()

* fix npm ci pwd

* update eslintrc

* revise code

* revert package-lock lockfileVersion 2->1

* update prebuild

* resolve comments

* update document

* revise eslint config

* update eslint for typescript rules

* revert changes by mistake in backend.ts

* add env

* resolve comments
2021-04-16 01:33:10 -07:00

84 lines
2.7 KiB
TypeScript

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {Backend} from './backend';
interface BackendInfo {
backend: Backend;
priority: number;
initializing?: boolean;
initialized?: boolean;
aborted?: boolean;
}
const backends: {[name: string]: BackendInfo} = {};
const backendsSortedByPriority: string[] = [];
/**
* Register a backend.
*
* @param name the name as a key to lookup as an execution provider.
* @param backend the backend object.
* @param priority an integer indicating the priority of the backend. Higher number means higher priority.
*/
export const registerBackend = (name: string, backend: Backend, priority: number): void => {
if (backend && typeof backend.init === 'function' && typeof backend.createSessionHandler === 'function') {
const currentBackend = backends[name];
if (currentBackend === undefined) {
backends[name] = {backend, priority};
} else if (currentBackend.backend === backend) {
return;
} else {
throw new Error(`backend "${name}" is already registered`);
}
for (let i = 0; i < backendsSortedByPriority.length; i++) {
if (backends[backendsSortedByPriority[i]].priority <= priority) {
backendsSortedByPriority.splice(i, 0, name);
return;
}
}
backendsSortedByPriority.push(name);
return;
}
throw new TypeError('not a valid backend');
};
/**
* Resolve backend by specified hints.
*
* @param backendHints a list of execution provider names to lookup. If omitted use registered backends as list.
* @returns a promise that resolves to the backend.
*/
export const resolveBackend = async(backendHints: readonly string[]): Promise<Backend> => {
const backendNames = backendHints.length === 0 ? backendsSortedByPriority : backendHints;
const errors = [];
for (const backendName of backendNames) {
const backendInfo = backends[backendName];
if (backendInfo) {
if (backendInfo.initialized) {
return backendInfo.backend;
} else if (backendInfo.initializing) {
throw new Error(`backend "${backendName}" is being initialized; cannot initialize multiple times.`);
} else if (backendInfo.aborted) {
continue; // current backend is unavailable; try next
}
try {
backendInfo.initializing = true;
await backendInfo.backend.init();
backendInfo.initialized = true;
return backendInfo.backend;
} catch (e) {
errors.push({name: backendName, err: e});
backendInfo.aborted = true;
} finally {
backendInfo.initializing = false;
}
}
}
throw new Error(`no available backend found. ERR: ${errors.join(', ')}`);
};