Skip to content

Add cuVS performance dashboard docs#2126

Open
ManasSingh12345 wants to merge 2 commits into
rapidsai:release/26.06from
ManasSingh12345:docs/performance-dashboard
Open

Add cuVS performance dashboard docs#2126
ManasSingh12345 wants to merge 2 commits into
rapidsai:release/26.06from
ManasSingh12345:docs/performance-dashboard

Conversation

@ManasSingh12345
Copy link
Copy Markdown

@ManasSingh12345 ManasSingh12345 commented May 26, 2026

Summary

  • Add a new Getting Started > Performance page with an interactive cuVS-Bench dashboard for cuVS 26.04 benchmark results.
  • Export the tab-delimited benchmark CSV into static JSON and generated TypeScript data during Fern docs builds.
  • Add a native Fern React dashboard with multi-select filters, recall-bucket bar charts for build time/QPS/latency, and a filtered results table.

How to test

From a fresh checkout of this branch:

git fetch origin docs/performance-dashboard
git checkout docs/performance-dashboard
node --version  # should be 22+
fern/build_docs.sh check

To preview the page locally:

fern/build_docs.sh dev --port 3000 --backend-port 3001

Then open:

http://localhost:3000/cuvs/getting-started/performance

Verify that:

  • The page renders without the Fern "Something went wrong!" badge.
  • The filter controls appear for algorithm, GPU/CPU SKU, batch size, TopK, vector count, dimensions, dtype, and mode.
  • The build time, QPS, and latency charts render and respond to filter/sort changes.
  • The filtered results table updates with the selected filters.

Local validation performed

  • fern/build_docs.sh check
  • Verified the local dev page renders at /cuvs/getting-started/performance without the Fern error badge.
  • Confirmed the page shows dashboard filters, chart sections, and the filtered benchmark rows table.

@copy-pr-bot
Copy link
Copy Markdown

copy-pr-bot Bot commented May 26, 2026

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@aamijar aamijar added non-breaking Introduces a non-breaking change doc Improvements or additions to documentation labels May 26, 2026
@aamijar aamijar moved this to In Progress in Unstructured Data Processing May 26, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 26, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b50d757f-e228-4d90-86a8-e095caa7d3d2

📥 Commits

Reviewing files that changed from the base of the PR and between 1ed98f7 and 43ece85.

📒 Files selected for processing (2)
  • fern/pages/performance.md
  • fern/theme/nvidia/components/PerformanceDashboard.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • fern/pages/performance.md
  • fern/theme/nvidia/components/PerformanceDashboard.tsx

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added an interactive Performance dashboard page to docs showing cuVS vector-search benchmark results with charts and a filterable results table.
    • Dashboard supports multi-select filters (algorithm, hardware, batch size, TopK, dimensions, dtype, mode) and sortable chart/table views.
  • Documentation

    • Added a Performance page with context about the benchmark data and reproduction guidance.
  • Style

    • New dashboard styling for filters, charts, legends, and tables.

Walkthrough

Adds a performance dashboard to the docs: benchmark data export and JSON/TS assets, filtering and chart-data logic, a React dashboard with Chart.js charts and table, CSS styling, and docs integration with build automation and a performance docs page.

Changes

Performance Dashboard

