Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 48 additions & 1 deletion packages/app/cypress/e2e/agentic-point-time-series.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,54 @@ const timelineRequest = (
...overrides,
});

const benchmarkSiblings = {
sku: {
hardware: 'b300',
framework: 'vllm',
model: 'kimik3',
precision: 'fp4',
spec_method: 'mtp',
benchmark_type: 'agentic_traces',
github_run_id: 31893747354,
date: '2026-08-15',
dataset_slug: null,
},
siblings: [
{
id: 206885,
conc: 8,
offload_mode: 'off',
decode_tp: 8,
decode_ep: 1,
decode_pp: 1,
decode_dcp_size: 8,
decode_pcp_size: 1,
decode_dp_attention: false,
decode_num_workers: 0,
prefill_tp: 8,
prefill_ep: 1,
prefill_pp: 1,
prefill_dcp_size: 8,
prefill_pcp_size: 1,
prefill_dp_attention: false,
prefill_num_workers: 0,
num_prefill_gpu: 8,
num_decode_gpu: 8,
disagg: false,
is_multinode: false,
tput_per_gpu: 1.2,
total_requests: 395,
is_current: true,
has_trace: true,
},
],
};

describe('Agentic point request metric time series', () => {
before(() => {
cy.intercept('GET', '/api/v1/trace-histograms*', { body: {} });
cy.intercept('GET', '/api/v1/trace-server-metrics*', { body: null });
cy.intercept('GET', '/api/v1/benchmark-siblings*', { statusCode: 404 });
cy.intercept('GET', '/api/v1/benchmark-siblings*', { body: benchmarkSiblings });
cy.intercept('GET', '/api/v1/request-timeline*', {
body: {
version: 3,
Expand Down Expand Up @@ -68,6 +111,10 @@ describe('Agentic point request metric time series', () => {
cy.visit('/inference/agentic/206885', { onBeforeLoad: unlockAgenticGate });
});

it('uses the shared topology label for the active agentic point', () => {
cy.contains('button', 'TP8/DCP8 • c=8').should('be.visible');
});

it('renders rolling P90 interactivity and TTFT by default using profiling requests only', () => {
cy.get('[data-testid="interactivity-over-time-chart"]').within(() => {
cy.contains('h2', 'Interactivity over time').should('be.visible');
Expand Down
14 changes: 14 additions & 0 deletions packages/app/cypress/e2e/unofficial-watermark.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,19 @@ describe('Unofficial-run watermark', () => {
benchmarks: benchmarks.map((row: Record<string, unknown>) => ({
...row,
is_multinode: true,
prefill_tp: 8,
prefill_ep: 1,
decode_tp: 8,
decode_ep: 1,
metrics: {
...(row.metrics as Record<string, unknown> | undefined),
kv_offloading: 'dram',
kv_offload_backend: 'hicache',
kv_p2p_transfer: 'nixl',
router_name: 'sglang-router',
router_version: '0.3.2',
dcp_size: 8,
pcp_size: 4,
server_gpu_cache_hit_rate: 0.875,
},
run_url: runUrl,
Expand Down Expand Up @@ -79,9 +85,17 @@ describe('Unofficial-run watermark', () => {
expect(tooltip).to.contain.text('KV Offload Engine: HiCache');
expect(tooltip).to.contain.text('KV Transfer Engine: NIXL');
expect(tooltip).to.contain.text('Router: SGLang Router 0.3.2');
expect(tooltip).to.contain.text('Decode Context Parallelism (DCP): 8');
expect(tooltip).to.contain.text('Prefill Context Parallelism (PCP): 4');
expect(tooltip).to.contain.text('Chip Cache Hit Rate: 87.5%');
});

cy.get('#scatter-parallelism-labels').click();
cy.get('[data-testid="scatter-graph"] .unofficial-overlay-pt')
.first()
.find('.overlay-label')
.should('contain.text', 'TP8/DCP8/PCP4');

cy.get('[data-testid="scatter-graph"]').first().scrollIntoView();
cy.screenshot('unofficial-watermark', { capture: 'viewport' });

Expand Down
6 changes: 3 additions & 3 deletions packages/app/src/app/api/v1/benchmark-siblings/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ export const dynamic = 'force-dynamic';

const getCachedSiblings = cachedQuery(
(id: number): Promise<BenchmarkSiblings | null> => getBenchmarkSiblings(getDb(), id),
// v2 adds PP and makes the aggregate topology explicit. Roll the blob
// namespace so old TP0 sibling payloads cannot survive the schema change.
'benchmark-siblings-v2',
// v3 adds DCP/PCP. Roll the blob namespace so cached sibling payloads gain
// the complete parallelism mapping used by chart point labels.
'benchmark-siblings-v3',
);

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@ function sibling(overrides: Partial<BenchmarkSibling> = {}): BenchmarkSibling {
decode_tp: 0,
decode_ep: 0,
decode_pp: 1,
decode_dcp_size: null,
decode_pcp_size: null,
decode_dp_attention: false,
decode_num_workers: 0,
prefill_tp: 8,
prefill_ep: 1,
prefill_pp: 2,
prefill_dcp_size: null,
prefill_pcp_size: null,
prefill_dp_attention: false,
prefill_num_workers: 1,
num_prefill_gpu: 16,
Expand All @@ -40,6 +44,19 @@ describe('chipLabel', () => {
expect(chipLabel(sibling({ decode_tp: 8, decode_ep: 1 }))).toBe('TP8PP2 • c=2');
});

it('uses the shared point-label format for aggregate DCP and PCP', () => {
expect(
chipLabel(
sibling({
prefill_dcp_size: 8,
decode_dcp_size: 8,
prefill_pcp_size: 1,
decode_pcp_size: 1,
}),
),
).toBe('TP8PP2/DCP8 • c=2');
});

it('keeps prefill and decode roles separate only for disaggregated serving', () => {
expect(
chipLabel(
Expand All @@ -48,9 +65,13 @@ describe('chipLabel', () => {
decode_tp: 8,
decode_ep: 1,
decode_pp: 1,
prefill_dcp_size: 2,
prefill_pcp_size: 4,
decode_dcp_size: 8,
decode_pcp_size: 1,
decode_num_workers: 1,
}),
),
).toBe('1xTP8PP2+1xTP8 • c=2');
).toBe('1xTP8PP2/DCP2/PCP4+1xTP8/DCP8 • c=2');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import { usePathname, useRouter } from 'next/navigation';
import { ChevronLeft, ChevronRight } from 'lucide-react';

import type { BenchmarkSibling, BenchmarkSku } from '@/hooks/api/use-benchmark-siblings';
import { parallelismLabel } from '@/components/inference/utils/parallelism-label';
import {
meaningfulParallelismSize,
parallelismLabel,
} from '@/components/inference/utils/parallelism-label';
import {
Select,
SelectContent,
Expand Down Expand Up @@ -71,6 +74,12 @@ export function chipLabel(s: BenchmarkSibling): string {
!s.disagg && (s.prefill_pp !== null || s.decode_pp !== null)
? Math.max(s.prefill_pp ?? 1, s.decode_pp ?? 1)
: undefined;
const aggregateDcp = s.disagg
? undefined
: meaningfulParallelismSize(s.prefill_dcp_size, s.decode_dcp_size);
const aggregatePcp = s.disagg
? undefined
: meaningfulParallelismSize(s.prefill_pcp_size, s.decode_pcp_size);
// Same parallelism labeler the chart points use (TP/EP/TEP/DEP/DPA…).
const parallel = parallelismLabel({
tp: usePrefill ? s.prefill_tp : s.decode_tp,
Expand All @@ -80,17 +89,31 @@ export function chipLabel(s: BenchmarkSibling): string {
? (s.prefill_pp ?? undefined)
: (s.decode_pp ?? undefined)
: aggregatePp,
dcp: s.disagg
? usePrefill
? (s.prefill_dcp_size ?? undefined)
: (s.decode_dcp_size ?? undefined)
: aggregateDcp,
pcp: s.disagg
? usePrefill
? (s.prefill_pcp_size ?? undefined)
: (s.decode_pcp_size ?? undefined)
: aggregatePcp,
dpAttention: usePrefill ? s.prefill_dp_attention : s.decode_dp_attention,
disagg: s.disagg,
isMultinode: s.is_multinode,
prefillTp: s.prefill_tp,
prefillEp: s.prefill_ep,
prefillPp: s.prefill_pp ?? undefined,
prefillDcp: s.prefill_dcp_size ?? undefined,
prefillPcp: s.prefill_pcp_size ?? undefined,
prefillDpAttention: s.prefill_dp_attention,
prefillNumWorkers: s.prefill_num_workers,
decodeTp: s.decode_tp,
decodeEp: s.decode_ep,
decodePp: s.decode_pp ?? undefined,
decodeDcp: s.decode_dcp_size ?? undefined,
decodePcp: s.decode_pcp_size ?? undefined,
decodeDpAttention: s.decode_dp_attention,
decodeNumWorkers: s.decode_num_workers,
});
Expand All @@ -111,12 +134,16 @@ const SORT_OPTIONS: { value: SortMode; label: string }[] = [
// Group key for the "parallelism" sort: ep first (so TP/EP1 sorts ahead of
// EP/TEP/DEP groups), then tp, then dp-attention, then disagg — every config
// of one parallelism lands together, ordered by concurrency within.
const parallelRank = (s: BenchmarkSibling): [number, number, number, number, number] => {
const parallelRank = (
s: BenchmarkSibling,
): [number, number, number, number, number, number, number] => {
const usePrefill = !s.disagg && s.decode_tp <= 0 && s.prefill_tp > 0;
return [
usePrefill ? s.prefill_ep : s.decode_ep,
usePrefill ? s.prefill_tp : s.decode_tp,
(usePrefill ? s.prefill_pp : s.decode_pp) ?? 1,
(usePrefill ? s.prefill_dcp_size : s.decode_dcp_size) ?? 1,
(usePrefill ? s.prefill_pcp_size : s.decode_pcp_size) ?? 1,
(usePrefill ? s.prefill_dp_attention : s.decode_dp_attention) ? 1 : 0,
s.disagg ? 1 : 0,
];
Expand Down
8 changes: 8 additions & 0 deletions packages/app/src/components/inference/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,14 @@ export interface AggDataEntry {
decode_ep?: number;
/** Decode-side pipeline parallelism — see {@link AggDataEntry.pp}. */
decode_pp?: number;
/** Prefill worker's decode-context parallel width, when emitted by the runtime. */
prefill_dcp_size?: number;
/** Decode worker's decode-context parallel width, when emitted by the runtime. */
decode_dcp_size?: number;
/** Prefill worker's prefill-context parallel width, when emitted by the runtime. */
prefill_pcp_size?: number;
/** Decode worker's prefill-context parallel width, when emitted by the runtime. */
decode_pcp_size?: number;
decode_dp_attention?: boolean | string;
decode_num_workers?: number;
image?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@ describe('configSegmentLabel', () => {
expect(configSegmentLabel(8, 1, false, 0)).toBe('TP8');
expect(configSegmentLabel(8, 1, false, undefined)).toBe('TP8');
});

it('appends non-default DCP and PCP as slash-delimited segments', () => {
expect(configSegmentLabel(8, 1, false, 1, 8, 1)).toBe('TP8/DCP8');
expect(configSegmentLabel(8, 1, false, 1, 8, 4)).toBe('TP8/DCP8/PCP4');
expect(configSegmentLabel(8, 8, false, 2, 8, 4)).toBe('TEP8PP2/DCP8/PCP4');
});

it('omits default DCP and PCP widths', () => {
expect(configSegmentLabel(8, 1, false, undefined, 1, 1)).toBe('TP8');
expect(configSegmentLabel(8, 1, false, undefined, 0, undefined)).toBe('TP8');
});
});

describe('parallelismLabel', () => {
Expand Down Expand Up @@ -94,6 +105,27 @@ describe('parallelismLabel', () => {
).toBe('2xTP8PP2+1xTP8');
});

it('applies per-role DCP and PCP to multinode-disagg segments', () => {
expect(
parallelismLabel({
tp: 8,
ep: 1,
disagg: true,
isMultinode: true,
prefillTp: 8,
prefillEp: 1,
prefillDcp: 2,
prefillPcp: 4,
prefillNumWorkers: 1,
decodeTp: 8,
decodeEp: 1,
decodeDcp: 8,
decodePcp: 1,
decodeNumWorkers: 1,
}),
).toBe('1xTP8/DCP2/PCP4+1xTP8/DCP8');
});

it('drops the decode segment when the decode pool is absent (0 workers, tp 0)', () => {
// Prefill-only agentic multinode runs (e.g. Kimi-K3 TP8 PP2 on b200-dgxc)
// emit decode_num_workers=0 / decode_tp=0 — the label is just the active
Expand Down
Loading