Skip to content

Commit e8e3fc2

Browse files
committed
Features/add tooltip to line chart #392
features/ui/add-tooltip-to-metric-summary
2 parents 088462e + 6041aba commit e8e3fc2

File tree

7 files changed

+87
-11
lines changed

7 files changed

+87
-11
lines changed

src/guidellm/presentation/data_models.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import httpx
77
from pydantic import BaseModel, computed_field
88

9+
from guidellm.scheduler.strategy import SchedulingStrategy
10+
911
if TYPE_CHECKING:
1012
from guidellm.benchmark import GenerativeBenchmark
1113

@@ -253,12 +255,30 @@ class BenchmarkDatum(BaseModel):
253255
ttft: TabularDistributionSummary
254256
throughput: TabularDistributionSummary
255257
time_per_request: TabularDistributionSummary
258+
strategy_display_str: str
259+
260+
@classmethod
261+
def get_strategy_display_str(cls, strategy: SchedulingStrategy):
262+
strategy_type = strategy if isinstance(strategy, str) else strategy.type_
263+
strategy_instance = (
264+
strategy if isinstance(strategy, SchedulingStrategy) else None
265+
)
266+
267+
if strategy_type == "concurrent":
268+
rate = f"@{strategy.streams}" if strategy_instance else "@##" # type: ignore[attr-defined]
269+
elif strategy_type in ("constant", "poisson"):
270+
rate = f"@{strategy.rate:.2f}" if strategy_instance else "@#.##" # type: ignore[attr-defined]
271+
else:
272+
rate = ""
273+
return f"{strategy_type}{rate}"
256274