Layer / File(s) Summary
Benchmark Data Shape & Export
fern/theme/nvidia/components/benchmarkData.ts, fern/assets/data/benchmark_results.json, fern/scripts/export_performance_dashboard_data.py
BenchmarkRow type and BENCHMARK_ROWS constant export benchmark records with metrics (throughput, latency, recall) across SKUs, algorithms, and recall ranges. Python export script generates both JSON and TypeScript outputs from CSV input.
Dashboard Filtering & Data Transformation Logic
fern/theme/nvidia/components/performanceDashboardLogic.ts
Exports filter pipeline (building options, defaults, applying selections), chart dataset construction with recall-bucket aggregation and per-bucket ranking, label/formatting utilities, filter description generation, and table sorting logic.
Dashboard UI Components
fern/theme/nvidia/components/PerformanceDashboard.tsx
Main PerformanceDashboard component with MultiSelectFilter dropdowns, ChartPanel instances rendering Chart.js bar charts with sort toggles, SeriesLegend descriptions, and ResultsTable with type-aware cell formatting (hardware styling, percentage/thousands formatting, rounding).
Dashboard Styling
fern/styles/performance-dashboard.css
CSS for dashboard container, filter dropdown panel with checkboxes and actions, chart card layout with legends, GPU/CPU hardware dots, table with sticky headers and scrollable region, and responsive multi-column wrapping.
Documentation Integration
fern/build_docs.sh, fern/docs.yml, fern/pages/performance.md
Build script adds export_performance_dashboard_data function and calls it in check/preview/publish/dev modes. Docs config adds performance stylesheet and navigation entry. New performance page imports and renders PerformanceDashboard with cuVS-Bench context.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add cuVS performance dashboard docs' directly and clearly summarizes the main change: adding a new performance dashboard documentation page with interactive features.
Description check ✅ Passed The description is well-related to the changeset, providing a clear summary of additions (Performance page, benchmark data export, React dashboard), testing instructions, and validation performed.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@fern/styles/performance-dashboard.css`:
- Around line 1-9: The stylelint error is caused by missing an empty line
between the custom property declarations and the normal declarations in the
.performance-dashboard rule; update the .performance-dashboard block (the lines
defining --pd-nv-green, --pd-intel-blue, --pd-border, --pd-muted) to add a
single blank line before the first regular declaration (margin) so the custom
property section is separated from the rest to satisfy
declaration-empty-line-before.

In `@fern/theme/nvidia/components/PerformanceDashboard.tsx`:
- Around line 90-112: chartLoaderPromise is permanently set to a rejected
promise on script load failure, preventing retries; modify the error handlers
for both script.onerror and plugin.onerror inside the chartLoaderPromise
initializer to clear/reset chartLoaderPromise (e.g., set chartLoaderPromise =
undefined or null) before calling reject(new Error(...)), so subsequent attempts
can recreate the loader and retry loading CHART_JS_URL and CHART_DATALABELS_URL;
update both error branches associated with script and plugin (the script element
named script and the plugin element named plugin that handle window.Chart and
window.ChartDataLabels registration) to perform this reset.
- Around line 35-38: The component currently injects Chart.js and
chartjs-plugin-datalabels at runtime using CHART_JS_URL and CHART_DATALABELS_URL
and caches the result in chartLoaderPromise, which can be permanently rejected
and also breaks CSP/offline environments; replace runtime CDN loading by
bundling/importing Chart.js and the datalabels plugin via package dependencies
(or serve local static assets) and import/register them in the module (remove
script injection logic such as the chartLoaderPromise loader function), or if
you must keep remote loading, add SRI integrity and crossOrigin attributes and
modify the loader (chartLoaderPromise and its loader function) to reset/recreate
the promise on error so retries are possible and surface errors to the UI;
update registration code that currently expects global Chart to instead use the
imported Chart and plugin symbols.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b3e88a24-9793-4583-bcba-0007fcb315bf

📥 Commits

Reviewing files that changed from the base of the PR and between e1db65c and 1ed98f7.

⛔ Files ignored due to path filters (1)
  • data/benchmarks/results_cuvs_26_04.csv is excluded by !**/*.csv
📒 Files selected for processing (9)
  • fern/assets/data/benchmark_results.json
  • fern/build_docs.sh
  • fern/docs.yml
  • fern/pages/performance.md
  • fern/scripts/export_performance_dashboard_data.py
  • fern/styles/performance-dashboard.css
  • fern/theme/nvidia/components/PerformanceDashboard.tsx
  • fern/theme/nvidia/components/benchmarkData.ts
  • fern/theme/nvidia/components/performanceDashboardLogic.ts

Comment on lines +1 to +9
.performance-dashboard {
--pd-nv-green: #76b900;
--pd-intel-blue: #0071c5;
--pd-border: #e0e0e0;
--pd-muted: #666;
margin: 0 0 24px;
font-size: 13px;
color: #222;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix stylelint declaration-empty-line-before at Line 6.

Insert an empty line between the custom property block and regular declarations to satisfy the configured stylelint rule.

Suggested fix
 .performance-dashboard {
   --pd-nv-green: `#76b900`;
   --pd-intel-blue: `#0071c5`;
   --pd-border: `#e0e0e0`;
   --pd-muted: `#666`;
