Skip to content

Commit 2d44cc9

Browse files
authored
Detailed reporting after profile (#711)
* Cherry picked changes * Changing to evaluate a mock config and directly call report * Switch away from using mock * Adding type checking to CLI.parse() * Restoring original profile config * Adding missing newline * Fixing codeQL issue
1 parent 650d118 commit 2d44cc9

File tree

9 files changed

+95
-23
lines changed

9 files changed

+95
-23
lines changed

docs/config.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,9 @@ cpu_only_composing_models: <comma-delimited-string-list>
230230
# Skips the generation of summary reports and tables
231231
[ skip_summary_reports: <bool> | default: false]
232232
233+
# Skips the generation of detailed reports and tables
234+
[ skip_detailed_reports: <bool> | default: false]
235+
233236
# Number of top configs to show in summary plots
234237
[ num_configs_per_model: <int> | default: 3]
235238

docs/report.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ $ model-analyzer profile --profile-models <list of model names> --checkpoint-dir
3333
The export directory will, by default, contain 3 subdirectories. The summary
3434
report for a model will be located in `[export-path]/reports/summaries/<model name>`. The report will look like the one shown [_here_](../examples/online_summary.pdf).
3535

36-
To disable summary report generation use `--summarize=false` or set the
37-
`summarize` yaml option to `false`.
36+
To disable summary report generation use `--skip-summary-reports` or set the
37+
`skip_summary_reports` yaml option to `false`.
3838

3939
## Detailed Reports
4040

@@ -57,3 +57,7 @@ look like the one shown [_here_](../examples/online_detailed_report.pdf).
5757
See the [**configuring model
5858
analyzer**](./config.md) section for more details on how to configure these
5959
reports.
60+
61+
Detailed reports for the top-N (based on the value of `--num-configs-per-model`) configurations are also generated at the end of `profile`.
62+
To disable detailed report generation after `profile` use `--skip-detailed-reports` or set the
63+
`skip_detailed_reports` yaml option to `false`.

model_analyzer/analyzer.py

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# limitations under the License.
1414

1515
from typing import List, Union, Optional
16+
from copy import deepcopy
1617
import sys
1718
from model_analyzer.constants import LOGGER_NAME, PA_ERROR_LOG_FILENAME
1819
from .model_manager import ModelManager
@@ -32,6 +33,8 @@
3233
from model_analyzer.state.analyzer_state_manager import AnalyzerStateManager
3334
from model_analyzer.triton.server.server import TritonServer
3435

36+
from model_analyzer.cli.cli import CLI
37+
3538
from model_analyzer.config.generate.base_model_config_generator import BaseModelConfigGenerator
3639

3740
from .triton.client.client import TritonClient
@@ -126,17 +129,9 @@ def profile(self, client: TritonClient, gpus: List[GPUDevice], mode: str,
126129
if not self._config.skip_summary_reports:
127130
self._create_summary_tables(verbose)
128131
self._create_summary_reports(mode)
132+
self._create_detailed_reports(mode)
129133

130-
# TODO-TMA-650: Detailed reporting not supported for multi-model
131-
if not self._config.run_config_profile_models_concurrently_enable:
132-
for model in self._config.profile_models:
133-
logger.info(
134-
self._get_report_command_help_string(
135-
model.model_name()))
136-
137-
if self._metrics_manager.encountered_perf_analyzer_error():
138-
logger.warning(f"Perf Analyzer encountered an error when profiling one or more configurations. " \
139-
f"See {self._config.export_path}/{PA_ERROR_LOG_FILENAME} for further details.\n")
134+
self._check_for_perf_analyzer_errors()
140135

141136
def report(self, mode: str) -> None:
142137
"""
@@ -280,18 +275,35 @@ def _get_num_profiled_configs(self):
280275
])
281276

282277
def _get_report_command_help_string(self, model_name: str) -> str:
283-
top_3_model_config_names = self._get_top_n_model_config_names(
284-
n=3, model_name=model_name)
278+
top_n_model_config_names = self._get_top_n_model_config_names(
279+
n=self._config.num_configs_per_model, model_name=model_name)
285280
return (
286281
f'To generate detailed reports for the '
287-
f'{len(top_3_model_config_names)} best {model_name} configurations, run '
288-
f'`{self._get_report_command_string(top_3_model_config_names)}`')
282+
f'{len(top_n_model_config_names)} best {model_name} configurations, run '
283+
f'`{self._get_report_command_string(top_n_model_config_names)}`')
284+
285+
def _run_report_command(self, model_name: str, mode: str) -> None:
286+
top_n_model_config_names = self._get_top_n_model_config_names(
287+
n=self._config.num_configs_per_model, model_name=model_name)
288+
top_n_string = ','.join(top_n_model_config_names)
289+
logger.info(
290+
f'Generating detailed reports for the best configurations {top_n_string}:'
291+
)
292+
293+
# [1:] removes 'model-analyzer' from the args
294+
args = self._get_report_command_string(top_n_model_config_names).split(
295+
' ')[1:]
296+
297+
original_profile_config = deepcopy(self._config)
298+
self._config = self._create_report_config(args)
299+
self.report(mode)
300+
self._config = original_profile_config
289301

290302
def _get_report_command_string(self,
291-
top_3_model_config_names: List[str]) -> str:
303+
top_n_model_config_names: List[str]) -> str:
292304
report_command_string = (f'model-analyzer report '
293305
f'--report-model-configs '
294-
f'{",".join(top_3_model_config_names)}')
306+
f'{",".join(top_n_model_config_names)}')
295307

296308
if self._config.export_path is not None:
297309
report_command_string += (f' --export-path '
@@ -336,3 +348,26 @@ def _multiple_models_in_report_model_config(self) -> bool:
336348
]
337349

338350
return len(set(model_names)) > 1
351+
352+
def _check_for_perf_analyzer_errors(self) -> None:
353+
if self._metrics_manager.encountered_perf_analyzer_error():
354+
logger.warning(f"Perf Analyzer encountered an error when profiling one or more configurations. " \
355+
f"See {self._config.export_path}/{PA_ERROR_LOG_FILENAME} for further details.\n")
356+
357+
def _create_detailed_reports(self, mode: str) -> None:
358+
# TODO-TMA-650: Detailed reporting not supported for multi-model
359+
if not self._config.run_config_profile_models_concurrently_enable:
360+
for model in self._config.profile_models:
361+
if not self._config.skip_detailed_reports:
362+
self._run_report_command(model.model_name(), mode)
363+
else:
364+
logger.info(
365+
self._get_report_command_help_string(
366+
model.model_name()))
367+
368+
def _create_report_config(self, args: list) -> ConfigCommandReport:
369+
config = ConfigCommandReport()
370+
cli = CLI()
371+
cli.add_subcommand(cmd='report', help="", config=config)
372+
cli.parse(args)
373+
return config

model_analyzer/cli/cli.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,15 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
from typing import List, Union, Optional, Tuple
16+
1517
import logging
1618
import argparse
17-
from argparse import ArgumentParser
19+
from argparse import ArgumentParser, Namespace
20+
21+
from model_analyzer.config.input.config_command_profile import ConfigCommandProfile
22+
from model_analyzer.config.input.config_command_report import ConfigCommandReport
23+
1824
from model_analyzer.constants import LOGGER_NAME
1925

2026
logger = logging.getLogger(LOGGER_NAME)
@@ -118,11 +124,20 @@ def _add_config_arguments(self, subparser, config):
118124
**config_field.parser_args(),
119125
)
120126

121-
def parse(self):
127+
def parse(
128+
self,
129+
input_args: Optional[List] = None
130+
) -> Tuple[Namespace, Union[ConfigCommandProfile, ConfigCommandReport]]:
122131
"""
123132
Parse CLI options using ArgumentParsers
124133
and set config values.
125134
135+
Parameters
136+
----------
137+
input_args: List
138+
The list of arguments to be parsed
139+
(if None then command line arguments will be used)
140+
126141
Returns
127142
-------
128143
args : Namespace
@@ -133,7 +148,8 @@ def parse(self):
133148
already filled in with values from CLI or YAML.
134149
"""
135150

136-
args = self._parser.parse_args()
151+
args = self._parser.parse_args(input_args)
152+
137153
if args.subcommand is None:
138154
self._parser.print_help()
139155
self._parser.exit()

model_analyzer/config/input/config_command_profile.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@
4646
DEFAULT_FILENAME_SERVER_ONLY, DEFAULT_NUM_CONFIGS_PER_MODEL, DEFAULT_NUM_TOP_MODEL_CONFIGS, \
4747
DEFAULT_INFERENCE_OUTPUT_FIELDS, DEFAULT_REQUEST_RATE_INFERENCE_OUTPUT_FIELDS, \
4848
DEFAULT_GPU_OUTPUT_FIELDS, DEFAULT_REQUEST_RATE_GPU_OUTPUT_FIELDS, DEFAULT_SERVER_OUTPUT_FIELDS, \
49-
DEFAULT_ONLINE_OBJECTIVES, DEFAULT_ONLINE_PLOTS, DEFAULT_OFFLINE_PLOTS, DEFAULT_MODEL_WEIGHTING
49+
DEFAULT_ONLINE_OBJECTIVES, DEFAULT_ONLINE_PLOTS, DEFAULT_OFFLINE_PLOTS, DEFAULT_MODEL_WEIGHTING, \
50+
DEFAULT_SKIP_DETAILED_REPORTS
5051

5152
from model_analyzer.constants import LOGGER_NAME
5253
from model_analyzer.triton.server.server_config import \
@@ -223,6 +224,15 @@ def _fill_config(self):
223224
default_value=DEFAULT_SKIP_SUMMARY_REPORTS,
224225
description=
225226
'Skips the generation of analysis summary reports and tables.'))
227+
self._add_config(
228+
ConfigField(
229+
'skip_detailed_reports',
230+
flags=['--skip-detailed-reports'],
231+
field_type=ConfigPrimitive(bool),
232+
parser_args={'action': 'store_true'},
233+
default_value=DEFAULT_SKIP_DETAILED_REPORTS,
234+
description=
235+
"Skips the generation of detailed summary reports and tables."))
226236

227237
self._add_repository_configs()
228238
self._add_client_configs()

model_analyzer/config/input/config_defaults.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
DEFAULT_LOG_LEVEL = 'INFO'
3434
DEFAULT_GPUS = 'all'
3535
DEFAULT_SKIP_SUMMARY_REPORTS = False
36+
DEFAULT_SKIP_DETAILED_REPORTS = False
3637
DEFAULT_OUTPUT_MODEL_REPOSITORY = os.path.join(os.getcwd(),
3738
'output_model_repository')
3839
DEFAULT_OVERRIDE_OUTPUT_REPOSITORY_FLAG = False

qa/L0_profile/test.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ MODEL_ANALYZER_BASE_ARGS="$MODEL_ANALYZER_BASE_ARGS --output-model-repository-pa
5353
MODEL_ANALYZER_BASE_ARGS="$MODEL_ANALYZER_BASE_ARGS --filename-server-only=$FILENAME_SERVER_ONLY"
5454
MODEL_ANALYZER_BASE_ARGS="$MODEL_ANALYZER_BASE_ARGS --filename-model-inference=$FILENAME_INFERENCE_MODEL --filename-model-gpu=$FILENAME_GPU_MODEL"
5555
MODEL_ANALYZER_ARGS="$MODEL_ANALYZER_BASE_ARGS -e $EXPORT_PATH --checkpoint-directory $CHECKPOINT_DIRECTORY"
56+
MODEL_ANALYZER_ARGS="$MODEL_ANALYZER_BASE_ARGS --skip-summary-reports"
5657
MODEL_ANALYZER_SUBCOMMAND="profile"
5758

5859
run_analyzer

tests/test_analyzer.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ def mock_get_list_of_models(self):
6464
_create_metrics_manager=MagicMock(),
6565
_create_model_manager=MagicMock(),
6666
_get_server_only_metrics=MagicMock(),
67-
_profile_models=MagicMock())
67+
_profile_models=MagicMock(),
68+
_check_for_perf_analyzer_errors=MagicMock())
6869
def test_profile_skip_summary_reports(self, **mocks):
6970
"""
7071
Tests when the skip_summary_reports config option is turned on,

tests/test_cli.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ def get_test_options():
6767
OptionStruct("bool", "profile","--reload-model-disable"),
6868
OptionStruct("bool", "profile","--early-exit-enable"),
6969
OptionStruct("bool", "profile","--skip-summary-reports"),
70+
OptionStruct("bool", "profile","--skip-detailed-reports"),
7071
#Int/Float options
7172
# Options format:
7273
# (int/float, MA step, long_option, short_option, test_value, expected_default_value)

0 commit comments

Comments
 (0)