mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-05-18 21:21:17 +00:00
### Description
This PR revises the backend registration.
The following describes the expected behavior after this change:
(**bolded are changed behavior**)
- (ort.min.js - built without webgpu support)
- loading: do not register 'webgpu' backend
- creating session without EP list: use default EP list ['webnn', 'cpu',
'wasm']
- creating session with ['webgpu'] as EP list: should fail with backend
not available
- (ort.webgpu.min.js - built with webgpu support)
- loading: **always register 'webgpu' backend**
( previous behavior: only register 'webgpu' backend when `navigator.gpu`
is available)
- creating session without EP list: use default EP list ['webgpu',
'webnn', 'cpu', 'wasm']
- when WebGPU is available (win): use WebGPU backend
- when WebGPU is unavailable (android): **should fail backend init,**
and try to use next backend in the list, 'webnn'
(previous behavior: does not fail backend init, but fail in JSEP init,
which was too late to switch to next backend)
- creating session with ['webgpu'] as EP list
- when WebGPU is available (win): use WebGPU backend
- when WebGPU is unavailable (android): **should fail backend init, and
because no more EP listed, fail.
related PRs: #18190 #18144
102 lines
3.3 KiB
TypeScript
102 lines
3.3 KiB
TypeScript
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// Licensed under the MIT License.
|
|
|
|
import {Backend} from './backend.js';
|
|
|
|
interface BackendInfo {
|
|
backend: Backend;
|
|
priority: number;
|
|
|
|
initPromise?: Promise<void>;
|
|
initialized?: boolean;
|
|
aborted?: boolean;
|
|
}
|
|
|
|
const backends: Map<string, BackendInfo> = new Map();
|
|
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. if priority
|
|
* < 0, it will be considered as a 'beta' version and will not be used as a fallback backend by default.
|
|
*
|
|
* @ignore
|
|
*/
|
|
export const registerBackend = (name: string, backend: Backend, priority: number): void => {
|
|
if (backend && typeof backend.init === 'function' && typeof backend.createInferenceSessionHandler === 'function') {
|
|
const currentBackend = backends.get(name);
|
|
if (currentBackend === undefined) {
|
|
backends.set(name, {backend, priority});
|
|
} else if (currentBackend.priority > priority) {
|
|
// same name is already registered with a higher priority. skip registeration.
|
|
return;
|
|
} else if (currentBackend.priority === priority) {
|
|
if (currentBackend.backend !== backend) {
|
|
throw new Error(`cannot register backend "${name}" using priority ${priority}`);
|
|
}
|
|
}
|
|
|
|
if (priority >= 0) {
|
|
const i = backendsSortedByPriority.indexOf(name);
|
|
if (i !== -1) {
|
|
backendsSortedByPriority.splice(i, 1);
|
|
}
|
|
|
|
for (let i = 0; i < backendsSortedByPriority.length; i++) {
|
|
if (backends.get(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.
|
|
*
|
|
* @ignore
|
|
*/
|
|
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.get(backendName);
|
|
if (backendInfo) {
|
|
if (backendInfo.initialized) {
|
|
return backendInfo.backend;
|
|
} else if (backendInfo.aborted) {
|
|
continue; // current backend is unavailable; try next
|
|
}
|
|
|
|
const isInitializing = !!backendInfo.initPromise;
|
|
try {
|
|
if (!isInitializing) {
|
|
backendInfo.initPromise = backendInfo.backend.init(backendName);
|
|
}
|
|
await backendInfo.initPromise;
|
|
backendInfo.initialized = true;
|
|
return backendInfo.backend;
|
|
} catch (e) {
|
|
if (!isInitializing) {
|
|
errors.push({name: backendName, err: e});
|
|
}
|
|
backendInfo.aborted = true;
|
|
} finally {
|
|
delete backendInfo.initPromise;
|
|
}
|
|
}
|
|
}
|
|
|
|
throw new Error(`no available backend found. ERR: ${errors.map(e => `[${e.name}] ${e.err}`).join(', ')}`);
|
|
};
|