+
   margin: 0 0 24px;
   font-size: 13px;
   color: `#222`;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.performance-dashboard {
--pd-nv-green: #76b900;
--pd-intel-blue: #0071c5;
--pd-border: #e0e0e0;
--pd-muted: #666;
margin: 0 0 24px;
font-size: 13px;
color: #222;
}
.performance-dashboard {
--pd-nv-green: `#76b900`;
--pd-intel-blue: `#0071c5`;
--pd-border: `#e0e0e0`;
--pd-muted: `#666`;
margin: 0 0 24px;
font-size: 13px;
color: `#222`;
}
🧰 Tools
🪛 Stylelint (17.12.0)

[error] 6-6: Expected empty line before declaration (declaration-empty-line-before)

(declaration-empty-line-before)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@fern/styles/performance-dashboard.css` around lines 1 - 9, The stylelint
error is caused by missing an empty line between the custom property
declarations and the normal declarations in the .performance-dashboard rule;
update the .performance-dashboard block (the lines defining --pd-nv-green,
--pd-intel-blue, --pd-border, --pd-muted) to add a single blank line before the
first regular declaration (margin) so the custom property section is separated
from the rest to satisfy declaration-empty-line-before.

Comment on lines +35 to +38
const CHART_JS_URL =
"https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js";
const CHART_DATALABELS_URL =
"https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0/dist/chartjs-plugin-datalabels.min.js";
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="fern/theme/nvidia/components/PerformanceDashboard.tsx"

# Show relevant portions around the referenced line ranges
nl -ba "$FILE" | sed -n '1,220p'

# Search for script injection / dynamic loading / caching / retry logic within the file
rg -n "CHART_JS_URL|CHART_DATALABELS_URL|script|appendChild|createElement|integrity|crossorigin|retry|Promise|loader|loadFailures|catch|then|onload" "$FILE" || true

# If there are other occurrences of these URLs elsewhere, list them
rg -n "cdn\.jsdelivr\.net/npm/chart\.js|chartjs-plugin-datalabels" -S . || true

Repository: rapidsai/cuvs

Length of output: 100


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="fern/theme/nvidia/components/PerformanceDashboard.tsx"
if [ ! -f "$FILE" ]; then
  echo "Missing file: $FILE" >&2
  exit 1
fi

# Print file with line numbers using awk (no nl dependency)
awk '{printf "%6d\t%s\n", NR, $0}' "$FILE" | sed -n '1,240p'

# Focused searches for CDN/runtime loader/caching/retry/integrity behavior
rg -n "CHART_JS_URL|CHART_DATALABELS_URL|jsdelivr|chart\.umd\.min|datalabels\.min|chartjs-plugin-datalabels|script|appendChild|createElement|integrity|crossorigin|retry|Promise|loader|load failures|catch|throw|onload|onerror" "$FILE" || true

# Check for any other jsdelivr/chart references across repo
rg -n "cdn\.jsdelivr\.net/npm/chart\.js|chartjs-plugin-datalabels" -S . || true

Repository: rapidsai/cuvs

Length of output: 9850


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="fern/theme/nvidia/components/PerformanceDashboard.tsx"

# Print a bit around where loadChartJs() is used (based on earlier rg hit at line ~417)
awk '{printf "%6d\t%s\n", NR, $0}' "$FILE" | sed -n '360,470p'

# Find all call sites of loadChartJs
rg -n "loadChartJs\\(" "$FILE" || true

# Show the exact block around the matching call(s)
# (use awk to print some window around each line number)
python3 - <<'PY'
import re, subprocess, os, sys
file_path="fern/theme/nvidia/components/PerformanceDashboard.tsx"
out=subprocess.check_output(["rg","-n","loadChartJs\\(","-S",file_path], text=True).strip().splitlines()
if not out or out==['']:
    print("No matches")
    sys.exit(0)
lines=[]
for line in out:
    m=re.match(r":(\d+):", line)
    if m:
        lines.append(int(m.group(1)))
for ln in sorted(set(lines)):
    start=max(1, ln-40)
    end=ln+80
    # print with awk
    cmd=f"awk '{{printf \"%6d\\t%s\\n\", NR, $0}}' {shlex_quote(file_path)} | sed -n '{start},{end}p'"
PY

Repository: rapidsai/cuvs

Length of output: 4348


🏁 Script executed:

#!/bin/bash
set -euo pipefail
FILE="fern/theme/nvidia/components/PerformanceDashboard.tsx"

# Show the ChartPanel and anything using chartsReady/chart instance creation
awk '{printf "%6d\t%s\n", NR, $0}' "$FILE" | sed -n '220,560p'

# Search for chartsReady usage and for chartLoaderPromise mutations
rg -n "chartsReady" "$FILE" || true
rg -n "chartLoaderPromise" "$FILE" || true

# Look for any retry/reset logic on failure
rg -n "setChartsReady\\(|setError\\(|retry|reset.*chart|chartLoaderPromise\\s*=\\s*null" "$FILE" || true

Repository: rapidsai/cuvs

Length of output: 10162


🏁 Script executed:

#!/bin/bash
set -euo pipefail
FILE="fern/theme/nvidia/components/PerformanceDashboard.tsx"

rg -n "integrity|crossorigin|crossOrigin" "$FILE" || true
rg -n "chartLoaderPromise\\s*=\\s*null|chartLoaderPromise\\s*=" "$FILE"

Repository: rapidsai/cuvs

Length of output: 118


Avoid runtime jsDelivr CDN loading for Chart.js + datalabels

PerformanceDashboard.tsx loads chart.js and chartjs-plugin-datalabels at runtime from https://cdn.jsdelivr.net/... via injected <script> tags (no integrity/crossOrigin), which can fail under strict CSP/offline/internal-docs environments and provides no integrity pinning (lines ~35-38, ~85-115).
The loader uses a module-level cached chartLoaderPromise; if either script load fails, the rejected promise is never reset, leaving the dashboard stuck in an error state with no retry (lines ~83-115, call site ~413-418).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@fern/theme/nvidia/components/PerformanceDashboard.tsx` around lines 35 - 38,
The component currently injects Chart.js and chartjs-plugin-datalabels at
runtime using CHART_JS_URL and CHART_DATALABELS_URL and caches the result in
chartLoaderPromise, which can be permanently rejected and also breaks
CSP/offline environments; replace runtime CDN loading by bundling/importing
Chart.js and the datalabels plugin via package dependencies (or serve local
static assets) and import/register them in the module (remove script injection
logic such as the chartLoaderPromise loader function), or if you must keep
remote loading, add SRI integrity and crossOrigin attributes and modify the
loader (chartLoaderPromise and its loader function) to reset/recreate the
promise on error so retries are possible and surface errors to the UI; update
registration code that currently expects global Chart to instead use the
imported Chart and plugin symbols.

