This is an automated email from the ASF dual-hosted git repository. tqchen pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tvm.git
The following commit(s) were added to refs/heads/main by this push: new 40ec46970f [WEB] Move ArtifactCache to Interface, Support Cache delete and Batch Delete, Remove typo (#16525) 40ec46970f is described below commit 40ec46970f7e1b94a0eec3b4da8868d1ec179d69 Author: Diego Cao <50705298+diego...@users.noreply.github.com> AuthorDate: Mon Feb 19 14:02:58 2024 -0500 [WEB] Move ArtifactCache to Interface, Support Cache delete and Batch Delete, Remove typo (#16525) Parallel Download, Move ArtifactCache to Interface to support future different cache types, fix README path typo, Support delete and batch delete Co-authored-by: DavidGOrtega <g.ortega.da...@gmail.com> --- web/README.md | 2 +- web/package-lock.json | 4 ++-- web/src/artifact_cache.ts | 19 ++++++++++++++++++ web/src/index.ts | 2 +- web/src/runtime.ts | 51 ++++++++++++++++++++++++++++++++++++++++------- 5 files changed, 67 insertions(+), 11 deletions(-) diff --git a/web/README.md b/web/README.md index 64f507579e..9b3cda1fb7 100644 --- a/web/README.md +++ b/web/README.md @@ -94,4 +94,4 @@ Right now we use the SPIRV to generate shaders that can be accepted by Chrome an - Firefox should be close pending the support of Fence. - Download vulkan SDK (1.1 or higher) that supports SPIRV 1.3 - Start the WebSocket RPC -- run `python tests/node/webgpu_rpc_test.py` +- run `python tests/python/webgpu_rpc_test.py` diff --git a/web/package-lock.json b/web/package-lock.json index 37bac4493f..74561324c9 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,12 +1,12 @@ { "name": "tvmjs", - "version": "0.15.0-dev0", + "version": "0.16.0-dev0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "tvmjs", - "version": "0.15.0-dev0", + "version": "0.16.0-dev0", "license": "Apache-2.0", "devDependencies": { "@rollup/plugin-commonjs": "^20.0.0", diff --git a/web/src/artifact_cache.ts b/web/src/artifact_cache.ts new file mode 100644 index 0000000000..394cda83bc --- /dev/null +++ b/web/src/artifact_cache.ts @@ -0,0 +1,19 @@ +/* + Common Interface for the artifact cache +*/ +export interface ArtifactCacheTemplate { + /** + * fetch key url from cache + */ + fetchWithCache(url: string); + + /** + * check if cache has all keys in Cache + */ + hasAllKeys(keys: string[]); + + /** + * Delete url in cache if url exists + */ + deleteInCache(url: string); +} diff --git a/web/src/index.ts b/web/src/index.ts index fd27fce9fd..9099d8f373 100644 --- a/web/src/index.ts +++ b/web/src/index.ts @@ -22,7 +22,7 @@ export { PackedFunc, Module, NDArray, TVMArray, TVMObject, VirtualMachine, InitProgressCallback, InitProgressReport, - ArtifactCache, Instance, instantiate, hasNDArrayInCache + ArtifactCache, Instance, instantiate, hasNDArrayInCache, deleteNDArrayCache } from "./runtime"; export { Disposable, LibraryProvider } from "./types"; export { RPCServer } from "./rpc_server"; diff --git a/web/src/runtime.ts b/web/src/runtime.ts index cf2a6069e4..cf8d17e772 100644 --- a/web/src/runtime.ts +++ b/web/src/runtime.ts @@ -26,6 +26,7 @@ import { Memory, CachedCallStack } from "./memory"; import { assert, StringToUint8Array } from "./support"; import { Environment } from "./environment"; import { FunctionInfo, WebGPUContext } from "./webgpu"; +import { ArtifactCacheTemplate } from "./artifact_cache"; import * as compact from "./compact"; import * as ctypes from "./ctypes"; @@ -988,7 +989,7 @@ export type InitProgressCallback = (report: InitProgressReport) => void; /** * Cache to store model related data. */ -export class ArtifactCache { +export class ArtifactCache implements ArtifactCacheTemplate { private scope: string; private cache?: Cache; @@ -1021,6 +1022,14 @@ export class ArtifactCache { .then(cacheKeys => keys.every(key => cacheKeys.indexOf(key) !== -1)) .catch(err => false); } + + async deleteInCache(url: string) { + if (this.cache === undefined) { + this.cache = await caches.open(this.scope); + } + const result = await this.cache.delete(url); + return result; + } } /** @@ -1454,7 +1463,7 @@ export class Instance implements Disposable { } /** - * Fetch NDArray cache from url. + * Given cacheUrl, search up items to fetch based on cacheUrl/ndarray-cache.json * * @param ndarrayCacheUrl The cache url. * @param device The device to be fetched to. @@ -1480,6 +1489,7 @@ export class Instance implements Disposable { this.cacheMetadata = { ...this.cacheMetadata, ...(list["metadata"] as Record<string, any>) }; } + /** * Fetch list of NDArray into the NDArrayCache. * @@ -1492,7 +1502,7 @@ export class Instance implements Disposable { ndarrayCacheUrl: string, list: Array<NDArrayShardEntry>, device: DLDevice, - artifactCache: ArtifactCache + artifactCache: ArtifactCacheTemplate ) { const perf = compact.getPerformance(); const tstart = perf.now(); @@ -1539,10 +1549,11 @@ export class Instance implements Disposable { }); } - for (let i = 0; i < list.length; ++i) { + const processShard = async (i: number) => { reportCallback(i); - fetchedBytes += list[i].nbytes; - const dataUrl = new URL(list[i].dataPath, ndarrayCacheUrl).href; + const shard = list[i]; + fetchedBytes += shard.nbytes; + const dataUrl = new URL(shard.dataPath, ndarrayCacheUrl).href; let buffer; try { buffer = await (await artifactCache.fetchWithCache(dataUrl)).arrayBuffer(); @@ -1550,7 +1561,7 @@ export class Instance implements Disposable { this.env.logger("Error: Cannot fetch " + dataUrl + " err= " + err); throw err; } - const shardRecords = list[i].records; + const shardRecords = shard.records; for (let j = 0; j < shardRecords.length; ++j) { const rec = shardRecords[j]; const cpu_arr = this.withNewScope(() => { @@ -1581,6 +1592,7 @@ export class Instance implements Disposable { } timeElapsed = Math.ceil((perf.now() - tstart) / 1000); } + await Promise.all(list.map((_, index) => processShard(index))); reportCallback(list.length); } @@ -2456,3 +2468,28 @@ export async function hasNDArrayInCache( list = list["records"] as Array<NDArrayShardEntry>; return await artifactCache.hasAllKeys(list.map(key => new URL(key.dataPath, ndarrayCacheUrl).href)); } + +/** + * Given cacheUrl, search up items to delete based on cacheUrl/ndarray-cache.json + * + * @param cacheUrl + * @param cacheScope + */ +export async function deleteNDArrayCache( + cacheUrl: string, + cacheScope = "tvmjs" +) { + const artifactCache = new ArtifactCache(cacheScope); + const jsonUrl = new URL("ndarray-cache.json", cacheUrl).href; + const result = await artifactCache.fetchWithCache(jsonUrl); + let list; + if (result instanceof Response){ + list = await result.json(); + } + const arrayentry = list["records"] as Array<NDArrayShardEntry>; + const processShard = async (i: number) => { + const dataUrl = new URL(arrayentry[i].dataPath, cacheUrl).href; + await artifactCache.deleteInCache(dataUrl); + } + await Promise.all(arrayentry.map((_, index) => processShard(index))); +}