Skip to content

Commit 838fcda

Browse files
authored
refactor: expose memory stats accessor on idetik (#679)
summary: add a read-only memoryStats accessor on idetik for baseline memory instrumentation ahead of experimenting with shared residency. the accessor reports: - cpu-resident chunk bytes + chunk count - gpu texture bytes + texture count - js heap usage (chromium performance.memory, optional)
1 parent b59a0a1 commit 838fcda

9 files changed

Lines changed: 98 additions & 2 deletions

File tree

src/core/renderer.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ export abstract class Renderer {
6060
return this.renderedObjects_;
6161
}
6262

63+
public abstract get gpuTextureBytes(): number;
64+
65+
public abstract get gpuTextureCount(): number;
66+
6367
public set backgroundColor(color: ColorLike) {
6468
this.backgroundColor_ = Color.from(color);
6569
}

src/data/chunk_manager.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { ChunkSource } from "./chunk";
22
import { ChunkQueue } from "./chunk_queue";
3+
import { chunkMemoryStats } from "./chunk_memory";
34

45
export type QueueStats = {
56
pending: number;
@@ -21,6 +22,10 @@ export class ChunkManager {
2122
};
2223
}
2324

25+
public get memoryStats() {
26+
return chunkMemoryStats();
27+
}
28+
2429
public async addView(
2530
source: ChunkSource,
2631
policy: ImageSourcePolicy

src/data/chunk_memory.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { Chunk, ChunkData } from "./chunk";
2+
3+
// Running totals for CPU-resident chunk voxel data. All mutations of
4+
// `chunk.data` must route through setChunkData/clearChunkData so these stay
5+
// accurate. Module-level (not per-store) because chunk loaders are created
6+
// per-source and have no back-reference to their store; this means the totals
7+
// are summed across all Idetik instances in the page, which is fine for the
8+
// single-instance debug/instrumentation use case.
9+
10+
let cpuChunkBytes = 0;
11+
let cpuChunkCount = 0;
12+
13+
export function setChunkData(chunk: Chunk, data: ChunkData): void {
14+
if (chunk.data) {
15+
cpuChunkBytes -= chunk.data.byteLength;
16+
cpuChunkCount -= 1;
17+
}
18+
chunk.data = data;
19+
cpuChunkBytes += data.byteLength;
20+
cpuChunkCount += 1;
21+
}
22+
23+
export function clearChunkData(chunk: Chunk): void {
24+
if (chunk.data) {
25+
cpuChunkBytes -= chunk.data.byteLength;
26+
cpuChunkCount -= 1;
27+
}
28+
chunk.data = undefined;
29+
}
30+
31+
export function chunkMemoryStats() {
32+
return { cpuChunkBytes, cpuChunkCount };
33+
}

src/data/chunk_store.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Chunk, SourceDimensionMap, ChunkLoader } from "./chunk";
2+
import { clearChunkData } from "./chunk_memory";
23
import { almostEqual } from "../utilities/almost_equal";
34
import { Logger } from "../utilities/logger";
45
import { ChunkStoreView } from "./chunk_store_view";
@@ -223,7 +224,7 @@ export class ChunkStore {
223224
);
224225
}
225226

226-
chunk.data = undefined;
227+
clearChunkData(chunk);
227228
chunk.state = "unloaded";
228229
chunk.orderKey = null;
229230
Logger.debug(

src/data/ome_zarr/image_loader.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as zarr from "zarrita";
22

33
import { Chunk, SourceDimension, SourceDimensionMap } from "../chunk";
4+
import { setChunkData } from "../chunk_memory";
45
import { isTextureUnpackRowAlignment } from "../../objects/textures/texture";
56

67
import { Image as OmeZarrImage } from "./0.5/image";
@@ -96,7 +97,7 @@ export class OmeZarrImageLoader {
9697
);
9798
}
9899
chunk.rowAlignmentBytes = rowAlignment;
99-
chunk.data = data;
100+
setChunkData(chunk, data);
100101
}
101102
}
102103

src/idetik.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,17 @@ export type IdetikContext = {
2727
chunkManager: ChunkManager;
2828
};
2929

30+
// JS heap usage from the non-standard performance.memory API.
31+
// Chromium only, undefined where the API is unavailable.
32+
type MemoryStats = {
33+
cpuChunkBytes: number;
34+
cpuChunkCount: number;
35+
gpuTextureBytes: number;
36+
gpuTextureCount: number;
37+
jsHeapUsedBytes?: number;
38+
jsHeapLimitBytes?: number;
39+
};
40+
3041
export class Idetik {
3142
private readonly chunkManager_: ChunkManager;
3243
private readonly context_: IdetikContext;
@@ -137,6 +148,22 @@ export class Idetik {
137148
return this.chunkManager_.queueStats;
138149
}
139150

151+
public get memoryStats(): MemoryStats {
152+
const perf = (
153+
performance as Performance & {
154+
memory?: { usedJSHeapSize: number; jsHeapSizeLimit: number };
155+
}
156+
).memory;
157+
158+
return {
159+
...this.chunkManager_.memoryStats,
160+
gpuTextureBytes: this.renderer_.gpuTextureBytes,
161+
gpuTextureCount: this.renderer_.gpuTextureCount,
162+
jsHeapUsedBytes: perf?.usedJSHeapSize,
163+
jsHeapLimitBytes: perf?.jsHeapSizeLimit,
164+
};
165+
}
166+
140167
public get renderedObjects() {
141168
return this.renderer_.renderedObjects;
142169
}

src/renderers/webgl_renderer.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@ export class WebGLRenderer extends Renderer {
6161
this.resize(this.canvas.width, this.canvas.height);
6262
}
6363

64+
public get gpuTextureBytes() {
65+
return this.textures_.gpuTextureBytes;
66+
}
67+
68+
public get gpuTextureCount() {
69+
return this.textures_.textureCount;
70+
}
71+
6472
public render(viewport: Viewport) {
6573
this.renderedObjects_ = 0;
6674
this.renderedObjectsPerFrame_ = 0;

src/renderers/webgl_textures.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ export class WebGLTextures {
3030
this.maxTextureUnits_ = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
3131
}
3232

33+
public get gpuTextureBytes() {
34+
return this.gpuTextureBytes_;
35+
}
36+
37+
public get textureCount() {
38+
return this.textureCount_;
39+
}
40+
3341
public bindTexture(texture: Texture, index: number) {
3442
if (this.alreadyActive(texture)) return;
3543

src/renderers/webgpu/webgpu_renderer.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,15 @@ class WebGPURenderer extends Renderer {
441441
projectionMatrix
442442
);
443443
}
444+
445+
// The experimental WebGPU texture pool does not track byte usage yet.
446+
public get gpuTextureBytes() {
447+
return 0;
448+
}
449+
450+
public get gpuTextureCount() {
451+
return 0;
452+
}
444453
}
445454

446455
function shaderNameForTexture(texture: Texture): ShaderName {

0 commit comments

Comments
 (0)