Comment on lines +90 to +112
chartLoaderPromise = new Promise((resolve, reject) => {
const script = document.createElement("script");
script.src = CHART_JS_URL;
script.async = true;
script.onload = () => {
const plugin = document.createElement("script");
plugin.src = CHART_DATALABELS_URL;
plugin.async = true;
plugin.onload = () => {
if (window.Chart && window.ChartDataLabels) {
const pluginModule =
(window.ChartDataLabels as { default?: unknown }).default ??
window.ChartDataLabels;
window.Chart.register(pluginModule);
}
resolve();
};
plugin.onerror = () => reject(new Error("Failed to load Chart.js datalabels plugin"));
document.head.appendChild(plugin);
};
script.onerror = () => reject(new Error("Failed to load Chart.js"));
document.head.appendChild(script);
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reset chartLoaderPromise when script loading fails.

A transient load error permanently poisons the cached promise, so subsequent retries in the same session will always fail. Clear the cache in the error path so retry is possible.

Suggested fix
   chartLoaderPromise = new Promise((resolve, reject) => {
+    const fail = (message: string) => {
+      chartLoaderPromise = null;
+      reject(new Error(message));
+    };
+
     const script = document.createElement("script");
     script.src = CHART_JS_URL;
     script.async = true;
     script.onload = () => {
       const plugin = document.createElement("script");
       plugin.src = CHART_DATALABELS_URL;
       plugin.async = true;
@@
         }
         resolve();
       };
-      plugin.onerror = () => reject(new Error("Failed to load Chart.js datalabels plugin"));
+      plugin.onerror = () => fail("Failed to load Chart.js datalabels plugin");
       document.head.appendChild(plugin);
     };
-    script.onerror = () => reject(new Error("Failed to load Chart.js"));
+    script.onerror = () => fail("Failed to load Chart.js");
     document.head.appendChild(script);
   });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
