From 2695d70d42855287c051ab89335a6e9190d7c974 Mon Sep 17 00:00:00 2001 From: Yilin Fan <206948969+nv-yilinf@users.noreply.github.com> Date: Fri, 10 Oct 2025 09:24:54 -0700 Subject: [PATCH] [None][feat] Add request timing breakdown option in benchmark_serving (#8128) Signed-off-by: nv-yilinf <206948969+nv-yilinf@users.noreply.github.com> --- .../serve/scripts/benchmark_serving.py | 85 +++ .../serve/scripts/time_breakdown/README.md | 181 ++++++ .../serve/scripts/time_breakdown/__init__.py | 19 + .../serve/scripts/time_breakdown/__main__.py | 13 + .../images/request_time_breakdown_example.png | Bin 0 -> 129879 bytes .../scripts/time_breakdown/time_breakdown.py | 550 ++++++++++++++++++ .../integration/test_lists/test-db/l0_a10.yml | 1 + tests/unittest/others/test_time_breakdown.py | 504 ++++++++++++++++ 8 files changed, 1353 insertions(+) create mode 100644 tensorrt_llm/serve/scripts/time_breakdown/README.md create mode 100644 tensorrt_llm/serve/scripts/time_breakdown/__init__.py create mode 100644 tensorrt_llm/serve/scripts/time_breakdown/__main__.py create mode 100644 tensorrt_llm/serve/scripts/time_breakdown/images/request_time_breakdown_example.png create mode 100644 tensorrt_llm/serve/scripts/time_breakdown/time_breakdown.py create mode 100644 tests/unittest/others/test_time_breakdown.py diff --git a/tensorrt_llm/serve/scripts/benchmark_serving.py b/tensorrt_llm/serve/scripts/benchmark_serving.py index 82a3c247d4..d046c291fc 100644 --- a/tensorrt_llm/serve/scripts/benchmark_serving.py +++ b/tensorrt_llm/serve/scripts/benchmark_serving.py @@ -45,6 +45,7 @@ from tensorrt_llm.serve.scripts.benchmark_dataset import ( SampleRequest, ShareGPTDataset, SonnetDataset, VisionArenaDataset) from tensorrt_llm.serve.scripts.benchmark_utils import ( convert_to_pytorch_benchmark_format, write_to_json) +from tensorrt_llm.serve.scripts.time_breakdown import RequestTimeBreakdown # isort: on MILLISECONDS_TO_SECONDS_CONVERSION = 1000 @@ -598,6 +599,34 @@ def save_to_pytorch_benchmark_format(args: argparse.Namespace, write_to_json(pt_file, pt_records) +async def fetch_perf_metrics(base_url: str) -> dict: + """ + Fetch performance metrics from the /perf_metrics endpoint. + + Args: + base_url: The base URL of the server + + Returns: + Dictionary containing the performance metrics + """ + perf_url = f"{base_url}/perf_metrics" + + async with aiohttp.ClientSession(trust_env=True, + timeout=AIOHTTP_TIMEOUT) as session: + try: + async with session.get(perf_url) as response: + if response.status == 200: + return await response.json() + else: + print( + f"Failed to fetch performance metrics. Status: {response.status}" + ) + return {} + except Exception as e: + print(f"Error fetching performance metrics: {e}") + return {} + + def main(args: argparse.Namespace): print(args) random.seed(args.seed) @@ -877,6 +906,55 @@ def main(args: argparse.Namespace): json.dump(result_json, outfile) save_to_pytorch_benchmark_format(args, result_json, file_name) + # Save per-request breakdown if requested + if args.save_request_time_breakdown: + print("Fetching request performance metrics...") + perf_metrics = asyncio.run(fetch_perf_metrics(base_url)) + + if perf_metrics: + # Generate filename for perf metrics + current_dt = datetime.now().strftime("%Y%m%d-%H%M%S") + base_model_id = model_id.split("/")[-1] + max_concurrency_str = (f"-concurrency{args.max_concurrency}" + if args.max_concurrency is not None else "") + perf_filename = f"{backend}-{args.request_rate}qps{max_concurrency_str}-{base_model_id}-{current_dt}-perf_metrics.json" + + if args.result_dir: + perf_filename = os.path.join(args.result_dir, perf_filename) + + # Save perf metrics to JSON file + with open(perf_filename, "w", encoding='utf-8') as outfile: + try: + json.dump(perf_metrics, outfile, indent=2) + except Exception as e: + print(f"Failed to save perf metrics: {e}") + + print(f"Request performance metrics saved to: {perf_filename}") + + # Create timing diagram from the saved JSON file + try: + analyzer = RequestTimeBreakdown() + + print("Creating time diagram from request time breakdown...") + timing_data = analyzer.parse_json_file(perf_filename) + + if timing_data: + # Generate HTML filename for the timing diagram + diagram_filename = f"{os.path.splitext(perf_filename)[0]}-time_diagram.html" + analyzer.create_timing_diagram(timing_data, + diagram_filename) + + print(f"Time diagram saved to: {diagram_filename}") + else: + print( + "No time data found in request time breakdown - skipping diagram creation." + ) + except Exception as e: + print(f"Failed to create time diagram: {e}") + print("Performance metrics were still saved successfully.") + else: + print("Failed to fetch per-request performance metrics.") + if __name__ == "__main__": parser = FlexibleArgumentParser( @@ -1260,6 +1338,13 @@ if __name__ == "__main__": help="Skip initial test run with a single prompt.", ) + parser.add_argument( + "--save-request-time-breakdown", + action="store_true", + help= + "After benchmarking, call the /perf_metric endpoint, save the result as JSON, and create an interactive time breakdown diagram.", + ) + args = parser.parse_args() main(args) diff --git a/tensorrt_llm/serve/scripts/time_breakdown/README.md b/tensorrt_llm/serve/scripts/time_breakdown/README.md new file mode 100644 index 0000000000..1769d640c7 --- /dev/null +++ b/tensorrt_llm/serve/scripts/time_breakdown/README.md @@ -0,0 +1,181 @@ +# Time Breakdown Tool + +A standalone tool for analyzing and visualizing TensorRT-LLM server request time breakdown. + +## Overview + +The Time Breakdown tool analyzes performance metrics from TensorRT-LLM servers and creates interactive visualizations showing how time is spent processing each request. It supports both aggregated and disaggregated server configurations. + + +The tool generates: + +1. **Interactive HTML Diagram**: A stacked bar chart showing timing breakdown per request with hover tooltips +2. **Statistics**: Median times for each timing segment (optional) + +### Example Visualization + +![Request Time Breakdown Example](images/request_time_breakdown_example.png) + +*Example of the interactive time diagram showing request time breakdown across different processing stages.* + +### Timing Metrics + +The tool aims to track detailed timing segments throughout the request lifecycle (currently we only track timing segments related to TTFT (Time-To-First-Token), full lifecycle tracking will be added soon): + +#### Context/Prefill Stage Metrics + +1. **Context Preprocessing** (`ctx_preprocessing`) + - **Time Period**: `server_arrival_time` → `arrival_time` + - **Description**: Python overhead & initialization when the context server receives the request + - **Includes**: Request parsing, pre-processing (e.g., tokenization) before queuing + +2. **Context Queue** (`ctx_queue`) + - **Time Period**: `arrival_time` → `first_scheduled_time` + - **Description**: Time spent waiting in queue and resource allocation + - **Includes**: Queueing delay, memory allocation, scheduling wait time + +3. **Context Processing** (`ctx_processing`) + - **Time Period**: `first_scheduled_time` → `first_token_time` + - **Description**: Actual prefill computation time + - **Includes**: Model forward pass for the context/prompt tokens + +4. **Context Postprocessing** (`ctx_postprocessing`) + - **Time Period**: `first_token_time` → `server_first_token_time` + - **Description**: Time to prepare and send the first token response + - **Includes**: Response preparation, serialization, network overhead + +#### Generation/Decode Stage Metrics (Disaggregated Mode Only) + +5. **Generation Preprocessing** (`gen_preprocessing`) + - **Time Period**: `gen_server_arrival_time` → `gen_arrival_time` + - **Description**: Python overhead & initialization when generation server receives the request + - **Includes**: Request parsing, KV cache transfer preparation + +6. **Generation Queue** (`gen_queue`) + - **Time Period**: `gen_arrival_time` → `gen_first_scheduled_time` + - **Description**: Time spent in queue and resource allocation, including KV cache transfer + - **Includes**: + Queueing delay, KV cache transfer, memory allocation for generation + +7. **Generation First Token Postprocessing** (`gen_postprocessing`) + - **Time Period**: `gen_first_scheduled_time` → `gen_server_first_token_time` + - **Description**: Time to generate and send first token from generation server + - **Includes**: Token generation, response preparation + +#### Disaggregation Server Metrics + +8. **Disaggregation Preprocessing** (`disagg_preprocessing`) + - **Time Period**: `disagg_server_arrival_time` → `ctx_server_arrival_time` + - **Description**: Routing overhead from disagg server to context server + - **Includes**: Request forwarding, network latency + +9. **Disaggregation Postprocessing** (`disagg_postprocessing`) + - **Time Period**: `gen_server_first_token_time` → `disagg_server_first_token_time` + - **Description**: Routing overhead from generation server back through disagg server + - **Includes**: Response forwarding, aggregation +## Input Format + +The tool expects a JSON file containing an array of request performance metrics (unit: seconds). + +### Aggregated Format + +```json +[ + { + "request_id": 0, + "perf_metrics": { + "timing_metrics": { + "server_arrival_time": 1.000, + "arrival_time": 1.002, + "first_scheduled_time": 1.005, + "first_token_time": 1.025, + "server_first_token_time": 1.027 + } + } + } +] +``` + +### Disaggregated Format + +```json +[ + { + "ctx_perf_metrics": { + "request_id": 3, + "perf_metrics": { + "timing_metrics": { + "server_arrival_time": 2.000, + "arrival_time": 2.003, + "first_scheduled_time": 2.008, + "first_token_time": 2.035, + "server_first_token_time": 2.038 + } + } + }, + "gen_perf_metrics": { + "perf_metrics": { + "timing_metrics": { + "server_arrival_time": 2.050, + "arrival_time": 2.052, + "first_scheduled_time": 2.055, + "first_token_time": 2.080, + "server_first_token_time": 2.083 + } + } + }, + "disagg_server_arrival_time": 1.995, + "disagg_server_first_token_time": 2.090 + } +] +``` +## Usage + +### Integration with Benchmark Serving +Step 1: +Set +``` + return_perf_metrics: True + perf_metrics_max_requests: +``` +in the `extra-llm-api-config.yaml`. If you are running disaggregated serving, you should add configs for all servers (disagg, context and generation server). + +Step 2: +Add `--save-request-time-breakdown` when running `benchmark_serving.py` +``` +python -m tensorrt_llm.serve.scripts.benchmark_serving \ + --model ${model_name} \ + --dataset-name random \ + --ignore-eos \ + --num-prompts 1000 \ + --random-input-len 1024 \ + --random-output-len 2048 \ + --random-ids \ + --max-concurrency 64 \ + --save-result \ + --result-dir \ + --percentile-metrics "ttft,tpot,itl,e2e" \ + --save-request-time-breakdown +``` +You will be able find the interactive time diagram in ``. +### As a CLI Tool +Step 1: +Query the perf_metrics.json using the `/perf_metrics` endpoint of the trtllm server (in case of disaggreated serving, you only need to query the disagg server). Make sure the servers have `perf_metrics_max_requests` and `return_perf_metric` configured. +``` +curl -o perf_metrics.json :/perf_metrics +``` +Step 2: +Process the `perf_metrics.json` with `time_breakdown.py` +```bash +# Basic usage - analyze and create time diagram +python time_breakdown.py perf_metrics.json + +# Specify custom output file +python time_breakdown.py perf_metrics.json -o my_time_diagram.html + +# Show statistics only (no diagram) +python time_breakdown.py perf_metrics.json --stats-only + +# Create diagram and show statistics +python time_breakdown.py perf_metrics.json --show-stats +``` diff --git a/tensorrt_llm/serve/scripts/time_breakdown/__init__.py b/tensorrt_llm/serve/scripts/time_breakdown/__init__.py new file mode 100644 index 0000000000..0dbe876728 --- /dev/null +++ b/tensorrt_llm/serve/scripts/time_breakdown/__init__.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 +""" +Time Breakdown Analysis Tool + +This module provides tools for analyzing and visualizing request time breakdown +from TensorRT-LLM server performance metrics. +""" + +from .time_breakdown import (RequestDataParser, RequestTimeBreakdown, + TimingMetric, TimingMetricsConfig, main) + +__all__ = [ + 'TimingMetric', + 'TimingMetricsConfig', + 'RequestDataParser', + 'RequestTimeBreakdown', + 'main', +] diff --git a/tensorrt_llm/serve/scripts/time_breakdown/__main__.py b/tensorrt_llm/serve/scripts/time_breakdown/__main__.py new file mode 100644 index 0000000000..45132f221e --- /dev/null +++ b/tensorrt_llm/serve/scripts/time_breakdown/__main__.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 +""" +Entry point for running time_breakdown as a module. + +Usage: + python -m tensorrt_llm.serve.scripts.time_breakdown perf_metrics.json [options] +""" + +from .time_breakdown import main + +if __name__ == '__main__': + main() diff --git a/tensorrt_llm/serve/scripts/time_breakdown/images/request_time_breakdown_example.png b/tensorrt_llm/serve/scripts/time_breakdown/images/request_time_breakdown_example.png new file mode 100644 index 0000000000000000000000000000000000000000..37b4dd192bd7f5b693052fd10989eff5a58152d3 GIT binary patch literal 129879 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 DX9e9S literal 0 HcmV?d00001 diff --git a/tensorrt_llm/serve/scripts/time_breakdown/time_breakdown.py b/tensorrt_llm/serve/scripts/time_breakdown/time_breakdown.py new file mode 100644 index 0000000000..e2a68b5e57 --- /dev/null +++ b/tensorrt_llm/serve/scripts/time_breakdown/time_breakdown.py @@ -0,0 +1,550 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 +""" +Time Breakdown Analysis Tool + +This module provides tools for analyzing and visualizing request time breakdown +from TensorRT-LLM server performance metrics. It can be used both as a library +and as a standalone CLI tool. + +Usage as CLI: + python time_breakdown.py [options] + +Usage as library: + from time_breakdown import RequestTimeBreakdown + analyzer = RequestTimeBreakdown() + timing_data = analyzer.parse_json_file("perf_metrics.json") + analyzer.create_timing_diagram(timing_data, "output.html") +""" + +import argparse +import json +import math +import sys +from dataclasses import dataclass +from typing import Any, Dict, List, Optional + +import numpy as np +import plotly.graph_objects as go +import plotly.offline as pyo + + +@dataclass +class TimingMetric: + """Configuration for a timing metric segment.""" + name: str + display_name: str + color: str + description: str + start_field: str + end_field: str + server_type: Optional[ + str] = None # 'ctx', 'gen', 'disagg', or None for direct calculation + + def calculate_duration(self, timing_data: Dict[str, float]) -> float: + """Calculate the duration for this metric from timing data.""" + start_time = timing_data.get(self.start_field, float('nan')) + end_time = timing_data.get(self.end_field, float('nan')) + + # If either timestamp is NaN (not available), return NaN duration + if math.isnan(start_time) or math.isnan(end_time): + print(f"Warning: {self.name} has NaN start or end time") + return 0 + + if start_time > end_time: + print(f"Warning: {self.name} has start time after end time") + return 0 + + return end_time - start_time + + +class TimingMetricsConfig: + """Configuration class that defines all available timing metrics.""" + + def __init__(self): + self.metrics = [ + TimingMetric( + name='disagg_preprocessing', + display_name='Disagg Preprocessing', + color='#B8B8B8', # Light gray + description= + 'Time duration from the disagg server receives the request to a context server receives it', + start_field='disagg_server_arrival_time', + end_field='ctx_server_arrival_time', + server_type='disagg'), + TimingMetric( + name='ctx_preprocessing', + display_name='Context Preprocessing', + color='#90EE90', # Light green + description= + 'Time duration from a context server receives the request to a LLM worker queues it', + start_field='ctx_server_arrival_time', + end_field='ctx_arrival_time', + server_type='ctx'), + TimingMetric( + name='ctx_queue', + display_name='Context Queue', + color='#FFB347', # Light orange + description= + 'Time duration from the request is queued to first scheduled', + start_field='ctx_arrival_time', + end_field='ctx_first_scheduled_time', + server_type='ctx'), + TimingMetric( + name='ctx_processing', + display_name='Context Processing', + color='#6495ED', # Cornflower blue + description= + 'Time duration from first scheduled to first token generated on a LLM worker', + start_field='ctx_first_scheduled_time', + end_field='ctx_first_token_time', + server_type='ctx'), + TimingMetric( + name='ctx_postprocessing', + display_name='Context Postprocessing', + color='#DDA0DD', # Plum + description= + 'Time duration from first token generated on a LLM worker to the first token response sent by the context server', + start_field='ctx_first_token_time', + end_field='ctx_server_first_token_time', + server_type='ctx'), + TimingMetric( + name='gen_preprocessing', + display_name='Generation Preprocessing', + color='#FFE66D', # Bright yellow + description= + 'Time duration from a generation server receives the request to a LLM worker receives it', + start_field='gen_server_arrival_time', + end_field='gen_arrival_time', + server_type='gen'), + TimingMetric( + name='gen_queue', + display_name='Generation Queue', + color='#FF6B6B', # Coral red + description= + 'Time duration from the request is queued to first scheduled', + start_field='gen_arrival_time', + end_field='gen_first_scheduled_time', + server_type='gen'), + TimingMetric( + name='gen_postprocessing', + display_name='Generation Postprocessing', + color='#95E1D3', # Mint/teal + description= + 'Time duration from first scheduled to the first token response sent by the generation server', + start_field='gen_first_scheduled_time', + end_field='gen_server_first_token_time', + server_type='gen'), + TimingMetric( + name='disagg_postprocessing', + display_name='Disagg Postprocessing', + color='#A9A9A9', # Dark gray + description= + 'Time duration from the first token response sent by the generation server to sent by the disagg server', + start_field='gen_server_first_token_time', + end_field='disagg_server_first_token_time', + server_type='disagg') + ] + + def get_metric_by_name(self, name: str) -> Optional[TimingMetric]: + """Get a metric by its name.""" + return next((m for m in self.metrics if m.name == name), None) + + def get_metrics_by_server(self, server_type: str) -> List[TimingMetric]: + """Get all metrics for a specific server type.""" + return [m for m in self.metrics if m.server_type == server_type] + + def add_metric(self, metric: TimingMetric): + """Add a new timing metric.""" + self.metrics.append(metric) + + def remove_metric(self, name: str): + """Remove a timing metric by name.""" + self.metrics = [m for m in self.metrics if m.name != name] + + +class RequestDataParser: + """Parser for disaggregated format with ctx_perf_metrics and gen_perf_metrics.""" + + def parse_request(self, request_data: Dict, + request_index: int) -> Dict[str, Any]: + is_disaggregated = 'ctx_perf_metrics' in request_data and 'gen_perf_metrics' in request_data + + ctx_metrics = {} + gen_metrics = {} + if is_disaggregated: + ctx_metrics = request_data.get('ctx_perf_metrics', {}).get( + 'perf_metrics', {}).get('timing_metrics', {}) + gen_metrics = request_data.get('gen_perf_metrics', {}).get( + 'perf_metrics', {}).get('timing_metrics', {}) + else: + ctx_metrics = request_data.get('perf_metrics', + {}).get('timing_metrics', {}) + + ctx_arrival_time = ctx_metrics.get('arrival_time', 0) + ctx_first_scheduled_time = ctx_metrics.get('first_scheduled_time', 0) + ctx_first_token_time = ctx_metrics.get('first_token_time', 0) + ctx_server_arrival_time = ctx_metrics.get('server_arrival_time', 0) + ctx_server_first_token_time = ctx_metrics.get('server_first_token_time', + 0) + + gen_server_first_token_time = gen_metrics.get('server_first_token_time', + 0) + gen_server_arrival_time = gen_metrics.get('server_arrival_time', 0) + gen_arrival_time = gen_metrics.get('arrival_time', 0) + gen_first_token_time = gen_metrics.get('first_token_time', 0) + gen_first_scheduled_time = gen_metrics.get('first_scheduled_time', 0) + + disagg_server_arrival_time = 0 + disagg_server_first_token_time = 0 + if is_disaggregated: + disagg_server_arrival_time = request_data.get( + 'disagg_server_arrival_time', 0) + disagg_server_first_token_time = request_data.get( + 'disagg_server_first_token_time', 0) + + # Get request ID + if is_disaggregated: + request_id = request_data.get('ctx_perf_metrics', + {}).get('request_id', request_index) + else: + request_id = request_data.get('request_id', request_index) + + return { + 'request_index': request_id, + 'ctx_server_arrival_time': ctx_server_arrival_time, + 'ctx_arrival_time': ctx_arrival_time, + 'ctx_first_scheduled_time': ctx_first_scheduled_time, + 'ctx_first_token_time': ctx_first_token_time, + 'ctx_server_first_token_time': ctx_server_first_token_time, + 'gen_server_arrival_time': gen_server_arrival_time, + 'gen_arrival_time': gen_arrival_time, + 'gen_first_scheduled_time': gen_first_scheduled_time, + 'gen_first_token_time': gen_first_token_time, + 'gen_server_first_token_time': gen_server_first_token_time, + 'disagg_server_arrival_time': disagg_server_arrival_time, + 'disagg_server_first_token_time': disagg_server_first_token_time, + } + + +class RequestTimeBreakdown: + """Main class for analyzing request time breakdown.""" + + def __init__(self, config: Optional[TimingMetricsConfig] = None): + self.config = config or TimingMetricsConfig() + self.parser = RequestDataParser() + + def parse_json_file(self, json_file_path: str) -> List[Dict]: + """Parse JSON performance metrics file and extract timing information.""" + try: + with open(json_file_path, 'r') as f: + data = json.load(f) + except FileNotFoundError: + print(f"Error: File '{json_file_path}' not found.") + sys.exit(1) + except json.JSONDecodeError as e: + print(f"Error parsing JSON file '{json_file_path}': {e}") + sys.exit(1) + except Exception as e: + print(f"Error reading file '{json_file_path}': {e}") + sys.exit(1) + + timing_data = [] + + for i, request in enumerate(data): + parsed_data = self.parser.parse_request(request, i) + + # Calculate durations for each metric + for metric in self.config.metrics: + duration = metric.calculate_duration(parsed_data) + parsed_data[f'{metric.name}_time'] = duration + + timing_data.append(parsed_data) + + if timing_data: + has_gen_metrics = any(entry['gen_server_arrival_time'] > 0 + for entry in timing_data) + format_type = "disaggregated " if has_gen_metrics else "aggregated" + print( + f"Parsed timing data for {len(timing_data)} requests from {json_file_path} ({format_type} format)" + ) + else: + print(f"Parsed timing data for 0 requests from {json_file_path}") + + return timing_data + + def create_timing_diagram(self, + timing_data: List[Dict], + output_file: Optional[str] = None): + """Create an interactive HTML stacked bar chart showing time breakdown.""" + if not timing_data: + print("No timing data to visualize.") + return + + # Extract data for plotting + request_indices = [data['request_index'] for data in timing_data] + + # Create the interactive plot + fig = go.Figure() + + # Add traces for each metric + for metric in self.config.metrics: + times_ms = [ + data.get(f'{metric.name}_time', 0) * 1000 + for data in timing_data + ] + + # Only add trace if there's some non-zero data + if any(t > 0 for t in times_ms): + fig.add_trace( + go.Bar( + x=request_indices, + y=times_ms, + name=metric.display_name, + marker_color=metric.color, + hovertemplate= + f'Request %{{x}}
{metric.display_name}: %{{y:.2f}} ms' + )) + + # Update layout + fig.update_layout( + barmode='stack', + title={ + 'text': + 'Request Time Breakdown
Time Spent in Each Segment (Interactive)', + 'x': 0.5, + 'xanchor': 'center', + 'font': { + 'size': 16 + } + }, + xaxis_title='Request Index', + yaxis_title='Time (milliseconds)', + hovermode='x unified', + legend=dict(orientation="v", + yanchor="top", + y=1, + xanchor="left", + x=1.02), + width=1200, + height=700, + margin=dict(r=200)) + + # Calculate and add statistics + self._add_statistics_annotation(fig, timing_data) + + # Set default output filename if not provided + if not output_file: + output_file = 'time_breakdown.html' + elif not output_file.endswith('.html'): + output_file += '.html' + + # Generate the plotly div + plot_div = pyo.plot(fig, + output_type='div', + include_plotlyjs='cdn', + auto_open=False) + + # Generate descriptions HTML + descriptions_html = self._generate_descriptions_html(timing_data) + + # Combine into full HTML + full_html = f""" + + + + + Request Timing Breakdown + + + + {plot_div} + {descriptions_html} + + +""" + + # Write to file + with open(output_file, 'w') as f: + f.write(full_html) + + print(f"Interactive time breakdown diagram saved to: {output_file}") + print(f"Open the file in your web browser to interact with the chart!") + + def _add_statistics_annotation(self, fig, timing_data: List[Dict]): + """Add statistics annotation to the plot.""" + # Calculate median times for each metric + stats_lines = ['Median Times (ms):'] + total_times = [] + + for metric in self.config.metrics: + times = [ + data.get(f'{metric.name}_time', 0) * 1000 + for data in timing_data + ] + if any(t > 0 for t in times): + median_time = np.median(times) + stats_lines.append(f'{metric.display_name}: {median_time:.2f}') + + # Calculate total time per request + for data in timing_data: + total = sum( + data.get(f'{metric.name}_time', 0) * 1000 + for metric in self.config.metrics) + total_times.append(total) + + if total_times: + median_total = np.median(total_times) + stats_lines.append(f'Total per Request: {median_total:.2f}') + + stats_lines.append(f'Requests: {len(timing_data)}') + + stats_text = '
'.join(stats_lines) + + fig.add_annotation(x=0.98, + y=0.98, + xref='paper', + yref='paper', + text=stats_text, + showarrow=False, + align='right', + bgcolor='rgba(255, 255, 255, 0.8)', + bordercolor='black', + borderwidth=1, + font=dict(size=10)) + + def _generate_descriptions_html(self, timing_data: List[Dict]) -> str: + """Generate HTML for metric descriptions section.""" + desc_items = [] + + for metric in self.config.metrics: + times = [ + data.get(f'{metric.name}_time', 0) * 1000 + for data in timing_data + ] + # Only include metrics that have non-zero data + if any(t > 0 for t in times): + desc_items.append( + f'
' + f'{metric.display_name}: ' + f'{metric.description}' + f'
') + + if not desc_items: + return '' + + descriptions_html = f""" +
+

Metric Descriptions

+ {''.join(desc_items)} + Reference: https://github.com/NVIDIA/TensorRT-LLM/blob/main/tensorrt_llm/serve/scripts/time_breakdown/README.md +
+""" + return descriptions_html + + def show_statistics(self, timing_data: List[Dict]): + """Show detailed statistics about the timing data.""" + if not timing_data: + print("No timing data to analyze.") + return + + print("\n=== Timing Statistics ===") + print(f"Total requests: {len(timing_data)}") + + for metric in self.config.metrics: + times = [data.get(f'{metric.name}_time', 0) for data in timing_data] + if any(t > 0 for t in times): + print(f"\n{metric.display_name} Times (seconds):") + print(f" Range: {min(times):.3f} to {max(times):.3f}") + print(f" Median: {np.median(times):.3f}") + print(f" Description: {metric.description}") + + +def main(): + """Main CLI entry point.""" + parser = argparse.ArgumentParser( + description='Analyze and visualize TensorRT-LLM server time breakdown', + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + # Analyze performance metrics and create timing diagram + python time_breakdown.py perf_metrics.json + + # Specify custom output file + python time_breakdown.py perf_metrics.json -o my_timing.html + + # Show statistics only (no diagram) + python time_breakdown.py perf_metrics.json --stats-only + + # Create diagram and show statistics + python time_breakdown.py perf_metrics.json --show-stats + """) + + parser.add_argument('json_file', + type=str, + help='Path to the JSON performance metrics file') + + parser.add_argument( + '-o', + '--output', + type=str, + default=None, + help='Output HTML file path (default: time_breakdown.html)') + + parser.add_argument('--stats-only', + action='store_true', + help='Show statistics only without creating diagram') + + parser.add_argument('--show-stats', + action='store_true', + help='Show statistics in addition to creating diagram') + + args = parser.parse_args() + + # Create analyzer + analyzer = RequestTimeBreakdown() + + # Parse the JSON file + print(f"Parsing timing data from: {args.json_file}") + timing_data = analyzer.parse_json_file(args.json_file) + + if not timing_data: + print("No timing data found in the file.") + sys.exit(1) + + # Show statistics if requested + if args.stats_only or args.show_stats: + analyzer.show_statistics(timing_data) + + # Create diagram unless stats-only mode + if not args.stats_only: + analyzer.create_timing_diagram(timing_data, args.output) + + +if __name__ == '__main__': + main() diff --git a/tests/integration/test_lists/test-db/l0_a10.yml b/tests/integration/test_lists/test-db/l0_a10.yml index 6bb7181a3d..b922391f88 100644 --- a/tests/integration/test_lists/test-db/l0_a10.yml +++ b/tests/integration/test_lists/test-db/l0_a10.yml @@ -20,6 +20,7 @@ l0_a10: # NOTE: this is a CPU-only test, but we do not have a dedicated job for this (and therefore no # test list either). - unittest/_torch/models/checkpoints/hf/test_weight_loader.py + - unittest/others/test_time_breakdown.py - disaggregated/test_disaggregated.py::test_disaggregated_single_gpu_with_mpirun[TinyLlama-1.1B-Chat-v1.0] - disaggregated/test_disaggregated.py::test_disaggregated_single_gpu_with_mpirun_trt_backend[TinyLlama-1.1B-Chat-v1.0] - disaggregated/test_disaggregated.py::test_disaggregated_cuda_graph[TinyLlama-1.1B-Chat-v1.0] diff --git a/tests/unittest/others/test_time_breakdown.py b/tests/unittest/others/test_time_breakdown.py new file mode 100644 index 0000000000..4922479498 --- /dev/null +++ b/tests/unittest/others/test_time_breakdown.py @@ -0,0 +1,504 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 +""" +Unit tests for time_breakdown module + +Run tests with: + python -m pytest tests/unittest/others/test_time_breakdown.py -v + or + python -m unittest tests.unittest.others.test_time_breakdown +""" + +import json +import os +import tempfile +import unittest +from unittest.mock import patch + +from tensorrt_llm.serve.scripts.time_breakdown import (RequestDataParser, + RequestTimeBreakdown, + TimingMetric, + TimingMetricsConfig) + + +class TestTimingMetric(unittest.TestCase): + """Test TimingMetric class.""" + + def test_timing_metric_creation(self): + """Test basic TimingMetric creation.""" + metric = TimingMetric(name='test_metric', + display_name='Test Metric', + color='blue', + description='Test description', + start_field='start_time', + end_field='end_time', + server_type='ctx') + + self.assertEqual(metric.name, 'test_metric') + self.assertEqual(metric.display_name, 'Test Metric') + self.assertEqual(metric.color, 'blue') + self.assertEqual(metric.description, 'Test description') + self.assertEqual(metric.start_field, 'start_time') + self.assertEqual(metric.end_field, 'end_time') + self.assertEqual(metric.server_type, 'ctx') + + def test_calculate_duration_valid(self): + """Test duration calculation with valid timestamps.""" + metric = TimingMetric(name='test', + display_name='Test', + color='blue', + description='Test', + start_field='start_time', + end_field='end_time') + + timing_data = {'start_time': 1.0, 'end_time': 3.5} + + duration = metric.calculate_duration(timing_data) + self.assertEqual(duration, 2.5) + + def test_calculate_duration_missing_start(self): + """Test duration calculation with missing start time.""" + metric = TimingMetric(name='test', + display_name='Test', + color='blue', + description='Test', + start_field='start_time', + end_field='end_time') + + timing_data = {'end_time': 3.5} + + duration = metric.calculate_duration(timing_data) + self.assertEqual(duration, 0.0) + + def test_calculate_duration_missing_end(self): + """Test duration calculation with missing end time.""" + metric = TimingMetric(name='test', + display_name='Test', + color='blue', + description='Test', + start_field='start_time', + end_field='end_time') + + timing_data = {'start_time': 1.0, 'end_time': 0} + + duration = metric.calculate_duration(timing_data) + self.assertEqual(duration, 0.0) + + def test_calculate_duration_negative(self): + """Test duration calculation doesn't produce negative values.""" + metric = TimingMetric(name='test', + display_name='Test', + color='blue', + description='Test', + start_field='start_time', + end_field='end_time') + + timing_data = {'start_time': 5.0, 'end_time': 3.5} + + duration = metric.calculate_duration(timing_data) + self.assertEqual(duration, 0.0) + + +class TestTimingMetricsConfig(unittest.TestCase): + """Test TimingMetricsConfig class.""" + + def test_default_metrics_loaded(self): + """Test that default metrics are loaded.""" + config = TimingMetricsConfig() + + # Should have multiple default metrics + self.assertGreater(len(config.metrics), 0) + + # Check for expected metric names + metric_names = [m.name for m in config.metrics] + self.assertIn('ctx_preprocessing', metric_names) + self.assertIn('ctx_processing', metric_names) + + def test_get_metric_by_name(self): + """Test retrieving a metric by name.""" + config = TimingMetricsConfig() + + metric = config.get_metric_by_name('ctx_preprocessing') + self.assertIsNotNone(metric) + self.assertEqual(metric.name, 'ctx_preprocessing') + + # Test non-existent metric + metric = config.get_metric_by_name('non_existent') + self.assertIsNone(metric) + + def test_get_metrics_by_server(self): + """Test retrieving metrics by server type.""" + config = TimingMetricsConfig() + + ctx_metrics = config.get_metrics_by_server('ctx') + self.assertGreater(len(ctx_metrics), 0) + + # All returned metrics should be for 'ctx' server + for metric in ctx_metrics: + self.assertEqual(metric.server_type, 'ctx') + + def test_add_metric(self): + """Test adding a new metric.""" + config = TimingMetricsConfig() + initial_count = len(config.metrics) + + new_metric = TimingMetric(name='custom_metric', + display_name='Custom Metric', + color='red', + description='Custom test metric', + start_field='start', + end_field='end') + + config.add_metric(new_metric) + self.assertEqual(len(config.metrics), initial_count + 1) + self.assertIsNotNone(config.get_metric_by_name('custom_metric')) + + def test_remove_metric(self): + """Test removing a metric.""" + config = TimingMetricsConfig() + initial_count = len(config.metrics) + + # Add a test metric first + test_metric = TimingMetric(name='test_to_remove', + display_name='Test', + color='blue', + description='Test', + start_field='start', + end_field='end') + config.add_metric(test_metric) + + # Remove it + config.remove_metric('test_to_remove') + self.assertEqual(len(config.metrics), initial_count) + self.assertIsNone(config.get_metric_by_name('test_to_remove')) + + +class TestRequestDataParser(unittest.TestCase): + """Test RequestDataParser class.""" + + def test_parse_aggregated_format(self): + """Test parsing aggregated (non-disaggregated) format.""" + parser = RequestDataParser() + + request_data = { + 'request_id': 'req123', + 'perf_metrics': { + 'timing_metrics': { + 'server_arrival_time': 1.0, + 'arrival_time': 1.1, + 'first_scheduled_time': 1.2, + 'first_token_time': 1.5, + 'server_first_token_time': 1.6 + } + } + } + + parsed = parser.parse_request(request_data, 0) + + self.assertEqual(parsed['request_index'], 'req123') + self.assertEqual(parsed['ctx_server_arrival_time'], 1.0) + self.assertEqual(parsed['ctx_arrival_time'], 1.1) + self.assertEqual(parsed['ctx_first_scheduled_time'], 1.2) + self.assertEqual(parsed['ctx_first_token_time'], 1.5) + self.assertEqual(parsed['ctx_server_first_token_time'], 1.6) + + # Gen metrics should be 0 in aggregated format + self.assertEqual(parsed['gen_server_arrival_time'], 0) + self.assertEqual(parsed['disagg_server_arrival_time'], 0) + + def test_parse_disaggregated_format(self): + """Test parsing disaggregated format.""" + parser = RequestDataParser() + + request_data = { + 'ctx_perf_metrics': { + 'request_id': 'req456', + 'perf_metrics': { + 'timing_metrics': { + 'server_arrival_time': 1.0, + 'arrival_time': 1.1, + 'first_scheduled_time': 1.2, + 'first_token_time': 1.5, + 'server_first_token_time': 1.6 + } + } + }, + 'gen_perf_metrics': { + 'perf_metrics': { + 'timing_metrics': { + 'server_arrival_time': 2.0, + 'arrival_time': 2.1, + 'first_scheduled_time': 2.2, + 'first_token_time': 2.5, + 'server_first_token_time': 2.6 + } + } + }, + 'disagg_server_arrival_time': 0.5, + 'disagg_server_first_token_time': 3.0 + } + + parsed = parser.parse_request(request_data, 0) + + self.assertEqual(parsed['request_index'], 'req456') + + # Context metrics + self.assertEqual(parsed['ctx_server_arrival_time'], 1.0) + self.assertEqual(parsed['ctx_arrival_time'], 1.1) + + # Generation metrics + self.assertEqual(parsed['gen_server_arrival_time'], 2.0) + self.assertEqual(parsed['gen_arrival_time'], 2.1) + + # Disaggregation metrics + self.assertEqual(parsed['disagg_server_arrival_time'], 0.5) + self.assertEqual(parsed['disagg_server_first_token_time'], 3.0) + + def test_parse_missing_fields(self): + """Test parsing with missing fields (should default to 0).""" + parser = RequestDataParser() + + request_data = { + 'request_id': 'req789', + 'perf_metrics': { + 'timing_metrics': {} + } + } + + parsed = parser.parse_request(request_data, 0) + + # All timing fields should default to 0 + self.assertEqual(parsed['ctx_server_arrival_time'], 0) + self.assertEqual(parsed['ctx_arrival_time'], 0) + self.assertEqual(parsed['gen_server_arrival_time'], 0) + + def test_parse_uses_index_as_fallback(self): + """Test that index is used when request_id is missing.""" + parser = RequestDataParser() + + request_data = {'perf_metrics': {'timing_metrics': {}}} + + parsed = parser.parse_request(request_data, 42) + + self.assertEqual(parsed['request_index'], 42) + + +class TestRequestTimeBreakdown(unittest.TestCase): + """Test RequestTimeBreakdown class.""" + + def setUp(self): + """Set up test fixtures.""" + self.analyzer = RequestTimeBreakdown() + + # Create a temporary JSON file for testing + self.test_data = [{ + 'request_id': 0, + 'perf_metrics': { + 'timing_metrics': { + 'server_arrival_time': 1.0, + 'arrival_time': 1.1, + 'first_scheduled_time': 1.2, + 'first_token_time': 1.5, + 'server_first_token_time': 1.6 + } + } + }, { + 'request_id': 1, + 'perf_metrics': { + 'timing_metrics': { + 'server_arrival_time': 2.0, + 'arrival_time': 2.1, + 'first_scheduled_time': 2.3, + 'first_token_time': 2.7, + 'server_first_token_time': 2.8 + } + } + }] + + def test_parse_json_file(self): + """Test parsing a JSON file.""" + # Create a temporary file + with tempfile.NamedTemporaryFile(mode='w', suffix='.json', + delete=False) as f: + json.dump(self.test_data, f) + temp_file = f.name + + try: + timing_data = self.analyzer.parse_json_file(temp_file) + + self.assertEqual(len(timing_data), 2) + + # Check first request + self.assertEqual(timing_data[0]['request_index'], 0) + self.assertEqual(timing_data[0]['ctx_server_arrival_time'], 1.0) + + # Check that durations were calculated + self.assertIn('ctx_preprocessing_time', timing_data[0]) + self.assertIn('ctx_queue_time', timing_data[0]) + + # Verify a specific duration calculation + # ctx_preprocessing = ctx_arrival_time - ctx_server_arrival_time + expected_preprocessing = 1.1 - 1.0 + self.assertAlmostEqual(timing_data[0]['ctx_preprocessing_time'], + expected_preprocessing, + places=5) + finally: + os.unlink(temp_file) + + def test_parse_json_file_not_found(self): + """Test parsing a non-existent file.""" + with self.assertRaises(SystemExit): + self.analyzer.parse_json_file('non_existent_file.json') + + def test_parse_json_file_invalid_json(self): + """Test parsing an invalid JSON file.""" + with tempfile.NamedTemporaryFile(mode='w', suffix='.json', + delete=False) as f: + f.write("{ invalid json") + temp_file = f.name + + try: + with self.assertRaises(SystemExit): + self.analyzer.parse_json_file(temp_file) + finally: + os.unlink(temp_file) + + def test_create_timing_diagram(self): + """Test creating a timing diagram.""" + # Create sample timing data + timing_data = [{ + 'request_index': 0, + 'ctx_preprocessing_time': 0.1, + 'ctx_queue_time': 0.2, + 'ctx_processing_time': 0.3, + 'ctx_postprocessing_time': 0.05, + 'gen_preprocessing_time': 0, + 'gen_queue_time': 0, + 'gen_postprocessing_time': 0, + 'disagg_preprocessing_time': 0, + 'disagg_postprocessing_time': 0, + }, { + 'request_index': 1, + 'ctx_preprocessing_time': 0.15, + 'ctx_queue_time': 0.25, + 'ctx_processing_time': 0.35, + 'ctx_postprocessing_time': 0.06, + 'gen_preprocessing_time': 0, + 'gen_queue_time': 0, + 'gen_postprocessing_time': 0, + 'disagg_preprocessing_time': 0, + 'disagg_postprocessing_time': 0, + }] + + with tempfile.NamedTemporaryFile(suffix='.html', delete=False) as f: + temp_file = f.name + + try: + # Mock plotly to avoid actual file creation + with patch( + 'tensorrt_llm.serve.scripts.time_breakdown.time_breakdown.pyo.plot' + ) as mock_plot: + self.analyzer.create_timing_diagram(timing_data, temp_file) + + # Verify that plot was called + mock_plot.assert_called_once() + finally: + if os.path.exists(temp_file): + os.unlink(temp_file) + + def test_create_timing_diagram_empty_data(self): + """Test creating a diagram with empty data.""" + # Should handle gracefully without creating a file + with patch('builtins.print') as mock_print: + self.analyzer.create_timing_diagram([]) + mock_print.assert_called_with("No timing data to visualize.") + + def test_show_statistics(self): + """Test showing statistics.""" + timing_data = [{ + 'ctx_preprocessing_time': 0.1, + 'ctx_queue_time': 0.2, + 'ctx_processing_time': 0.3, + }, { + 'ctx_preprocessing_time': 0.15, + 'ctx_queue_time': 0.25, + 'ctx_processing_time': 0.35, + }] + + # Capture printed output + with patch('builtins.print') as mock_print: + self.analyzer.show_statistics(timing_data) + + # Should have printed something + self.assertTrue(mock_print.called) + + # Check for expected content in printed output + printed_output = ' '.join( + [str(call[0][0]) for call in mock_print.call_args_list]) + self.assertIn('Total requests', printed_output) + + def test_show_statistics_empty_data(self): + """Test showing statistics with empty data.""" + with patch('builtins.print') as mock_print: + self.analyzer.show_statistics([]) + mock_print.assert_called_with("No timing data to analyze.") + + def test_custom_config(self): + """Test using a custom configuration.""" + custom_config = TimingMetricsConfig() + custom_config.add_metric( + TimingMetric(name='custom_metric', + display_name='Custom', + color='red', + description='Custom metric', + start_field='custom_start', + end_field='custom_end')) + + analyzer = RequestTimeBreakdown(config=custom_config) + + # Verify custom config is used + self.assertIsNotNone( + analyzer.config.get_metric_by_name('custom_metric')) + + +class TestIntegration(unittest.TestCase): + """Integration tests for the full workflow.""" + + def test_full_workflow(self): + """Test the complete workflow from file to diagram.""" + # Create test data + test_data = [{ + 'request_id': i, + 'perf_metrics': { + 'timing_metrics': { + 'server_arrival_time': float(i), + 'arrival_time': float(i) + 0.1, + 'first_scheduled_time': float(i) + 0.2, + 'first_token_time': float(i) + 0.5, + 'server_first_token_time': float(i) + 0.6 + } + } + } for i in range(5)] + + # Create temporary files and run the complete workflow + with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=True) as json_f, \ + tempfile.NamedTemporaryFile(suffix='.html', delete=True) as html_f: + # Write test data to JSON file + json.dump(test_data, json_f) + json_f.flush() # Ensure data is written before reading + + analyzer = RequestTimeBreakdown() + timing_data = analyzer.parse_json_file(json_f.name) + + # Verify parsing + self.assertEqual(len(timing_data), 5) + + # Mock the plot function to avoid actual file operations + with patch( + 'tensorrt_llm.serve.scripts.time_breakdown.time_breakdown.pyo.plot' + ): + analyzer.create_timing_diagram(timing_data, html_f.name) + + +if __name__ == '__main__': + unittest.main()