257275
@classmethod
258276
def from_benchmark(cls, bm: "GenerativeBenchmark"):
277+
rps = bm.metrics.requests_per_second.successful.mean
259278
return cls(
260-
requests_per_second=bm.metrics.requests_per_second.successful.mean,
261-
tpot=TabularDistributionSummary.from_distribution_summary(
279+
strategy_display_str=cls.get_strategy_display_str(bm.args.strategy),
280+
requests_per_second=rps,
281+
itl=TabularDistributionSummary.from_distribution_summary(
262282
bm.metrics.inter_token_latency_ms.successful
263283
),
264284
ttft=TabularDistributionSummary.from_distribution_summary(

src/ui/lib/components/Charts/MetricLine/MetricLine.component.tsx

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { useTheme } from '@mui/material';
2-
import { ResponsiveLine } from '@nivo/line';
1+
import { Typography, useTheme } from '@mui/material';
2+
import { PointTooltipProps, ResponsiveLine } from '@nivo/line';
3+
import { BasicTooltip } from '@nivo/tooltip';
34
import React, { FC } from 'react';
45

56
import { useColor } from '@/lib/hooks/useColor';
@@ -49,11 +50,30 @@ export const Component: FC<MetricLineProps> = ({
4950
reverse: false,
5051
};
5152
}
53+
type PointTooltipPropsWithLabel = PointTooltipProps & {
54+
point: {
55+
data: {
56+
label: string;
57+
};
58+
};
59+
};
5260

5361
return (
5462
<ResponsiveLine
5563
curve="monotoneX"
5664
data={data}
65+
tooltip={(point) => (
66+
<BasicTooltip
67+
id={
68+
<Typography variant="body2">
69+
{(point as PointTooltipPropsWithLabel).point.data.label}
70+
</Typography>
71+
}
72+
color={point.point.color}
73+
enableChip={true}
74+
/>
75+
)}
76+
pointSize={10}
5777
colors={[selectedColor]}
5878
margin={{ top: 20, right: 10, bottom: 20, left: 35.5 }}
5979
xScale={{ type: 'linear', min: minX }}
@@ -92,7 +112,6 @@ export const Component: FC<MetricLineProps> = ({
92112
}}
93113
enableGridX={false}
94114
enableGridY={false}
95-
pointSize={0}
96115
useMesh={true}
97116
layers={[
98117
CustomAxes,
@@ -115,6 +134,9 @@ export const Component: FC<MetricLineProps> = ({
115134
),
116135
'axes',
117136
'lines',
137+
'points',
138+
'markers',
139+
'mesh',
118140
]}
119141
theme={lineTheme}
120142
/>

src/ui/lib/components/MetricsSummary/MetricsSummary.component.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ export const Component = () => {
102102
return (
103103
<>
104104
<BlockHeader label="Metrics Summary" />
105-
<MetricsSummaryContainer container>
105+
<MetricsSummaryContainer sx={{ overflow: 'visible' }} container>
106106
<HeaderLeftCell item xs={9}>
107107
<Box display="flex" flexDirection="row" justifyContent="space-between">
108108
<Typography variant="h6" color="surface.onSurface" mb={2}>

src/ui/lib/store/benchmarksWindowData.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export const benchmarksScript = `window.benchmarks = [
22
{
3+
strategyDisplayStr: "synchronous",
34
requestsPerSecond: 11.411616848282272,
45
tpot: {
56
mean: 8.758024845683707,
@@ -171,6 +172,7 @@ export const benchmarksScript = `window.benchmarks = [
171172
},
172173
},
173174
{
175+
strategyDisplayStr: "[email protected]",
174176
requestsPerSecond: 36.289181300710815,
175177
tpot: {
176178
mean: 588.0161376137819,
@@ -342,6 +344,7 @@ export const benchmarksScript = `window.benchmarks = [
342344
},
343345
},
344346
{
347+
strategyDisplayStr: "[email protected]",
345348
requestsPerSecond: 20.752070927855794,
346349
tpot: {
347350
mean: 116.28360712595156,
@@ -513,6 +516,7 @@ export const benchmarksScript = `window.benchmarks = [
513516
},
514517
},
515518
{
519+
strategyDisplayStr: "[email protected]",
516520
requestsPerSecond: 26.81917480361788,
517521
tpot: {
518522
mean: 299.7306064613554,
@@ -684,6 +688,7 @@ export const benchmarksScript = `window.benchmarks = [
684688
},
685689
},
686690
{
691+
strategyDisplayStr: "[email protected]",
687692
requestsPerSecond: 26.823988819498975,
688693
tpot: {
689694
mean: 683.8011571339198,
@@ -855,6 +860,7 @@ export const benchmarksScript = `window.benchmarks = [
855860
},
856861
},
857862
{
863+
strategyDisplayStr: "[email protected]",
858864
requestsPerSecond: 24.50047903792646,
859865
tpot: {
860866
mean: 742.9258901891964,
@@ -1026,6 +1032,7 @@ export const benchmarksScript = `window.benchmarks = [
10261032
},
10271033
},
10281034
{
1035+
strategyDisplayStr: "[email protected]",
10291036
requestsPerSecond: 25.617829792196602,
10301037
tpot: {
10311038
mean: 663.3098317044122,
@@ -1197,6 +1204,7 @@ export const benchmarksScript = `window.benchmarks = [
11971204
},
11981205
},
11991206
{
1207+
strategyDisplayStr: "[email protected]",
12001208
requestsPerSecond: 37.02892550982192,
12011209
tpot: {
12021210
mean: 606.4144710877113,
@@ -1368,6 +1376,7 @@ export const benchmarksScript = `window.benchmarks = [
13681376
},
13691377
},
13701378
{
1379+
strategyDisplayStr: "[email protected]",
13711380
requestsPerSecond: 37.29183354201869,
13721381
tpot: {
13731382
mean: 603.3237551205925,
@@ -1539,6 +1548,7 @@ export const benchmarksScript = `window.benchmarks = [
15391548
},
15401549
},
15411550
{
1551+
strategyDisplayStr: "throughput",
15421552
requestsPerSecond: 37.45318312972309,
15431553
tpot: {
15441554
mean: 600.7204526769262,

src/ui/lib/store/slices/benchmarks/benchmarks.interfaces.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export interface BenchmarkMetrics {
2727

2828
export interface Benchmark extends BenchmarkMetrics {
2929
requestsPerSecond: number;
30+
strategyDisplayStr: string;
3031
}
3132

3233
export type Benchmarks = Benchmark[];

src/ui/lib/store/slices/benchmarks/benchmarks.selectors.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,29 @@ import { selectSloState } from '../slo/slo.selectors';
1111

1212
export const selectBenchmarks = (state: RootState) => state.benchmarks.data;
1313

14+
const getUnitsByMetric = (metric: string) => {
15+
switch (metric) {
16+
case 'ttft':
17+
case 'tpot':
18+
return 'ms';
19+
case 'timePerRequest':
20+
return 'sec';
21+
case 'throughput':
22+
return 'tok/s';
23+
}
24+
};
25+
1426
export const selectMetricsSummaryLineData = createSelector(
1527
[selectBenchmarks, selectSloState],
1628
(benchmarks, sloState) => {
1729
const sortedByRPS = benchmarks
1830
?.slice()
1931
?.sort((bm1, bm2) => (bm1.requestsPerSecond > bm2.requestsPerSecond ? 1 : -1));
2032
const selectedPercentile = sloState.enforcedPercentile;
21-
22-
const lineData: { [K in keyof BenchmarkMetrics]: Point[] } = {
33+
interface PointWithLabel extends Point {
34+
label: string;
35+
}
36+
const lineData: { [K in keyof BenchmarkMetrics]: PointWithLabel[] } = {
2337
ttft: [],
2438
tpot: [],
2539
timePerRequest: [],
@@ -32,14 +46,17 @@ export const selectMetricsSummaryLineData = createSelector(
3246
'throughput',
3347
];
3448
metrics.forEach((metric) => {
35-
const data: Point[] = [];
49+
const data: PointWithLabel[] = [];
3650
sortedByRPS?.forEach((benchmark) => {
3751
const percentile = benchmark[metric].percentileRows.find(
3852
(p) => p.percentile === selectedPercentile
3953
);
54+
const yValue = percentile?.value ?? 0;
55+
const units = getUnitsByMetric(metric);
4056
data.push({
4157
x: benchmark.requestsPerSecond,
42-
y: percentile?.value ?? 0,
58+
y: yValue,
59+
label: `${benchmark.strategyDisplayStr} ${formatNumber(yValue)} ${units}`,
4360
});
4461
});
4562

tests/unit/presentation/test_data_models.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from guidellm.dataset.hf_datasets import HFDatasetsCreator
77
from guidellm.dataset.in_memory import InMemoryDatasetCreator
88
from guidellm.dataset.synthetic import SyntheticDatasetCreator
9-
from guidellm.presentation.data_models import Bucket, Dataset
9+
from guidellm.presentation.data_models import Bucket, Dataset, BenchmarkDatum, Bucket
1010
from tests.unit.mock_benchmark import mock_generative_benchmark
1111

1212

@@ -136,3 +136,9 @@ def test_dataset_from_data_with_hf_dataset():
136136
):
137137
dataset = Dataset.from_data(mock_benchmark.request_loader)
138138
assert dataset.name == "openai/gsm8k"
139+
140+
@pytest.mark.smoke
141+
def test_from_benchmark_includes_strategy_display_str():
142+
mock_bm = mock_generative_benchmark()
143+
bm = BenchmarkDatum.from_benchmark(mock_bm)
144+
assert bm.strategy_display_str == "synchronous"

0 commit comments

Comments
 (0)