From 10e99754d027107c70bb27975263632c203d230e Mon Sep 17 00:00:00 2001 From: Max Richter Date: Fri, 26 Apr 2024 16:09:00 +0200 Subject: [PATCH] feat: some stuff --- app/src/lib/result-viewer/Viewer.svelte | 36 +++++++++++++++++-------- app/src/lib/runtime-executor.ts | 9 ++++--- app/src/routes/+page.svelte | 20 ++++---------- packages/types/src/components.ts | 2 +- packages/utils/src/fastHash.test.ts | 12 ++++----- packages/utils/src/fastHash.ts | 4 +-- 6 files changed, 45 insertions(+), 38 deletions(-) diff --git a/app/src/lib/result-viewer/Viewer.svelte b/app/src/lib/result-viewer/Viewer.svelte index bb7e603..9faff43 100644 --- a/app/src/lib/result-viewer/Viewer.svelte +++ b/app/src/lib/result-viewer/Viewer.svelte @@ -7,12 +7,10 @@ Float32BufferAttribute, Vector3, } from "three"; - import { decodeFloat } from "@nodes/utils"; + import { decodeFloat, fastHashArrayBuffer } from "@nodes/utils"; import type { PerformanceStore } from "$lib/performance"; import { AppSettings } from "$lib/settings/app-settings"; - export let result: Int32Array; - export let centerCamera: boolean = true; export let perf: PerformanceStore; @@ -22,6 +20,22 @@ let totalVertices = 0; let totalFaces = 0; + function fastArrayHash(arr: ArrayBuffer) { + let ints = new Uint8Array(arr); + + const sampleDistance = Math.max(Math.floor(ints.length / 100), 1); + const sampleCount = Math.floor(ints.length / sampleDistance); + + let hash = new Uint8Array(sampleCount); + + for (let i = 0; i < sampleCount; i++) { + const index = i * sampleDistance; + hash[i] = ints[index]; + } + + return fastHashArrayBuffer(hash.buffer); + } + function createGeometryFromEncodedData( encodedData: Int32Array, geometry = new BufferGeometry(), @@ -47,6 +61,10 @@ vertexCount * 3, ); index = index + vertexCount * 3; + let hash = fastArrayHash(vertices); + if (geometry.userData?.hash === hash) { + return geometry; + } const normals = new Float32Array( encodedData.buffer, @@ -90,6 +108,7 @@ geometry.userData = { vertexCount, faceCount, + hash, }; return geometry; @@ -153,11 +172,11 @@ return positions; } - $: if (result) { + export const update = function updateGeometries(result: Int32Array) { let a = performance.now(); const inputs = parse_args(result); let b = performance.now(); - perf?.addPoint("parse-args", b - a); + perf?.addPoint("split-result", b - a); totalVertices = 0; totalFaces = 0; @@ -185,14 +204,9 @@ .filter(Boolean) as BufferGeometry[]; b = performance.now(); perf?.addPoint("create-geometries", b - a); - - for (const geometry of geometries) { - geometry.needsUpdate = true; - } - perf?.addPoint("total-vertices", totalVertices); perf?.addPoint("total-faces", totalFaces); - } + }; diff --git a/app/src/lib/runtime-executor.ts b/app/src/lib/runtime-executor.ts index 6e740de..9a2dee2 100644 --- a/app/src/lib/runtime-executor.ts +++ b/app/src/lib/runtime-executor.ts @@ -1,5 +1,5 @@ import type { Graph, NodeRegistry, NodeDefinition, RuntimeExecutor, NodeInput } from "@nodes/types"; -import { concatEncodedArrays, encodeFloat, fastHashArray } from "@nodes/utils" +import { concatEncodedArrays, encodeFloat, fastHashArrayBuffer } from "@nodes/utils" import { createLogger } from "./helpers"; import type { RuntimeCache } from "@nodes/types"; import type { PerformanceStore } from "./performance"; @@ -138,7 +138,7 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor { const [outputNode, nodes] = await this.addMetaData(graph); let b = performance.now(); - this.perf?.addPoint("metadata", b - a); + this.perf?.addPoint("collect-metadata", b - a); /* * Here we sort the nodes into buckets, which we then execute one by one @@ -211,7 +211,10 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor { b = performance.now(); this.perf?.addPoint("encoded-inputs", b - a); - let inputHash = `node-${node.id}-${fastHashArray(encoded_inputs)}`; + a = performance.now(); + let inputHash = `node-${node.id}-${fastHashArrayBuffer(encoded_inputs)}`; + b = performance.now(); + this.perf?.addPoint("hash-inputs", b - a); let cachedValue = this.cache?.get(inputHash); if (cachedValue !== undefined) { log.log(`Using cached value for ${node_type.id || node.id}`); diff --git a/app/src/routes/+page.svelte b/app/src/routes/+page.svelte index f045a5f..70891f9 100644 --- a/app/src/routes/+page.svelte +++ b/app/src/routes/+page.svelte @@ -14,11 +14,6 @@ import NodeStore from "$lib/node-store/NodeStore.svelte"; import type { GraphManager } from "$lib/graph-interface/graph-manager"; import { setContext } from "svelte"; - import { - decodeFloat, - decodeNestedArray, - encodeNestedArray, - } from "@nodes/utils"; import ActiveNodeSettings from "$lib/settings/panels/ActiveNodeSettings.svelte"; import PerformanceViewer from "$lib/performance/PerformanceViewer.svelte"; import Panel from "$lib/settings/Panel.svelte"; @@ -26,28 +21,22 @@ import NestedSettings from "$lib/settings/panels/NestedSettings.svelte"; import { createPerformanceStore } from "$lib/performance"; import { type PerformanceData } from "$lib/performance/store"; - import { RemoteRuntimeExecutor } from "$lib/remote-runtime-executor"; const nodeRegistry = new RemoteNodeRegistry(""); const workerRuntime = new WorkerRuntimeExecutor(); - // const remoteRuntime = new RemoteRuntimeExecutor("/runtime"); let performanceData: PerformanceData; let viewerPerformance = createPerformanceStore(); - globalThis.decode = decodeNestedArray; - globalThis.encode = encodeNestedArray; - globalThis.decodeFloat = decodeFloat; - let res: Int32Array; let activeNode: Node | undefined; + let updateViewer: (arg: Int32Array) => void; + let graph = localStorage.getItem("graph") ? JSON.parse(localStorage.getItem("graph")!) : templates.plant; - console.log({ graph }); - let manager: GraphManager; let managerStatus: Writable<"loading" | "error" | "idle">; $: if (manager) { @@ -80,8 +69,9 @@ try { let a = performance.now(); // res = await remoteRuntime.execute(_graph, _settings); - res = await workerRuntime.execute(_graph, _settings); + let res = await workerRuntime.execute(_graph, _settings); let b = performance.now(); + updateViewer(res); let perfData = await workerRuntime.getPerformanceData(); let lastRun = perfData.runs?.at(-1); if (lastRun) { @@ -125,7 +115,7 @@ diff --git a/packages/types/src/components.ts b/packages/types/src/components.ts index f941f18..8b2a324 100644 --- a/packages/types/src/components.ts +++ b/packages/types/src/components.ts @@ -13,7 +13,7 @@ export interface NodeRegistry { * @throws An error if the nodes could not be loaded * @remarks This method should be called before calling getNode or getAllNodes */ - load: (nodeIds: (NodeId | string)[]) => Promise; + load: (nodeIds: NodeId[]) => Promise; /** * Get a node by id * @param id - The id of the node to get diff --git a/packages/utils/src/fastHash.test.ts b/packages/utils/src/fastHash.test.ts index 4c6dd09..ae8d729 100644 --- a/packages/utils/src/fastHash.test.ts +++ b/packages/utils/src/fastHash.test.ts @@ -14,10 +14,10 @@ test("fastHashArray doesnt product collisions", () => { const a = new Int32Array(1000); - const hash_a = fastHashArray(a); + const hash_a = fastHashArray(a.buffer); a[0] = 1; - const hash_b = fastHashArray(a); + const hash_b = fastHashArray(a.buffer); expect(hash_a).not.toEqual(hash_b); @@ -28,13 +28,13 @@ test('fastHashArray is fast(ish) < 20ms', () => { const a = new Int32Array(10_000); const t0 = performance.now(); - fastHashArray(a); + fastHashArray(a.buffer); const t1 = performance.now(); a[0] = 1; - fastHashArray(a); + fastHashArray(a.buffer); const t2 = performance.now(); @@ -48,7 +48,7 @@ test('fastHashArray is deterministic', () => { a[42] = 69; const b = new Int32Array(1000); b[42] = 69; - const hashA = fastHashArray(a); - const hashB = fastHashArray(b); + const hashA = fastHashArray(a.buffer); + const hashB = fastHashArray(b.buffer); expect(hashA).toEqual(hashB); }); diff --git a/packages/utils/src/fastHash.ts b/packages/utils/src/fastHash.ts index 1bfc4a3..6019522 100644 --- a/packages/utils/src/fastHash.ts +++ b/packages/utils/src/fastHash.ts @@ -83,8 +83,8 @@ function sha256(data?: string | Uint8Array) { return { add, digest }; } -export function fastHashArray(arr: Int32Array): string { - return sha256(new Uint8Array(arr.buffer)).digest(); +export function fastHashArrayBuffer(buffer: ArrayBuffer): string { + return sha256(new Uint8Array(buffer)).digest(); } // Shamelessly copied from