@camstack/addon-benchmark 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addon-benchmark.css +1 -0
- package/dist/index.js +6 -743
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5 -723
- package/dist/index.mjs.map +1 -1
- package/dist/page.mjs +34094 -0
- package/package.json +44 -12
- package/dist/index.d.mts +0 -222
- package/dist/index.d.ts +0 -222
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runner/stats.ts","../src/runner/accuracy.ts","../src/runner/benchmark-runner.ts","../src/runner/system-info.ts","../src/benchmark-addon.ts","../src/annotator/result-annotator.ts","../src/distributed/benchmark-hub.ts","../src/distributed/benchmark-agent.ts"],"sourcesContent":["import type { LatencyStats } from '@camstack/types'\n\n/**\n * Compute percentile value from a sorted array.\n * @param sorted - ascending-sorted array of numbers\n * @param p - percentile in range [0, 1]\n */\nfunction percentile(sorted: readonly number[], p: number): number {\n if (sorted.length === 0) return 0\n const idx = p * (sorted.length - 1)\n const lo = Math.floor(idx)\n const hi = Math.ceil(idx)\n const loVal = sorted[lo] ?? 0\n const hiVal = sorted[hi] ?? 0\n return loVal + (hiVal - loVal) * (idx - lo)\n}\n\n/**\n * Compute latency statistics from an array of timing measurements in milliseconds.\n */\nexport function computeLatencyStats(timingsMs: readonly number[]): LatencyStats {\n if (timingsMs.length === 0) {\n return { mean: 0, median: 0, p95: 0, p99: 0, min: 0, max: 0 }\n }\n\n const sorted = [...timingsMs].sort((a, b) => a - b)\n const sum = sorted.reduce((acc, v) => acc + v, 0)\n const mean = sum / sorted.length\n\n return {\n mean,\n median: percentile(sorted, 0.5),\n p95: percentile(sorted, 0.95),\n p99: percentile(sorted, 0.99),\n min: sorted[0] ?? 0,\n max: sorted[sorted.length - 1] ?? 0,\n }\n}\n\n/**\n * Compute frames per second from timing measurements.\n */\nexport function computeFps(timingsMs: readonly number[]): number {\n if (timingsMs.length === 0) return 0\n const stats = computeLatencyStats(timingsMs)\n if (stats.mean === 0) return 0\n return 1000 / stats.mean\n}\n","import type { SpatialDetection, BoundingBox, GroundTruthAnnotation, AccuracyStats } from '@camstack/types'\n\n/**\n * Compute Intersection over Union (IoU) between two bounding boxes.\n * Boxes are in {x, y, w, h} format where x, y are top-left corner.\n */\nexport function iou(pred: BoundingBox, gt: BoundingBox): number {\n const predX2 = pred.x + pred.w\n const predY2 = pred.y + pred.h\n const gtX2 = gt.x + gt.w\n const gtY2 = gt.y + gt.h\n\n const interX1 = Math.max(pred.x, gt.x)\n const interY1 = Math.max(pred.y, gt.y)\n const interX2 = Math.min(predX2, gtX2)\n const interY2 = Math.min(predY2, gtY2)\n\n const interW = Math.max(0, interX2 - interX1)\n const interH = Math.max(0, interY2 - interY1)\n const interArea = interW * interH\n\n if (interArea === 0) return 0\n\n const predArea = pred.w * pred.h\n const gtArea = gt.w * gt.h\n const unionArea = predArea + gtArea - interArea\n\n if (unionArea <= 0) return 0\n\n return interArea / unionArea\n}\n\n/**\n * Compute the area under the precision-recall curve using the trapezoidal method.\n */\nfunction areaUnderPRCurve(precision: readonly number[], recall: readonly number[]): number {\n if (precision.length < 2) return precision[0] ?? 0\n let area = 0\n for (let i = 1; i < recall.length; i++) {\n const dr = (recall[i] ?? 0) - (recall[i - 1] ?? 0)\n const avgP = ((precision[i] ?? 0) + (precision[i - 1] ?? 0)) / 2\n area += dr * avgP\n }\n return Math.abs(area)\n}\n\n/**\n * Compute Average Precision (AP) for a single class using greedy matching.\n *\n * @param predictions - All predictions for this class, sorted by score descending\n * @param groundTruths - All ground truth annotations for this class\n * @param iouThreshold - IoU threshold for a match (default 0.5)\n */\nfunction computeClassAP(\n predictions: readonly SpatialDetection[],\n groundTruths: readonly GroundTruthAnnotation[],\n iouThreshold: number,\n): number {\n const nGt = groundTruths.length\n if (nGt === 0) return 0\n if (predictions.length === 0) return 0\n\n const matched = new Set<number>()\n const tp: number[] = []\n const fp: number[] = []\n\n for (const pred of predictions) {\n let bestIou = -1\n let bestGtIdx = -1\n\n for (let i = 0; i < groundTruths.length; i++) {\n if (matched.has(i)) continue\n const gt = groundTruths[i]\n if (!gt) continue\n const score = iou(pred.bbox, gt.bbox)\n if (score > bestIou) {\n bestIou = score\n bestGtIdx = i\n }\n }\n\n if (bestIou >= iouThreshold && bestGtIdx >= 0) {\n matched.add(bestGtIdx)\n tp.push(1)\n fp.push(0)\n } else {\n tp.push(0)\n fp.push(1)\n }\n }\n\n // Compute cumulative TP and FP\n const cumTp: number[] = []\n const cumFp: number[] = []\n let sumTp = 0\n let sumFp = 0\n\n for (let i = 0; i < tp.length; i++) {\n sumTp += tp[i] ?? 0\n sumFp += fp[i] ?? 0\n cumTp.push(sumTp)\n cumFp.push(sumFp)\n }\n\n // Compute precision-recall curve\n const precisions: number[] = []\n const recalls: number[] = []\n\n // Add origin point\n precisions.push(1)\n recalls.push(0)\n\n for (let i = 0; i < cumTp.length; i++) {\n const cTp = cumTp[i] ?? 0\n const cFp = cumFp[i] ?? 0\n const denom = cTp + cFp\n precisions.push(denom > 0 ? cTp / denom : 0)\n recalls.push(nGt > 0 ? cTp / nGt : 0)\n }\n\n return areaUnderPRCurve(precisions, recalls)\n}\n\n/**\n * Compute mAP@50 and per-class precision/recall for a set of predictions vs ground truth.\n *\n * Uses greedy matching (highest-score prediction matched first).\n * Each ground truth can be matched at most once.\n */\nexport function computeAccuracy(\n predictions: readonly SpatialDetection[],\n groundTruth: readonly GroundTruthAnnotation[],\n iouThreshold = 0.5,\n): AccuracyStats {\n if (groundTruth.length === 0) {\n return { mAP50: undefined, precision: undefined, recall: undefined }\n }\n\n // Collect all unique classes from ground truth\n const classes = [...new Set(groundTruth.map((gt) => gt.class))]\n\n const aps: number[] = []\n let totalTp = 0\n let totalFp = 0\n let totalGt = 0\n\n for (const cls of classes) {\n // Sort predictions by score descending\n const classPredictions = predictions\n .filter((p) => p.class === cls)\n .sort((a, b) => b.score - a.score)\n\n const classGt = groundTruth.filter((gt) => gt.class === cls)\n totalGt += classGt.length\n\n const ap = computeClassAP(classPredictions, classGt, iouThreshold)\n aps.push(ap)\n\n // Count TP/FP for global precision/recall\n const matched = new Set<number>()\n for (const pred of classPredictions) {\n let bestIou = -1\n let bestGtIdx = -1\n for (let i = 0; i < classGt.length; i++) {\n if (matched.has(i)) continue\n const gt = classGt[i]\n if (!gt) continue\n const score = iou(pred.bbox, gt.bbox)\n if (score > bestIou) {\n bestIou = score\n bestGtIdx = i\n }\n }\n if (bestIou >= iouThreshold && bestGtIdx >= 0) {\n matched.add(bestGtIdx)\n totalTp++\n } else {\n totalFp++\n }\n }\n }\n\n const mAP50 = aps.length > 0 ? aps.reduce((sum, ap) => sum + ap, 0) / aps.length : undefined\n const precision = totalTp + totalFp > 0 ? totalTp / (totalTp + totalFp) : undefined\n const recall = totalGt > 0 ? totalTp / totalGt : undefined\n\n return { mAP50, precision, recall }\n}\n","import type {\n BenchmarkConfig,\n BenchmarkTarget,\n BenchmarkTargetResult,\n FrameInput,\n GroundTruth,\n DetectorOutput,\n ResourceStats,\n} from '@camstack/types'\nimport { computeLatencyStats, computeFps } from './stats.js'\nimport { computeAccuracy } from './accuracy.js'\n\nexport interface BenchmarkRunnerOptions {\n /** Function to run inference — provided by the addon that's being benchmarked */\n readonly runInference: (\n frame: FrameInput,\n config: Readonly<Record<string, unknown>>,\n ) => Promise<DetectorOutput>\n /** Reference images with ground truth */\n readonly referenceImages: readonly { readonly frame: FrameInput; readonly groundTruth: GroundTruth }[]\n /** Progress callback */\n readonly onProgress?: (completed: number, total: number, currentTarget: string) => void\n}\n\n/** Collect peak memory snapshot */\nfunction measureResources(): ResourceStats {\n const memUsage = process.memoryUsage()\n return {\n peakMemoryMB: Math.round(memUsage.heapUsed / (1024 * 1024)),\n avgCpuPercent: 0, // CPU profiling requires native tooling; best-effort zero\n }\n}\n\nexport class BenchmarkRunner {\n constructor(private readonly options: BenchmarkRunnerOptions) {}\n\n /** Run inference on a single frame, picking a reference image round-robin if needed */\n private async runOnce(\n target: BenchmarkTarget,\n frameIdx = 0,\n ): Promise<DetectorOutput> {\n const images = this.options.referenceImages\n if (images.length === 0) {\n // No reference images — create a minimal synthetic frame\n const syntheticFrame: FrameInput = {\n data: Buffer.alloc(320 * 240 * 3),\n format: 'rgb',\n width: 320,\n height: 240,\n timestamp: Date.now(),\n }\n return this.options.runInference(syntheticFrame, target.config)\n }\n\n const idx = frameIdx % images.length\n const entry = images[idx]\n if (!entry) {\n throw new Error(`Reference image at index ${idx} is undefined`)\n }\n return this.options.runInference(entry.frame, target.config)\n }\n\n /** Measure accuracy across all reference images */\n private async measureAccuracy(target: BenchmarkTarget) {\n const images = this.options.referenceImages\n if (images.length === 0) return undefined\n\n const allPredictions: DetectorOutput['detections'][number][] = []\n const allGroundTruth: GroundTruth['annotations'][number][] = []\n\n for (const entry of images) {\n const output = await this.options.runInference(entry.frame, target.config)\n allPredictions.push(...output.detections)\n allGroundTruth.push(...entry.groundTruth.annotations)\n }\n\n return computeAccuracy(allPredictions, allGroundTruth)\n }\n\n /** Run benchmark for a single target configuration */\n async runTarget(target: BenchmarkTarget, config: BenchmarkConfig): Promise<BenchmarkTargetResult> {\n const warmup = config.warmup ?? 10\n const iterations = config.iterations ?? 100\n const timings: number[] = []\n\n // Warmup loop\n for (let i = 0; i < warmup; i++) {\n await this.runOnce(target, i)\n }\n\n // Measurement loop\n for (let i = 0; i < iterations; i++) {\n const start = performance.now()\n await this.runOnce(target, i)\n timings.push(performance.now() - start)\n this.options.onProgress?.(i + 1, iterations, target.label)\n }\n\n const latency = computeLatencyStats(timings)\n const fps = computeFps(timings)\n const accuracy = await this.measureAccuracy(target)\n const resources = measureResources()\n\n return {\n label: target.label,\n addonId: target.addonId,\n config: target.config,\n latency,\n fps,\n accuracy,\n resources,\n }\n }\n\n /** Run benchmark for all targets defined in the config */\n async runAll(config: BenchmarkConfig): Promise<BenchmarkTargetResult[]> {\n const results: BenchmarkTargetResult[] = []\n for (const target of config.targets) {\n results.push(await this.runTarget(target, config))\n }\n return results\n }\n}\n","import type { SystemInfo } from '@camstack/types'\nimport os from 'node:os'\nimport { execSync } from 'node:child_process'\n\n/**\n * Attempt to detect GPU model from system tools.\n * Returns undefined if detection fails.\n */\nfunction detectGpuModel(): string | undefined {\n // Try nvidia-smi\n try {\n const output = execSync('nvidia-smi --query-gpu=name --format=csv,noheader', {\n timeout: 3000,\n stdio: ['ignore', 'pipe', 'ignore'],\n })\n .toString()\n .trim()\n if (output.length > 0) {\n return output.split('\\n')[0]?.trim()\n }\n } catch {\n // nvidia-smi not available\n }\n\n // Try system_profiler on macOS for Metal GPU\n if (process.platform === 'darwin') {\n try {\n const output = execSync(\n \"system_profiler SPDisplaysDataType 2>/dev/null | grep 'Chipset Model:' | head -1\",\n { timeout: 5000, stdio: ['ignore', 'pipe', 'ignore'] },\n )\n .toString()\n .trim()\n const match = output.match(/Chipset Model:\\s*(.+)/)\n if (match?.[1]) {\n return match[1].trim()\n }\n } catch {\n // system_profiler not available\n }\n }\n\n return undefined\n}\n\n/**\n * Collect system hardware and runtime information.\n */\nexport function collectSystemInfo(): SystemInfo {\n const cpus = os.cpus()\n const firstCpu = cpus[0]\n\n return {\n os: `${os.type()} ${os.release()}`,\n arch: os.arch(),\n cpuModel: firstCpu?.model ?? 'Unknown',\n cpuCores: cpus.length,\n totalMemoryMB: Math.round(os.totalmem() / (1024 * 1024)),\n gpuModel: detectGpuModel(),\n nodeVersion: process.version,\n }\n}\n","import type {\n ICamstackAddon,\n AddonManifest,\n AddonContext,\n AddonPageDeclaration,\n IAddonPageProvider,\n BenchmarkConfig,\n MultiBenchmarkReport,\n BenchmarkTargetResult,\n FrameInput,\n GroundTruth,\n DetectorOutput,\n CapabilityProviderMap,\n} from '@camstack/types'\nimport { BenchmarkRunner } from './runner/benchmark-runner.js'\nimport { collectSystemInfo } from './runner/system-info.js'\n\nexport type BenchmarkInferenceFactory = (\n addonId: string,\n config: Readonly<Record<string, unknown>>,\n) => (frame: FrameInput, cfg: Readonly<Record<string, unknown>>) => Promise<DetectorOutput>\n\nexport interface BenchmarkAddonOptions {\n /** Factory to create an inference function for a given addonId + config */\n readonly inferenceFactory?: BenchmarkInferenceFactory\n /** Reference images with ground truth for accuracy evaluation */\n readonly referenceImages?: ReadonlyArray<{\n readonly frame: FrameInput\n readonly groundTruth: GroundTruth\n }>\n}\n\nexport class BenchmarkAddon implements ICamstackAddon {\n readonly id = 'benchmark'\n\n readonly manifest: AddonManifest = {\n id: 'benchmark',\n name: 'Benchmark',\n version: '0.1.0',\n description:\n 'Detection addon benchmarking with reference images and distributed execution',\n packageName: '@camstack/addon-benchmark',\n }\n\n readonly pages: readonly AddonPageDeclaration[] = [\n {\n id: 'benchmark',\n label: 'Benchmark',\n icon: 'gauge',\n path: '/addon/benchmark',\n bundle: 'benchmark.js',\n element: 'camstack-benchmark',\n },\n ] as const\n\n private context: AddonContext | null = null\n private options: BenchmarkAddonOptions = {}\n\n async initialize(ctx: AddonContext, opts?: BenchmarkAddonOptions): Promise<void> {\n this.context = ctx\n this.options = opts ?? {}\n }\n\n async shutdown(): Promise<void> {\n this.context = null\n }\n\n getCapabilityProvider<K extends keyof CapabilityProviderMap>(\n name: K,\n ): CapabilityProviderMap[K] | null {\n if (name === 'addon-pages') {\n const provider: IAddonPageProvider = {\n id: this.id,\n getPages: () => this.pages,\n }\n return provider as CapabilityProviderMap[K]\n }\n return null\n }\n\n /**\n * Run a benchmark locally and return a MultiBenchmarkReport.\n */\n async run(\n config: BenchmarkConfig,\n onProgress?: (completed: number, total: number, currentTarget: string) => void,\n ): Promise<MultiBenchmarkReport> {\n const systemInfo = collectSystemInfo()\n\n const results = await this.runLocally(config, onProgress)\n\n const leaderboard = results\n .sort((a, b) => a.latency.mean - b.latency.mean)\n .map((r, idx) => ({\n rank: idx + 1,\n agentId: 'local',\n label: r.label,\n meanMs: r.latency.mean,\n fps: r.fps,\n peakMemoryMB: r.resources.peakMemoryMB,\n accuracy: r.accuracy,\n }))\n\n return {\n timestamp: new Date().toISOString(),\n source: config.source,\n agents: [\n {\n agentId: 'local',\n status: 'completed',\n systemInfo,\n results,\n },\n ],\n leaderboard,\n }\n }\n\n /**\n * Run a distributed benchmark across agents.\n *\n * Stub: distributed execution requires a BenchmarkHub instance bound to\n * live WebSocket connections. Call BenchmarkHub.dispatch() directly from\n * the server transport layer. This method runs locally as a fallback.\n */\n async runDistributed(\n config: BenchmarkConfig,\n onProgress?: (completed: number, total: number, currentTarget: string) => void,\n ): Promise<MultiBenchmarkReport> {\n // Fallback to local execution when no distributed transport is configured\n return this.run(config, onProgress)\n }\n\n private async runLocally(\n config: BenchmarkConfig,\n onProgress?: (completed: number, total: number, currentTarget: string) => void,\n ): Promise<BenchmarkTargetResult[]> {\n const { inferenceFactory, referenceImages = [] } = this.options\n\n const firstTarget = config.targets[0]\n if (!firstTarget) {\n throw new Error('BenchmarkConfig must have at least one target')\n }\n\n if (!inferenceFactory) {\n // Return stub results when no inference factory is configured\n return config.targets.map((target) => ({\n label: target.label,\n addonId: target.addonId,\n config: target.config,\n latency: { mean: 0, median: 0, p95: 0, p99: 0, min: 0, max: 0 },\n fps: 0,\n resources: { peakMemoryMB: 0, avgCpuPercent: 0 },\n }))\n }\n\n const runInference = inferenceFactory(firstTarget.addonId, firstTarget.config)\n\n const runner = new BenchmarkRunner({\n runInference,\n referenceImages,\n onProgress,\n })\n\n return runner.runAll(config)\n }\n}\n","import type { SpatialDetection, FrameInput } from '@camstack/types'\nimport sharp from 'sharp'\n\n/** RGBA color for a detection class (cycles through palette) */\nconst COLOR_PALETTE: readonly string[] = [\n '#FF4136',\n '#2ECC40',\n '#0074D9',\n '#FF851B',\n '#B10DC9',\n '#FFDC00',\n '#7FDBFF',\n '#01FF70',\n '#F012BE',\n '#3D9970',\n]\n\nfunction classColor(cls: string): string {\n let hash = 0\n for (let i = 0; i < cls.length; i++) {\n hash = (hash * 31 + (cls.codePointAt(i) ?? 0)) >>> 0\n }\n return COLOR_PALETTE[hash % COLOR_PALETTE.length] ?? '#FF4136'\n}\n\n/** Escape a string for safe embedding in SVG text */\nfunction escSvg(str: string): string {\n return str\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n}\n\n/** Build SVG overlay with bounding boxes and labels */\nfunction buildSvgOverlay(\n detections: readonly SpatialDetection[],\n width: number,\n height: number,\n): string {\n const rects = detections.map((det) => {\n const color = classColor(det.class)\n const label = escSvg(`${det.class} ${(det.score * 100).toFixed(0)}%`)\n const { x, y, w, h } = det.bbox\n const clampX = Math.max(0, Math.min(x, width - 1))\n const clampY = Math.max(0, Math.min(y, height - 1))\n const clampW = Math.max(1, Math.min(w, width - clampX))\n const clampH = Math.max(1, Math.min(h, height - clampY))\n const labelY = clampY > 14 ? clampY - 2 : clampY + clampH + 12\n\n return `\n <rect x=\"${clampX}\" y=\"${clampY}\" width=\"${clampW}\" height=\"${clampH}\"\n stroke=\"${color}\" stroke-width=\"2\" fill=\"none\"/>\n <rect x=\"${clampX}\" y=\"${labelY - 12}\" width=\"${label.length * 7}\" height=\"14\"\n fill=\"${color}\" fill-opacity=\"0.75\"/>\n <text x=\"${clampX + 2}\" y=\"${labelY}\" font-family=\"monospace\" font-size=\"11\"\n fill=\"white\">${label}</text>`\n })\n\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\">${rects.join('')}</svg>`\n}\n\n/** Build a semi-transparent mask overlay for detections that have mask data */\nasync function buildMaskOverlays(\n detections: readonly SpatialDetection[],\n width: number,\n height: number,\n): Promise<Buffer[]> {\n const overlays: Buffer[] = []\n\n for (const det of detections) {\n if (!det.mask || !det.maskWidth || !det.maskHeight) continue\n\n const color = classColor(det.class)\n const r = parseInt(color.slice(1, 3), 16)\n const g = parseInt(color.slice(3, 5), 16)\n const b = parseInt(color.slice(5, 7), 16)\n\n // Build RGBA buffer for the mask at its native resolution\n const rgba = Buffer.alloc(det.maskWidth * det.maskHeight * 4)\n for (let i = 0; i < det.mask.length; i++) {\n const alpha = det.mask[i] ?? 0\n if (alpha > 0) {\n const base = i * 4\n rgba[base] = r\n rgba[base + 1] = g\n rgba[base + 2] = b\n rgba[base + 3] = Math.round(alpha * 0.5) // 50% opacity\n }\n }\n\n // Resize mask to full image dimensions\n const maskBuffer = await sharp(rgba, {\n raw: { width: det.maskWidth, height: det.maskHeight, channels: 4 },\n })\n .resize(width, height)\n .png()\n .toBuffer()\n\n overlays.push(maskBuffer)\n }\n\n return overlays\n}\n\n/**\n * Draw bounding boxes and optional masks on a frame, write result as JPEG.\n *\n * @param frame - Input image frame\n * @param detections - Detections to annotate\n * @param outputPath - Where to save the annotated JPEG\n */\nexport async function annotateImage(\n frame: FrameInput,\n detections: readonly SpatialDetection[],\n outputPath: string,\n): Promise<void> {\n let image: sharp.Sharp\n\n if (frame.format === 'jpeg') {\n image = sharp(frame.data)\n } else {\n // 'rgb' or 'yuv420' — treat as raw RGB\n image = sharp(frame.data, {\n raw: { width: frame.width, height: frame.height, channels: 3 },\n })\n }\n\n // Collect composite layers\n const composites: sharp.OverlayOptions[] = []\n\n // Mask overlays (behind bbox lines)\n const maskBuffers = await buildMaskOverlays(detections, frame.width, frame.height)\n for (const maskBuf of maskBuffers) {\n composites.push({ input: maskBuf, blend: 'over' })\n }\n\n // SVG bbox overlay\n const svgBuf = Buffer.from(buildSvgOverlay(detections, frame.width, frame.height))\n composites.push({ input: svgBuf, blend: 'over' })\n\n await image.composite(composites).jpeg({ quality: 90 }).toFile(outputPath)\n}\n","import type {\n BenchmarkConfig,\n MultiBenchmarkReport,\n BenchmarkTargetResult,\n SystemInfo,\n} from '@camstack/types'\nimport type {\n BenchmarkMessage,\n BenchmarkResultMessage,\n BenchmarkErrorMessage,\n BenchmarkProgressMessage,\n AgentHelloMessage,\n} from './benchmark-protocol.js'\n\nexport type HubSendFn = (agentId: string, message: BenchmarkMessage) => void\n\nexport interface AgentEntry {\n readonly agentId: string\n systemInfo?: SystemInfo\n status: 'idle' | 'running' | 'done' | 'error' | 'disconnected'\n results?: readonly BenchmarkTargetResult[]\n error?: string\n completedIterations?: number\n}\n\n/**\n * BenchmarkHub orchestrates benchmark task distribution to connected agents.\n *\n * Transport (WebSocket) is provided externally via the `send` callback.\n * Call `handleMessage()` for every inbound message from agents.\n */\nexport class BenchmarkHub {\n private readonly agents = new Map<string, AgentEntry>()\n private activeTaskId: string | null = null\n private resolveTask: ((report: MultiBenchmarkReport) => void) | null = null\n private rejectTask: ((err: Error) => void) | null = null\n private pendingConfig: BenchmarkConfig | null = null\n\n constructor(private readonly send: HubSendFn) {}\n\n /** Register a connected agent (typically on WS connect + hello message) */\n registerAgent(agentId: string, systemInfo?: SystemInfo): void {\n this.agents.set(agentId, {\n agentId,\n systemInfo,\n status: 'idle',\n })\n }\n\n /** Mark an agent as disconnected */\n disconnectAgent(agentId: string): void {\n const entry = this.agents.get(agentId)\n if (entry) {\n this.agents.set(agentId, { ...entry, status: 'disconnected' })\n }\n this.checkCompletion()\n }\n\n /** Handle incoming message from any agent */\n handleMessage(message: BenchmarkMessage): void {\n switch (message.type) {\n case 'agent.hello':\n this.onAgentHello(message)\n break\n case 'benchmark.progress':\n this.onProgress(message)\n break\n case 'benchmark.result':\n this.onResult(message)\n break\n case 'benchmark.error':\n this.onError(message)\n break\n default:\n // Hub ignores start/cancel/ack — those are hub-originating messages\n break\n }\n }\n\n /**\n * Dispatch a benchmark to a subset of agents.\n * Returns a promise that resolves when all targeted agents have finished.\n *\n * @param config - Benchmark configuration\n * @param agentIds - If empty, dispatches to all connected/idle agents\n * @param referenceImages - Reference image buffers to send to agents\n */\n async dispatch(\n config: BenchmarkConfig,\n agentIds: readonly string[],\n referenceImages: ReadonlyArray<{\n readonly name: string\n readonly data: Buffer\n readonly width: number\n readonly height: number\n }> = [],\n ): Promise<MultiBenchmarkReport> {\n const taskId = `task-${Date.now()}-${Math.random().toString(36).slice(2)}`\n this.activeTaskId = taskId\n this.pendingConfig = config\n\n const targets =\n agentIds.length > 0\n ? agentIds\n : [...this.agents.values()]\n .filter((a) => a.status === 'idle')\n .map((a) => a.agentId)\n\n if (targets.length === 0) {\n throw new Error('No idle agents available for benchmark dispatch')\n }\n\n // Reset agent states\n for (const agentId of targets) {\n const entry = this.agents.get(agentId)\n if (entry) {\n this.agents.set(agentId, { ...entry, status: 'running', results: undefined, error: undefined })\n }\n }\n\n // Send start message to each target\n for (const agentId of targets) {\n this.send(agentId, {\n type: 'benchmark.start',\n taskId,\n config,\n referenceImages,\n })\n }\n\n return new Promise<MultiBenchmarkReport>((resolve, reject) => {\n this.resolveTask = resolve\n this.rejectTask = reject\n })\n }\n\n private onAgentHello(message: AgentHelloMessage): void {\n this.registerAgent(message.agentId, message.systemInfo)\n }\n\n private onProgress(message: BenchmarkProgressMessage): void {\n const entry = this.agents.get(message.agentId)\n if (entry) {\n this.agents.set(message.agentId, {\n ...entry,\n completedIterations: message.completed,\n })\n }\n }\n\n private onResult(message: BenchmarkResultMessage): void {\n const entry = this.agents.get(message.agentId)\n if (entry) {\n this.agents.set(message.agentId, {\n ...entry,\n status: 'done',\n systemInfo: message.systemInfo,\n results: message.results,\n })\n }\n this.checkCompletion()\n }\n\n private onError(message: BenchmarkErrorMessage): void {\n const entry = this.agents.get(message.agentId)\n if (entry) {\n this.agents.set(message.agentId, {\n ...entry,\n status: 'error',\n error: message.error,\n })\n }\n this.checkCompletion()\n }\n\n private checkCompletion(): void {\n if (!this.resolveTask || !this.activeTaskId) return\n\n const runningAgents = [...this.agents.values()].filter(\n (a) => a.status === 'running',\n )\n if (runningAgents.length > 0) return\n\n const report = this.buildReport()\n this.resolveTask(report)\n this.resolveTask = null\n this.rejectTask = null\n this.activeTaskId = null\n }\n\n private buildReport(): MultiBenchmarkReport {\n const source = this.pendingConfig?.source ?? { type: 'reference', images: 'all' as const }\n const agentEntries = [...this.agents.values()]\n\n // Build leaderboard from all successful results\n const allResults: Array<{\n agentId: string\n result: BenchmarkTargetResult\n }> = []\n\n for (const agent of agentEntries) {\n if (agent.results) {\n for (const result of agent.results) {\n allResults.push({ agentId: agent.agentId, result })\n }\n }\n }\n\n const leaderboard = allResults\n .sort((a, b) => a.result.latency.mean - b.result.latency.mean)\n .map((entry, idx) => ({\n rank: idx + 1,\n agentId: entry.agentId,\n label: entry.result.label,\n meanMs: entry.result.latency.mean,\n fps: entry.result.fps,\n peakMemoryMB: entry.result.resources.peakMemoryMB,\n accuracy: entry.result.accuracy,\n }))\n\n return {\n timestamp: new Date().toISOString(),\n source,\n agents: agentEntries.map((a) => ({\n agentId: a.agentId,\n status:\n a.status === 'done'\n ? 'completed'\n : a.status === 'error'\n ? 'failed'\n : a.status === 'disconnected'\n ? 'disconnected'\n : 'partial',\n systemInfo: a.systemInfo ?? {\n os: 'unknown',\n arch: 'unknown',\n cpuModel: 'unknown',\n cpuCores: 0,\n totalMemoryMB: 0,\n nodeVersion: 'unknown',\n },\n results: a.results ?? [],\n error: a.error,\n completedIterations: a.completedIterations,\n })),\n leaderboard,\n }\n }\n}\n","import type {\n DetectorOutput,\n FrameInput,\n SystemInfo,\n} from '@camstack/types'\nimport type {\n BenchmarkMessage,\n BenchmarkStartMessage,\n BenchmarkCancelMessage,\n} from './benchmark-protocol.js'\nimport { BenchmarkRunner } from '../runner/benchmark-runner.js'\nimport { collectSystemInfo } from '../runner/system-info.js'\n\nexport type AgentSendFn = (message: BenchmarkMessage) => void\n\nexport type InferenceFactory = (\n addonId: string,\n config: Readonly<Record<string, unknown>>,\n) => (frame: FrameInput, cfg: Readonly<Record<string, unknown>>) => Promise<DetectorOutput>\n\n/**\n * BenchmarkAgent executes benchmark tasks dispatched by the hub.\n *\n * Transport (WebSocket) is provided externally via the `send` callback.\n * Call `handleMessage()` for every inbound message from the hub.\n */\nexport class BenchmarkAgent {\n private readonly agentId: string\n private readonly systemInfo: SystemInfo\n private cancelRequested = false\n\n constructor(\n agentId: string,\n private readonly send: AgentSendFn,\n private readonly inferenceFactory: InferenceFactory,\n ) {\n this.agentId = agentId\n this.systemInfo = collectSystemInfo()\n }\n\n /** Send hello to the hub — call this on WS connect */\n hello(): void {\n this.send({\n type: 'agent.hello',\n agentId: this.agentId,\n systemInfo: this.systemInfo,\n })\n }\n\n /** Handle incoming message from the hub */\n handleMessage(message: BenchmarkMessage): void {\n switch (message.type) {\n case 'benchmark.start':\n void this.onStart(message)\n break\n case 'benchmark.cancel':\n this.onCancel(message)\n break\n default:\n // Agent ignores result/progress/hello messages — those are agent-originating\n break\n }\n }\n\n private async onStart(message: BenchmarkStartMessage): Promise<void> {\n this.cancelRequested = false\n const { taskId, config } = message\n\n try {\n // Reconstruct FrameInput objects from the transferred image buffers\n const referenceImages = message.referenceImages.map((img) => ({\n frame: {\n data: img.data,\n format: 'jpeg' as const,\n width: img.width,\n height: img.height,\n timestamp: Date.now(),\n } satisfies FrameInput,\n groundTruth: { image: img.name, annotations: [] },\n }))\n\n // Use the first target's addonId and config for all iterations\n // (targets are looped inside the runner)\n const firstTarget = config.targets[0]\n if (!firstTarget) {\n throw new Error('No benchmark targets specified')\n }\n\n const runInference = this.inferenceFactory(firstTarget.addonId, firstTarget.config)\n\n const runner = new BenchmarkRunner({\n runInference,\n referenceImages,\n onProgress: (completed, total, currentTarget) => {\n if (this.cancelRequested) return\n this.send({\n type: 'benchmark.progress',\n taskId,\n agentId: this.agentId,\n completed,\n total,\n currentTarget,\n })\n },\n })\n\n const results = await runner.runAll(config)\n\n if (!this.cancelRequested) {\n this.send({\n type: 'benchmark.result',\n taskId,\n agentId: this.agentId,\n systemInfo: this.systemInfo,\n results,\n })\n }\n } catch (err) {\n this.send({\n type: 'benchmark.error',\n taskId,\n agentId: this.agentId,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n private onCancel(message: BenchmarkCancelMessage): void {\n if (message.taskId === this.activeTaskId) {\n this.cancelRequested = true\n }\n }\n\n /** Returns the current task ID (last started), or null if idle */\n private get activeTaskId(): string | null {\n return null // Stub: real implementation tracks task lifecycle\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/benchmark-addon.ts"],"sourcesContent":["import type {\n ICamstackAddon,\n AddonManifest,\n AddonContext,\n AddonPageDeclaration,\n IAddonPageProvider,\n CapabilityProviderMap,\n} from '@camstack/types'\n\n/**\n * Benchmark addon — provides the Benchmark page in the admin UI.\n *\n * All benchmark logic (inference, pipeline execution, model download)\n * lives in InferenceCapabilitiesService + PipelineExecutor on the server.\n * This addon only registers the page.\n */\nexport class BenchmarkAddon implements ICamstackAddon {\n readonly id = 'benchmark'\n\n readonly manifest: AddonManifest = {\n id: 'benchmark',\n name: 'Benchmark',\n version: '0.1.0',\n packageName: '@camstack/addon-benchmark',\n description: 'Detection benchmark, image tester, and pipeline runner',\n }\n\n readonly pages: readonly AddonPageDeclaration[] = [\n {\n id: 'benchmark',\n label: 'Benchmark',\n icon: 'gauge',\n path: '/addon/benchmark',\n bundle: 'page.mjs',\n },\n ] as const\n\n async initialize(_ctx: AddonContext): Promise<void> {}\n async shutdown(): Promise<void> {}\n\n getCapabilityProvider<K extends keyof CapabilityProviderMap>(\n name: K,\n ): CapabilityProviderMap[K] | null {\n if (name === 'addon-pages') {\n const provider: IAddonPageProvider = {\n id: this.id,\n getPages: () => this.pages,\n }\n return provider as CapabilityProviderMap[K]\n }\n return null\n }\n}\n"],"mappings":";AAgBO,IAAM,iBAAN,MAA+C;AAAA,EAC3C,KAAK;AAAA,EAEL,WAA0B;AAAA,IACjC,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aAAa;AAAA,IACb,aAAa;AAAA,EACf;AAAA,EAES,QAAyC;AAAA,IAChD;AAAA,MACE,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,MAAM;AAAA,MACN,MAAM;AAAA,MACN,QAAQ;AAAA,IACV;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,MAAmC;AAAA,EAAC;AAAA,EACrD,MAAM,WAA0B;AAAA,EAAC;AAAA,EAEjC,sBACE,MACiC;AACjC,QAAI,SAAS,eAAe;AAC1B,YAAM,WAA+B;AAAA,QACnC,IAAI,KAAK;AAAA,QACT,UAAU,MAAM,KAAK;AAAA,MACvB;AACA,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AACF;","names":[]}
|