chartLoaderPromise = new Promise((resolve, reject) => {
const script = document.createElement("script");
script.src = CHART_JS_URL;
script.async = true;
script.onload = () => {
const plugin = document.createElement("script");
plugin.src = CHART_DATALABELS_URL;
plugin.async = true;
plugin.onload = () => {
if (window.Chart && window.ChartDataLabels) {
const pluginModule =
(window.ChartDataLabels as { default?: unknown }).default ??
window.ChartDataLabels;
window.Chart.register(pluginModule);
}
resolve();
};
plugin.onerror = () => reject(new Error("Failed to load Chart.js datalabels plugin"));
document.head.appendChild(plugin);
};
script.onerror = () => reject(new Error("Failed to load Chart.js"));
document.head.appendChild(script);
});
chartLoaderPromise = new Promise((resolve, reject) => {
const fail = (message: string) => {
chartLoaderPromise = null;
reject(new Error(message));
};
const script = document.createElement("script");
script.src = CHART_JS_URL;
script.async = true;
script.onload = () => {
const plugin = document.createElement("script");
plugin.src = CHART_DATALABELS_URL;
plugin.async = true;
plugin.onload = () => {
if (window.Chart && window.ChartDataLabels) {
const pluginModule =
(window.ChartDataLabels as { default?: unknown }).default ??
window.ChartDataLabels;
window.Chart.register(pluginModule);
}
resolve();
};
plugin.onerror = () => fail("Failed to load Chart.js datalabels plugin");
document.head.appendChild(plugin);
};
script.onerror = () => fail("Failed to load Chart.js");
document.head.appendChild(script);
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@fern/theme/nvidia/components/PerformanceDashboard.tsx` around lines 90 - 112,
chartLoaderPromise is permanently set to a rejected promise on script load
failure, preventing retries; modify the error handlers for both script.onerror
and plugin.onerror inside the chartLoaderPromise initializer to clear/reset
chartLoaderPromise (e.g., set chartLoaderPromise = undefined or null) before
calling reject(new Error(...)), so subsequent attempts can recreate the loader
and retry loading CHART_JS_URL and CHART_DATALABELS_URL; update both error
branches associated with script and plugin (the script element named script and
the plugin element named plugin that handle window.Chart and
window.ChartDataLabels registration) to perform this reset.

@aamijar
Copy link
Copy Markdown
Member

aamijar commented May 26, 2026

/ok to test 1ed98f7

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

doc Improvements or additions to documentation non-breaking Introduces a non-breaking change

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

2 participants