human/src/util/env.ts

188 lines
6.6 KiB
TypeScript
Raw Normal View History

2022-10-17 02:28:57 +02:00
import * as tf from 'dist/tfjs.esm.js';
2021-09-27 19:58:13 +02:00
import * as image from '../image/image';
2021-09-12 18:42:17 +02:00
2021-10-21 16:26:44 +02:00
/** Env class that holds detected capabilities */
export class Env {
2021-10-10 23:52:43 +02:00
/** Running in Browser */
2021-10-21 16:26:44 +02:00
browser: boolean;
2021-10-10 23:52:43 +02:00
/** Running in NodeJS */
2021-10-21 16:26:44 +02:00
node: boolean;
2021-10-10 23:52:43 +02:00
/** Running in WebWorker thread */
2021-10-21 16:26:44 +02:00
worker: boolean;
2021-10-10 23:52:43 +02:00
/** Detected platform */
2021-10-21 16:26:44 +02:00
platform: string = '';
2021-10-10 23:52:43 +02:00
/** Detected agent */
2021-10-21 16:26:44 +02:00
agent: string = '';
2021-10-10 23:52:43 +02:00
/** List of supported backends */
2021-10-21 16:26:44 +02:00
backends: string[] = [];
2021-10-10 23:52:43 +02:00
/** Has any work been performed so far */
2021-10-21 16:26:44 +02:00
initial: boolean;
2021-10-10 23:52:43 +02:00
/** Are image filters supported? */
2021-10-21 16:26:44 +02:00
filter: boolean | undefined;
2021-10-10 23:52:43 +02:00
/** TFJS instance details */
2021-09-12 18:42:17 +02:00
tfjs: {
version: undefined | string,
2021-10-21 16:26:44 +02:00
};
2021-10-10 23:52:43 +02:00
/** Is offscreenCanvas supported? */
2021-10-21 16:26:44 +02:00
offscreen: undefined | boolean;
2021-10-23 15:38:52 +02:00
/** Are performance counter instant values or additive */
perfadd: boolean = false;
2022-08-15 17:40:15 +02:00
/** If using tfjs-node get version of underlying tensorflow shared library and if gpu acceleration is enabled */
2022-08-15 17:29:56 +02:00
tensorflow: {
version: undefined | string,
2022-08-15 17:40:15 +02:00
gpu: undefined | boolean,
} = {
version: undefined,
gpu: undefined,
};
2021-10-10 23:52:43 +02:00
/** WASM detected capabilities */
2021-09-12 18:42:17 +02:00
wasm: {
supported: undefined | boolean,
backend: undefined | boolean,
2021-09-12 18:42:17 +02:00
simd: undefined | boolean,
multithread: undefined | boolean,
2021-10-21 16:26:44 +02:00
} = {
supported: undefined,
backend: undefined,
simd: undefined,
multithread: undefined,
};
2021-10-10 23:52:43 +02:00
/** WebGL detected capabilities */
2021-09-12 18:42:17 +02:00
webgl: {
supported: undefined | boolean,
backend: undefined | boolean,
2021-09-12 18:42:17 +02:00
version: undefined | string,
renderer: undefined | string,
2022-11-11 02:16:40 +01:00
shader: undefined | string,
vendor: undefined | string,
2021-10-21 16:26:44 +02:00
} = {
supported: undefined,
backend: undefined,
version: undefined,
renderer: undefined,
2022-11-11 02:16:40 +01:00
shader: undefined,
vendor: undefined,
2021-10-21 16:26:44 +02:00
};
2021-10-10 23:52:43 +02:00
/** WebGPU detected capabilities */
2021-09-12 18:42:17 +02:00
webgpu: {
supported: undefined | boolean,
backend: undefined | boolean,
2022-11-11 02:16:40 +01:00
adapter: undefined | GPUAdapterInfo,
2021-10-21 16:26:44 +02:00
} = {
supported: undefined,
backend: undefined,
adapter: undefined,
};
/** CPU info */
cpu: {
model: undefined | string,
flags: string[],
} = {
model: undefined,
flags: [],
};
2021-10-10 23:52:43 +02:00
/** List of supported kernels for current backend */
2021-10-21 16:26:44 +02:00
kernels: string[] = [];
2022-11-22 16:33:31 +01:00
/** MonkeyPatch for Canvas/Image/ImageData */
#canvas: undefined;
#image: undefined;
#imageData: undefined;
get Canvas() { return this.#canvas; }
set Canvas(val) { this.#canvas = val; globalThis.Canvas = val; }
get Image() { return this.#image; }
// @ts-ignore monkey-patch;
set Image(val) { this.#image = val; globalThis.Image = val; }
get ImageData() { return this.#imageData; }
// @ts-ignore monkey-patch;
set ImageData(val) { this.#imageData = val; globalThis.ImageData = val; }
2021-09-12 18:42:17 +02:00
2021-10-21 16:26:44 +02:00
constructor() {
this.browser = (typeof navigator !== 'undefined') && (typeof navigator.appVersion !== 'undefined');
this.node = (typeof process !== 'undefined') && (typeof process.versions !== 'undefined') && (typeof process.versions.node !== 'undefined');
2021-11-18 16:10:06 +01:00
this.tfjs = { version: tf.version['tfjs-core'] };
2021-10-21 16:26:44 +02:00
this.offscreen = typeof OffscreenCanvas !== 'undefined';
this.initial = true;
2022-08-15 17:29:56 +02:00
2021-10-21 16:26:44 +02:00
// @ts-ignore WorkerGlobalScope evaluated in browser only
this.worker = this.browser && this.offscreen ? (typeof WorkerGlobalScope !== 'undefined') : undefined;
2023-01-12 21:40:37 +01:00
if ((typeof navigator !== 'undefined') && (typeof navigator.userAgent !== 'undefined')) { // TBD replace with navigator.userAgentData once in mainline
const agent = navigator.userAgent || '';
const raw = agent.match(/\(([^()]+)\)/g);
2022-08-21 21:23:03 +02:00
if (raw?.[0]) {
2021-10-21 16:26:44 +02:00
const platformMatch = raw[0].match(/\(([^()]+)\)/g);
2022-08-21 21:23:03 +02:00
this.platform = (platformMatch?.[0]) ? platformMatch[0].replace(/\(|\)/g, '') : '';
2023-01-12 21:40:37 +01:00
this.agent = agent.replace(raw[0], '');
2021-10-21 16:26:44 +02:00
if (this.platform[1]) this.agent = this.agent.replace(raw[1], '');
this.agent = this.agent.replace(/ /g, ' ');
2021-09-12 18:42:17 +02:00
}
2021-10-21 16:26:44 +02:00
} else if (typeof process !== 'undefined') {
this.platform = `${process.platform} ${process.arch}`;
this.agent = `NodeJS ${process.version}`;
}
}
2021-11-17 21:45:49 +01:00
/** update backend information */
2021-10-21 16:26:44 +02:00
async updateBackend() {
// analyze backends
this.backends = Object.keys(tf.engine().registryFactory);
2022-11-11 17:11:27 +01:00
try { // backend may not be initialized
2022-11-11 02:16:40 +01:00
this.tensorflow = {
version: (tf.backend()['binding'] ? tf.backend()['binding'].TF_Version : undefined),
gpu: (tf.backend()['binding'] ? tf.backend()['binding'].isUsingGpuDevice() : undefined),
};
} catch { /**/ }
2021-10-21 16:26:44 +02:00
this.wasm.supported = typeof WebAssembly !== 'undefined';
this.wasm.backend = this.backends.includes('wasm');
2022-11-11 02:16:40 +01:00
if (this.wasm.supported && this.wasm.backend) {
this.wasm.simd = await tf.env().getAsync('WASM_HAS_SIMD_SUPPORT') as boolean;
this.wasm.multithread = await tf.env().getAsync('WASM_HAS_MULTITHREAD_SUPPORT') as boolean;
2021-10-21 16:26:44 +02:00
}
const c = image.canvas(100, 100);
2022-11-11 17:11:27 +01:00
const gl = c ? c.getContext('webgl2') as WebGL2RenderingContext : undefined; // causes too many gl contexts
this.webgl.supported = typeof gl !== 'undefined';
2021-10-21 16:26:44 +02:00
this.webgl.backend = this.backends.includes('webgl');
2022-11-11 17:11:27 +01:00
if (this.webgl.supported && this.webgl.backend && gl) {
2022-11-11 02:16:40 +01:00
this.webgl.version = gl.getParameter(gl.VERSION);
this.webgl.vendor = gl.getParameter(gl.VENDOR);
this.webgl.renderer = gl.getParameter(gl.RENDERER);
this.webgl.shader = gl.getParameter(gl.SHADING_LANGUAGE_VERSION);
2021-09-12 18:42:17 +02:00
}
2023-01-12 21:40:37 +01:00
this.webgpu.supported = this.browser && typeof navigator !== 'undefined' && typeof navigator.gpu !== 'undefined';
2021-10-21 16:26:44 +02:00
this.webgpu.backend = this.backends.includes('webgpu');
2021-11-14 17:22:52 +01:00
try {
2022-08-21 19:34:51 +02:00
if (this.webgpu.supported) {
const adapter = await navigator.gpu.requestAdapter();
2022-11-11 02:16:40 +01:00
this.webgpu.adapter = await adapter?.requestAdapterInfo();
2022-08-21 19:34:51 +02:00
}
2021-11-14 17:22:52 +01:00
} catch {
this.webgpu.supported = false;
}
2021-11-21 22:55:17 +01:00
try {
2022-10-17 02:28:57 +02:00
this.kernels = tf.getKernelsForBackend(tf.getBackend()).map((kernel) => kernel.kernelName.toLowerCase());
2021-11-21 22:55:17 +01:00
} catch { /**/ }
2021-09-12 18:42:17 +02:00
}
2021-11-17 21:45:49 +01:00
/** update cpu information */
2022-08-10 19:44:38 +02:00
updateCPU() {
2021-10-21 16:26:44 +02:00
const cpu = { model: '', flags: [] };
2021-11-04 11:34:13 +01:00
if (this.node && this.platform.startsWith('linux')) {
2021-11-17 22:50:21 +01:00
/*
2021-10-21 16:26:44 +02:00
const fs = require('fs');
try {
const data = fs.readFileSync('/proc/cpuinfo').toString();
for (const line of data.split('\n')) {
2022-07-16 15:08:58 +02:00
if (line.startsWith('model name')) cpu.model = line.match(/:(.*)/g)[0].replace(':', '').trim();
if (line.startsWith('flags')) cpu.flags = line.match(/:(.*)/g)[0].replace(':', '').trim().split(' ').sort();
2021-10-21 16:26:44 +02:00
}
2021-11-17 22:50:21 +01:00
} catch { }
*/
2021-10-21 16:26:44 +02:00
}
2022-08-21 19:34:51 +02:00
if (!this.cpu) Object.defineProperty(this, 'cpu', { value: cpu });
else this.cpu = cpu;
2021-10-21 16:26:44 +02:00
}
2021-09-12 18:42:17 +02:00
}
2021-09-20 23:17:13 +02:00
2021-10-21 16:26:44 +02:00
export const env = new Env();