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)));
+}

Reply via email to