triton-model-analyzer 1.48.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (204) hide show
  1. model_analyzer/__init__.py +15 -0
  2. model_analyzer/analyzer.py +448 -0
  3. model_analyzer/cli/__init__.py +15 -0
  4. model_analyzer/cli/cli.py +193 -0
  5. model_analyzer/config/__init__.py +15 -0
  6. model_analyzer/config/generate/__init__.py +15 -0
  7. model_analyzer/config/generate/automatic_model_config_generator.py +164 -0
  8. model_analyzer/config/generate/base_model_config_generator.py +352 -0
  9. model_analyzer/config/generate/brute_plus_binary_parameter_search_run_config_generator.py +164 -0
  10. model_analyzer/config/generate/brute_run_config_generator.py +154 -0
  11. model_analyzer/config/generate/concurrency_sweeper.py +75 -0
  12. model_analyzer/config/generate/config_generator_interface.py +52 -0
  13. model_analyzer/config/generate/coordinate.py +143 -0
  14. model_analyzer/config/generate/coordinate_data.py +86 -0
  15. model_analyzer/config/generate/generator_utils.py +116 -0
  16. model_analyzer/config/generate/manual_model_config_generator.py +187 -0
  17. model_analyzer/config/generate/model_config_generator_factory.py +92 -0
  18. model_analyzer/config/generate/model_profile_spec.py +74 -0
  19. model_analyzer/config/generate/model_run_config_generator.py +154 -0
  20. model_analyzer/config/generate/model_variant_name_manager.py +150 -0
  21. model_analyzer/config/generate/neighborhood.py +536 -0
  22. model_analyzer/config/generate/optuna_plus_concurrency_sweep_run_config_generator.py +141 -0
  23. model_analyzer/config/generate/optuna_run_config_generator.py +838 -0
  24. model_analyzer/config/generate/perf_analyzer_config_generator.py +312 -0
  25. model_analyzer/config/generate/quick_plus_concurrency_sweep_run_config_generator.py +130 -0
  26. model_analyzer/config/generate/quick_run_config_generator.py +753 -0
  27. model_analyzer/config/generate/run_config_generator_factory.py +329 -0
  28. model_analyzer/config/generate/search_config.py +112 -0
  29. model_analyzer/config/generate/search_dimension.py +73 -0
  30. model_analyzer/config/generate/search_dimensions.py +85 -0
  31. model_analyzer/config/generate/search_parameter.py +49 -0
  32. model_analyzer/config/generate/search_parameters.py +388 -0
  33. model_analyzer/config/input/__init__.py +15 -0
  34. model_analyzer/config/input/config_command.py +483 -0
  35. model_analyzer/config/input/config_command_profile.py +1747 -0
  36. model_analyzer/config/input/config_command_report.py +267 -0
  37. model_analyzer/config/input/config_defaults.py +236 -0
  38. model_analyzer/config/input/config_enum.py +83 -0
  39. model_analyzer/config/input/config_field.py +216 -0
  40. model_analyzer/config/input/config_list_generic.py +112 -0
  41. model_analyzer/config/input/config_list_numeric.py +151 -0
  42. model_analyzer/config/input/config_list_string.py +111 -0
  43. model_analyzer/config/input/config_none.py +71 -0
  44. model_analyzer/config/input/config_object.py +129 -0
  45. model_analyzer/config/input/config_primitive.py +81 -0
  46. model_analyzer/config/input/config_status.py +75 -0
  47. model_analyzer/config/input/config_sweep.py +83 -0
  48. model_analyzer/config/input/config_union.py +113 -0
  49. model_analyzer/config/input/config_utils.py +128 -0
  50. model_analyzer/config/input/config_value.py +243 -0
  51. model_analyzer/config/input/objects/__init__.py +15 -0
  52. model_analyzer/config/input/objects/config_model_profile_spec.py +325 -0
  53. model_analyzer/config/input/objects/config_model_report_spec.py +173 -0
  54. model_analyzer/config/input/objects/config_plot.py +198 -0
  55. model_analyzer/config/input/objects/config_protobuf_utils.py +101 -0
  56. model_analyzer/config/input/yaml_config_validator.py +82 -0
  57. model_analyzer/config/run/__init__.py +15 -0
  58. model_analyzer/config/run/model_run_config.py +313 -0
  59. model_analyzer/config/run/run_config.py +168 -0
  60. model_analyzer/constants.py +76 -0
  61. model_analyzer/device/__init__.py +15 -0
  62. model_analyzer/device/device.py +24 -0
  63. model_analyzer/device/gpu_device.py +87 -0
  64. model_analyzer/device/gpu_device_factory.py +248 -0
  65. model_analyzer/entrypoint.py +307 -0
  66. model_analyzer/log_formatter.py +65 -0
  67. model_analyzer/model_analyzer_exceptions.py +24 -0
  68. model_analyzer/model_manager.py +255 -0
  69. model_analyzer/monitor/__init__.py +15 -0
  70. model_analyzer/monitor/cpu_monitor.py +69 -0
  71. model_analyzer/monitor/dcgm/DcgmDiag.py +191 -0
  72. model_analyzer/monitor/dcgm/DcgmFieldGroup.py +83 -0
  73. model_analyzer/monitor/dcgm/DcgmGroup.py +815 -0
  74. model_analyzer/monitor/dcgm/DcgmHandle.py +141 -0
  75. model_analyzer/monitor/dcgm/DcgmJsonReader.py +69 -0
  76. model_analyzer/monitor/dcgm/DcgmReader.py +623 -0
  77. model_analyzer/monitor/dcgm/DcgmStatus.py +57 -0
  78. model_analyzer/monitor/dcgm/DcgmSystem.py +412 -0
  79. model_analyzer/monitor/dcgm/__init__.py +15 -0
  80. model_analyzer/monitor/dcgm/common/__init__.py +13 -0
  81. model_analyzer/monitor/dcgm/common/dcgm_client_cli_parser.py +194 -0
  82. model_analyzer/monitor/dcgm/common/dcgm_client_main.py +86 -0
  83. model_analyzer/monitor/dcgm/dcgm_agent.py +887 -0
  84. model_analyzer/monitor/dcgm/dcgm_collectd_plugin.py +369 -0
  85. model_analyzer/monitor/dcgm/dcgm_errors.py +395 -0
  86. model_analyzer/monitor/dcgm/dcgm_field_helpers.py +546 -0
  87. model_analyzer/monitor/dcgm/dcgm_fields.py +815 -0
  88. model_analyzer/monitor/dcgm/dcgm_fields_collectd.py +671 -0
  89. model_analyzer/monitor/dcgm/dcgm_fields_internal.py +29 -0
  90. model_analyzer/monitor/dcgm/dcgm_fluentd.py +45 -0
  91. model_analyzer/monitor/dcgm/dcgm_monitor.py +138 -0
  92. model_analyzer/monitor/dcgm/dcgm_prometheus.py +326 -0
  93. model_analyzer/monitor/dcgm/dcgm_structs.py +2357 -0
  94. model_analyzer/monitor/dcgm/dcgm_telegraf.py +65 -0
  95. model_analyzer/monitor/dcgm/dcgm_value.py +151 -0
  96. model_analyzer/monitor/dcgm/dcgmvalue.py +155 -0
  97. model_analyzer/monitor/dcgm/denylist_recommendations.py +573 -0
  98. model_analyzer/monitor/dcgm/pydcgm.py +47 -0
  99. model_analyzer/monitor/monitor.py +143 -0
  100. model_analyzer/monitor/remote_monitor.py +137 -0
  101. model_analyzer/output/__init__.py +15 -0
  102. model_analyzer/output/file_writer.py +63 -0
  103. model_analyzer/output/output_writer.py +42 -0
  104. model_analyzer/perf_analyzer/__init__.py +15 -0
  105. model_analyzer/perf_analyzer/genai_perf_config.py +206 -0
  106. model_analyzer/perf_analyzer/perf_analyzer.py +882 -0
  107. model_analyzer/perf_analyzer/perf_config.py +479 -0
  108. model_analyzer/plots/__init__.py +15 -0
  109. model_analyzer/plots/detailed_plot.py +266 -0
  110. model_analyzer/plots/plot_manager.py +224 -0
  111. model_analyzer/plots/simple_plot.py +213 -0
  112. model_analyzer/record/__init__.py +15 -0
  113. model_analyzer/record/gpu_record.py +68 -0
  114. model_analyzer/record/metrics_manager.py +887 -0
  115. model_analyzer/record/record.py +280 -0
  116. model_analyzer/record/record_aggregator.py +256 -0
  117. model_analyzer/record/types/__init__.py +15 -0
  118. model_analyzer/record/types/cpu_available_ram.py +93 -0
  119. model_analyzer/record/types/cpu_used_ram.py +93 -0
  120. model_analyzer/record/types/gpu_free_memory.py +96 -0
  121. model_analyzer/record/types/gpu_power_usage.py +107 -0
  122. model_analyzer/record/types/gpu_total_memory.py +96 -0
  123. model_analyzer/record/types/gpu_used_memory.py +96 -0
  124. model_analyzer/record/types/gpu_utilization.py +108 -0
  125. model_analyzer/record/types/inter_token_latency_avg.py +60 -0
  126. model_analyzer/record/types/inter_token_latency_base.py +74 -0
  127. model_analyzer/record/types/inter_token_latency_max.py +60 -0
  128. model_analyzer/record/types/inter_token_latency_min.py +60 -0
  129. model_analyzer/record/types/inter_token_latency_p25.py +60 -0
  130. model_analyzer/record/types/inter_token_latency_p50.py +60 -0
  131. model_analyzer/record/types/inter_token_latency_p75.py +60 -0
  132. model_analyzer/record/types/inter_token_latency_p90.py +60 -0
  133. model_analyzer/record/types/inter_token_latency_p95.py +60 -0
  134. model_analyzer/record/types/inter_token_latency_p99.py +60 -0
  135. model_analyzer/record/types/output_token_throughput.py +105 -0
  136. model_analyzer/record/types/perf_client_response_wait.py +97 -0
  137. model_analyzer/record/types/perf_client_send_recv.py +97 -0
  138. model_analyzer/record/types/perf_latency.py +111 -0
  139. model_analyzer/record/types/perf_latency_avg.py +60 -0
  140. model_analyzer/record/types/perf_latency_base.py +74 -0
  141. model_analyzer/record/types/perf_latency_p90.py +60 -0
  142. model_analyzer/record/types/perf_latency_p95.py +60 -0
  143. model_analyzer/record/types/perf_latency_p99.py +60 -0
  144. model_analyzer/record/types/perf_server_compute_infer.py +97 -0
  145. model_analyzer/record/types/perf_server_compute_input.py +97 -0
  146. model_analyzer/record/types/perf_server_compute_output.py +97 -0
  147. model_analyzer/record/types/perf_server_queue.py +97 -0
  148. model_analyzer/record/types/perf_throughput.py +105 -0
  149. model_analyzer/record/types/time_to_first_token_avg.py +60 -0
  150. model_analyzer/record/types/time_to_first_token_base.py +74 -0
  151. model_analyzer/record/types/time_to_first_token_max.py +60 -0
  152. model_analyzer/record/types/time_to_first_token_min.py +60 -0
  153. model_analyzer/record/types/time_to_first_token_p25.py +60 -0
  154. model_analyzer/record/types/time_to_first_token_p50.py +60 -0
  155. model_analyzer/record/types/time_to_first_token_p75.py +60 -0
  156. model_analyzer/record/types/time_to_first_token_p90.py +60 -0
  157. model_analyzer/record/types/time_to_first_token_p95.py +60 -0
  158. model_analyzer/record/types/time_to_first_token_p99.py +60 -0
  159. model_analyzer/reports/__init__.py +15 -0
  160. model_analyzer/reports/html_report.py +195 -0
  161. model_analyzer/reports/pdf_report.py +50 -0
  162. model_analyzer/reports/report.py +86 -0
  163. model_analyzer/reports/report_factory.py +62 -0
  164. model_analyzer/reports/report_manager.py +1376 -0
  165. model_analyzer/reports/report_utils.py +42 -0
  166. model_analyzer/result/__init__.py +15 -0
  167. model_analyzer/result/constraint_manager.py +150 -0
  168. model_analyzer/result/model_config_measurement.py +354 -0
  169. model_analyzer/result/model_constraints.py +105 -0
  170. model_analyzer/result/parameter_search.py +246 -0
  171. model_analyzer/result/result_manager.py +430 -0
  172. model_analyzer/result/result_statistics.py +159 -0
  173. model_analyzer/result/result_table.py +217 -0
  174. model_analyzer/result/result_table_manager.py +646 -0
  175. model_analyzer/result/result_utils.py +42 -0
  176. model_analyzer/result/results.py +277 -0
  177. model_analyzer/result/run_config_measurement.py +658 -0
  178. model_analyzer/result/run_config_result.py +210 -0
  179. model_analyzer/result/run_config_result_comparator.py +110 -0
  180. model_analyzer/result/sorted_results.py +151 -0
  181. model_analyzer/state/__init__.py +15 -0
  182. model_analyzer/state/analyzer_state.py +76 -0
  183. model_analyzer/state/analyzer_state_manager.py +215 -0
  184. model_analyzer/triton/__init__.py +15 -0
  185. model_analyzer/triton/client/__init__.py +15 -0
  186. model_analyzer/triton/client/client.py +234 -0
  187. model_analyzer/triton/client/client_factory.py +57 -0
  188. model_analyzer/triton/client/grpc_client.py +104 -0
  189. model_analyzer/triton/client/http_client.py +107 -0
  190. model_analyzer/triton/model/__init__.py +15 -0
  191. model_analyzer/triton/model/model_config.py +556 -0
  192. model_analyzer/triton/model/model_config_variant.py +29 -0
  193. model_analyzer/triton/server/__init__.py +15 -0
  194. model_analyzer/triton/server/server.py +76 -0
  195. model_analyzer/triton/server/server_config.py +269 -0
  196. model_analyzer/triton/server/server_docker.py +229 -0
  197. model_analyzer/triton/server/server_factory.py +306 -0
  198. model_analyzer/triton/server/server_local.py +158 -0
  199. triton_model_analyzer-1.48.0.dist-info/METADATA +52 -0
  200. triton_model_analyzer-1.48.0.dist-info/RECORD +204 -0
  201. triton_model_analyzer-1.48.0.dist-info/WHEEL +5 -0
  202. triton_model_analyzer-1.48.0.dist-info/entry_points.txt +2 -0
  203. triton_model_analyzer-1.48.0.dist-info/licenses/LICENSE +67 -0
  204. triton_model_analyzer-1.48.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Copyright 2020-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
@@ -0,0 +1,448 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Copyright 2021-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ import logging
18
+ import sys
19
+ from copy import deepcopy
20
+ from typing import Dict, List, Optional, Union
21
+
22
+ from model_analyzer.cli.cli import CLI
23
+ from model_analyzer.config.generate.base_model_config_generator import (
24
+ BaseModelConfigGenerator,
25
+ )
26
+ from model_analyzer.config.generate.model_profile_spec import ModelProfileSpec
27
+ from model_analyzer.config.generate.search_parameters import SearchParameters
28
+ from model_analyzer.constants import LOGGER_NAME, PA_ERROR_LOG_FILENAME
29
+ from model_analyzer.state.analyzer_state_manager import AnalyzerStateManager
30
+ from model_analyzer.triton.server.server import TritonServer
31
+
32
+ from .config.input.config_command_profile import ConfigCommandProfile
33
+ from .config.input.config_command_report import ConfigCommandReport
34
+ from .config.input.config_defaults import DEFAULT_CHECKPOINT_DIRECTORY
35
+ from .device.gpu_device import GPUDevice
36
+ from .model_analyzer_exceptions import TritonModelAnalyzerException
37
+ from .model_manager import ModelManager
38
+ from .record.metrics_manager import MetricsManager
39
+ from .reports.report_manager import ReportManager
40
+ from .result.constraint_manager import ConstraintManager
41
+ from .result.result_manager import ResultManager
42
+ from .result.result_table_manager import ResultTableManager
43
+ from .triton.client.client import TritonClient
44
+
45
+ logger = logging.getLogger(LOGGER_NAME)
46
+
47
+
48
+ class Analyzer:
49
+ """
50
+ A class responsible for coordinating the various components of the
51
+ model_analyzer. Configured with metrics to monitor, exposes profiling and
52
+ result writing methods.
53
+ """
54
+
55
+ def __init__(
56
+ self,
57
+ config: Union[ConfigCommandProfile, ConfigCommandReport],
58
+ server: TritonServer,
59
+ state_manager: AnalyzerStateManager,
60
+ checkpoint_required: bool,
61
+ ):
62
+ """
63
+ Parameters
64
+ ----------
65
+ config : ConfigCommandProfile or ConfigCommandReport
66
+ Model Analyzer config
67
+ server : TritonServer
68
+ Server handle
69
+ state_manager: AnalyzerStateManager
70
+ The object that maintains Model Analyzer State
71
+ checkpoint_required : bool
72
+ If true, an existing checkpoint is required to run MA
73
+ """
74
+
75
+ self._config = config
76
+ self._server = server
77
+ self._state_manager = state_manager
78
+ state_manager.load_checkpoint(checkpoint_required)
79
+
80
+ self._constraint_manager = ConstraintManager(self._config)
81
+ self._result_manager = ResultManager(
82
+ config=config,
83
+ state_manager=self._state_manager,
84
+ constraint_manager=self._constraint_manager,
85
+ )
86
+
87
+ self._search_parameters: Dict[str, SearchParameters] = {}
88
+ self._composing_search_parameters: Dict[str, SearchParameters] = {}
89
+
90
+ def profile(
91
+ self, client: TritonClient, gpus: List[GPUDevice], mode: str, verbose: bool
92
+ ) -> None:
93
+ """
94
+ Subcommand: PROFILE
95
+
96
+ Creates a RunConfigGenerator to generate RunConfigs, and then
97
+ profiles each RunConfig on Perf Analyzer and gathers the resulting
98
+ measurements.
99
+
100
+ Each RunConfig contains one or more (in the case of concurrent multi-model)
101
+ ModelRunConfigs, each of which contain a ModelConfig and a PerfAnalyzerConfig
102
+
103
+ Parameters
104
+ ----------
105
+ client : TritonClient
106
+ Instance used to load/unload models
107
+ gpus: List of GPUDevices
108
+ The gpus being used to profile
109
+
110
+ Raises
111
+ ------
112
+ TritonModelAnalyzerException
113
+ """
114
+
115
+ if not isinstance(self._config, ConfigCommandProfile):
116
+ raise TritonModelAnalyzerException(
117
+ f"Expected config of type {ConfigCommandProfile},"
118
+ " got {type(self._config)}."
119
+ )
120
+
121
+ self._create_metrics_manager(client, gpus)
122
+ self._create_model_manager(client, gpus)
123
+ self._populate_search_parameters(client, gpus)
124
+ self._populate_composing_search_parameters(client, gpus)
125
+
126
+ if self._config.triton_launch_mode == "remote":
127
+ self._warn_if_other_models_loaded_on_remote_server(client)
128
+
129
+ if self._config.model_repository or self._config.triton_launch_mode == "remote":
130
+ self._get_server_only_metrics(client, gpus)
131
+ self._profile_models()
132
+
133
+ # The message is in interrupt_handler(), so we can just exit
134
+ if self._state_manager.exiting():
135
+ sys.exit(1)
136
+
137
+ logger.info(self._get_profile_complete_string())
138
+ logger.info("")
139
+ elif self._state_manager.starting_fresh_run():
140
+ raise TritonModelAnalyzerException(
141
+ "No model repository specified and no checkpoint found. Please either specify a model repository (-m) or load a checkpoint (--checkpoint-directory)."
142
+ )
143
+
144
+ if not self._config.skip_summary_reports:
145
+ self._create_summary_tables(verbose)
146
+ self._create_summary_reports(mode)
147
+ self._create_detailed_reports(mode)
148
+
149
+ self._check_for_perf_analyzer_errors()
150
+
151
+ def report(self, mode: str) -> None:
152
+ """
153
+ Subcommand: REPORT
154
+
155
+ Generates detailed information on
156
+ one or more model configs
157
+
158
+ Parameters
159
+ ----------
160
+ mode : str
161
+ Global mode that the analyzer is running on
162
+ """
163
+
164
+ if not isinstance(self._config, ConfigCommandReport):
165
+ raise TritonModelAnalyzerException(
166
+ f"Expected config of type {ConfigCommandReport}, got {type(self._config)}."
167
+ )
168
+
169
+ gpu_info = self._state_manager.get_state_variable("MetricsManager.gpus")
170
+ if not gpu_info:
171
+ gpu_info = {}
172
+ self._report_manager = ReportManager(
173
+ mode=mode,
174
+ config=self._config,
175
+ result_manager=self._result_manager,
176
+ gpu_info=gpu_info,
177
+ constraint_manager=self._constraint_manager,
178
+ )
179
+
180
+ if self._multiple_models_in_report_model_config():
181
+ raise TritonModelAnalyzerException(
182
+ "Model Analyzer does not support detailed reporting for multi-model runs.\n"
183
+ "If you are trying to generate detailed reports for different sequentially profiled models you must run "
184
+ "the report command for each model separately."
185
+ )
186
+
187
+ self._report_manager.create_detailed_reports()
188
+ self._report_manager.export_detailed_reports()
189
+
190
+ def _create_metrics_manager(self, client, gpus):
191
+ self._metrics_manager = MetricsManager(
192
+ config=self._config,
193
+ client=client,
194
+ server=self._server,
195
+ gpus=gpus,
196
+ result_manager=self._result_manager,
197
+ state_manager=self._state_manager,
198
+ )
199
+
200
+ def _create_model_manager(self, client, gpus):
201
+ self._model_manager = ModelManager(
202
+ config=self._config,
203
+ gpus=gpus,
204
+ client=client,
205
+ server=self._server,
206
+ result_manager=self._result_manager,
207
+ metrics_manager=self._metrics_manager,
208
+ state_manager=self._state_manager,
209
+ constraint_manager=self._constraint_manager,
210
+ search_parameters=self._search_parameters,
211
+ composing_search_parameters=self._composing_search_parameters,
212
+ )
213
+
214
+ def _get_server_only_metrics(self, client, gpus):
215
+ if self._config.triton_launch_mode != "c_api":
216
+ if not self._state_manager._starting_fresh_run:
217
+ if self._config.dcgm_disable:
218
+ logger.info(
219
+ "DCGM is disabled - cannot verify that GPU devices match checkpoint"
220
+ )
221
+ elif self._do_checkpoint_gpus_match(gpus):
222
+ logger.info(
223
+ "GPU devices match checkpoint - skipping server metric acquisition"
224
+ )
225
+ return
226
+ elif gpus is not None:
227
+ raise TritonModelAnalyzerException(
228
+ "GPU devices do not match checkpoint - Remove checkpoint file and rerun profile"
229
+ )
230
+
231
+ logger.info("Profiling server only metrics...")
232
+ self._server.start()
233
+ client.wait_for_server_ready(
234
+ num_retries=self._config.client_max_retries,
235
+ log_file=self._server.log_file(),
236
+ )
237
+ self._metrics_manager.profile_server()
238
+ self._server.stop()
239
+
240
+ def _profile_models(self):
241
+ models = self._config.profile_models
242
+
243
+ if self._should_profile_multiple_models_concurrently():
244
+ # Profile all models concurrently
245
+ try:
246
+ self._model_manager.run_models(models=models)
247
+ finally:
248
+ self._state_manager.save_checkpoint()
249
+ else:
250
+ # Profile each model, save state after each
251
+ for model in models:
252
+ if self._state_manager.exiting():
253
+ break
254
+ try:
255
+ self._model_manager.run_models(models=[model])
256
+ finally:
257
+ self._state_manager.save_checkpoint()
258
+
259
+ def _create_summary_tables(self, verbose: bool) -> None:
260
+ self._result_table_manager = ResultTableManager(
261
+ self._config, self._result_manager
262
+ )
263
+ self._result_table_manager.create_tables()
264
+ self._result_table_manager.tabulate_results()
265
+ self._result_table_manager.export_results()
266
+
267
+ if verbose:
268
+ self._result_table_manager.write_results()
269
+
270
+ def _create_summary_reports(self, mode: str) -> None:
271
+ gpu_info = self._state_manager.get_state_variable("MetricsManager.gpus")
272
+ if not gpu_info:
273
+ gpu_info = {}
274
+
275
+ self._report_manager = ReportManager(
276
+ mode=mode,
277
+ config=self._config,
278
+ gpu_info=gpu_info,
279
+ result_manager=self._result_manager,
280
+ constraint_manager=self._constraint_manager,
281
+ )
282
+
283
+ self._report_manager.create_summaries()
284
+ self._report_manager.export_summaries()
285
+
286
+ def _should_profile_multiple_models_concurrently(self):
287
+ return (
288
+ self._config.run_config_profile_models_concurrently_enable
289
+ and len(self._config.profile_models) > 1
290
+ )
291
+
292
+ def _get_profile_complete_string(self):
293
+ profiled_model_list = self._state_manager.get_state_variable(
294
+ "ResultManager.results"
295
+ ).get_list_of_models()
296
+ num_profiled_configs = self._get_num_profiled_configs()
297
+
298
+ return (
299
+ f"Profile complete. Profiled {num_profiled_configs} "
300
+ f"configurations for models: {profiled_model_list}"
301
+ )
302
+
303
+ def _get_num_profiled_configs(self):
304
+ return sum(
305
+ [
306
+ len(x)
307
+ for x in self._state_manager.get_state_variable(
308
+ "ResultManager.results"
309
+ ).get_list_of_model_config_measurement_tuples()
310
+ ]
311
+ )
312
+
313
+ def _get_report_command_help_string(self, model_name: str) -> str:
314
+ top_n_model_config_names = self._get_top_n_model_config_names(
315
+ n=self._config.num_configs_per_model, model_name=model_name
316
+ )
317
+ return (
318
+ f"To generate detailed reports for the "
319
+ f"{len(top_n_model_config_names)} best {model_name} configurations, run "
320
+ f"`{self._get_report_command_string(top_n_model_config_names)}`"
321
+ )
322
+
323
+ def _run_report_command(self, model_name: str, mode: str) -> None:
324
+ top_n_model_config_names = self._get_top_n_model_config_names(
325
+ n=self._config.num_configs_per_model, model_name=model_name
326
+ )
327
+ top_n_string = ",".join(top_n_model_config_names)
328
+ logger.info(
329
+ f"Generating detailed reports for the best configurations {top_n_string}:"
330
+ )
331
+
332
+ # [1:] removes 'model-analyzer' from the args
333
+ args = self._get_report_command_string(top_n_model_config_names).split(" ")[1:]
334
+
335
+ original_profile_config = deepcopy(self._config)
336
+ self._config = self._create_report_config(args)
337
+ self.report(mode)
338
+ self._config = original_profile_config
339
+
340
+ def _get_report_command_string(self, top_n_model_config_names: List[str]) -> str:
341
+ report_command_string = (
342
+ f"model-analyzer report "
343
+ f"--report-model-configs "
344
+ f'{",".join(top_n_model_config_names)}'
345
+ )
346
+
347
+ if self._config.export_path is not None:
348
+ report_command_string += f" --export-path " f"{self._config.export_path}"
349
+
350
+ if self._config.config_file is not None:
351
+ report_command_string += f" --config-file " f"{self._config.config_file}"
352
+
353
+ if self._config.checkpoint_directory != DEFAULT_CHECKPOINT_DIRECTORY:
354
+ report_command_string += (
355
+ f" --checkpoint-directory " f"{self._config.checkpoint_directory}"
356
+ )
357
+
358
+ return report_command_string
359
+
360
+ def _get_top_n_model_config_names(
361
+ self, n: int = -1, model_name: Optional[str] = None
362
+ ) -> List[str]:
363
+ return [
364
+ x.run_config().model_variants_name()
365
+ for x in self._result_manager.top_n_results(n=n, model_name=model_name)
366
+ ]
367
+
368
+ def _do_checkpoint_gpus_match(self, gpus: dict) -> bool:
369
+ ckpt_data = self._result_manager.get_server_only_data()
370
+ ckpt_uuids = [ckpt_uuid for ckpt_uuid in ckpt_data.keys()]
371
+ gpu_uuids = [gpu._device_uuid for gpu in gpus]
372
+
373
+ return sorted(ckpt_uuids) == sorted(gpu_uuids)
374
+
375
+ def _multiple_models_in_report_model_config(self) -> bool:
376
+ model_config_names = [
377
+ report_model_config.model_config_name()
378
+ for report_model_config in self._config.report_model_configs
379
+ ]
380
+
381
+ model_names = [
382
+ BaseModelConfigGenerator.extract_model_name_from_variant_name(
383
+ model_config_name
384
+ )
385
+ for model_config_name in model_config_names
386
+ ]
387
+
388
+ return len(set(model_names)) > 1
389
+
390
+ def _check_for_perf_analyzer_errors(self) -> None:
391
+ if self._metrics_manager.encountered_perf_analyzer_error():
392
+ logger.warning(
393
+ f"Perf Analyzer encountered an error when profiling one or more configurations. "
394
+ f"See {self._config.export_path}/{PA_ERROR_LOG_FILENAME} for further details.\n"
395
+ )
396
+
397
+ def _create_detailed_reports(self, mode: str) -> None:
398
+ # TODO-TMA-650: Detailed reporting not supported for multi-model
399
+ if not self._config.run_config_profile_models_concurrently_enable:
400
+ for model in self._config.profile_models:
401
+ if not self._config.skip_detailed_reports:
402
+ self._run_report_command(model.model_name(), mode)
403
+ else:
404
+ logger.info(
405
+ self._get_report_command_help_string(model.model_name())
406
+ )
407
+
408
+ def _create_report_config(self, args: list) -> ConfigCommandReport:
409
+ config = ConfigCommandReport()
410
+ cli = CLI()
411
+ cli.add_subcommand(cmd="report", help="", config=config)
412
+ cli.parse(args)
413
+ return config
414
+
415
+ def _warn_if_other_models_loaded_on_remote_server(self, client):
416
+ repository_index = client.get_model_repository_index()
417
+ profile_model_names = [pm.model_name() for pm in self._config.profile_models]
418
+
419
+ model_names_loaded_on_server = []
420
+ for repository_item in repository_index:
421
+ if client.is_model_ready(repository_item["name"]):
422
+ model_names_loaded_on_server.append(repository_item["name"])
423
+
424
+ for model_name in model_names_loaded_on_server:
425
+ if model_name not in profile_model_names:
426
+ logger.warning(
427
+ f"A model not being profiled ({model_name}) is loaded on the remote Tritonserver. "
428
+ "This could impact the profile results."
429
+ )
430
+
431
+ def _populate_search_parameters(self, client, gpus):
432
+ for model in self._config.profile_models:
433
+ model_profile_spec = ModelProfileSpec(model, self._config, client, gpus)
434
+ self._search_parameters[model.model_name()] = SearchParameters(
435
+ config=self._config,
436
+ model=model_profile_spec,
437
+ is_bls_model=bool(self._config.bls_composing_models),
438
+ is_ensemble_model=model_profile_spec.is_ensemble(),
439
+ )
440
+
441
+ def _populate_composing_search_parameters(self, client, gpus):
442
+ for model in self._config.bls_composing_models:
443
+ model_profile_spec = ModelProfileSpec(model, self._config, client, gpus)
444
+ self._composing_search_parameters[model.model_name()] = SearchParameters(
445
+ config=self._config,
446
+ model=model_profile_spec,
447
+ is_composing_model=True,
448
+ )
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Copyright 2020-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
@@ -0,0 +1,193 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Copyright 2020-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ import logging
18
+ import sys
19
+ from argparse import SUPPRESS, ArgumentParser, Namespace
20
+ from typing import List, Optional, Tuple, Union
21
+
22
+ import importlib_metadata
23
+
24
+ from model_analyzer.config.input.config_command_profile import ConfigCommandProfile
25
+ from model_analyzer.config.input.config_command_report import ConfigCommandReport
26
+ from model_analyzer.constants import LOGGER_NAME, PACKAGE_NAME
27
+ from model_analyzer.model_analyzer_exceptions import TritonModelAnalyzerException
28
+
29
+ logger = logging.getLogger(LOGGER_NAME)
30
+
31
+
32
+ class CLI:
33
+ """
34
+ CLI class to parse the command line arguments
35
+ """
36
+
37
+ def __init__(self):
38
+ self._parser = ArgumentParser()
39
+ self._add_global_options()
40
+ self._subparsers = self._parser.add_subparsers(
41
+ help="Subcommands under Model Analyzer", dest="subcommand"
42
+ )
43
+
44
+ # Store subcommands, and their configs
45
+ self._subcommand_configs = {}
46
+
47
+ def _add_global_options(self):
48
+ """
49
+ Adds the Model Analyzer's global options
50
+ to the parser
51
+ """
52
+
53
+ self._parser.add_argument(
54
+ "-m",
55
+ "--mode",
56
+ type=str,
57
+ default="online",
58
+ choices=["online", "offline"],
59
+ help="Choose a preset configuration mode.",
60
+ )
61
+ self._parser.add_argument(
62
+ "--version", action="store_true", help="Show the Model Analyzer version."
63
+ )
64
+
65
+ def _add_global_options_to_subparser(self, subparser):
66
+ """
67
+ Adds global options to a subparser so they can be
68
+ used after the subcommand (e.g., 'model-analyzer profile -v')
69
+ """
70
+
71
+ subparser.add_argument(
72
+ "-q",
73
+ "--quiet",
74
+ action="store_true",
75
+ help="Suppress all output except for error messages.",
76
+ )
77
+ subparser.add_argument(
78
+ "-v",
79
+ "--verbose",
80
+ action="store_true",
81
+ help="Show detailed logs, messages and status.",
82
+ )
83
+
84
+ def add_subcommand(self, cmd, help, config=None):
85
+ """
86
+ Adds a subparser to the main parser representing
87
+ a command. Also adds the passed in config to
88
+ the subcommands dict to set its values upon parse.
89
+
90
+ Parameters
91
+ ----------
92
+ cmd : str
93
+ subcommand name
94
+ help: str
95
+ help string or description for the subcommand
96
+ config: Config
97
+ The config containing the arguments that are required
98
+ to be parsed for this subcommand.
99
+ """
100
+
101
+ subparser = self._subparsers.add_parser(cmd, help=help)
102
+
103
+ self._add_global_options_to_subparser(subparser)
104
+
105
+ if config:
106
+ self._add_config_arguments(subparser, config)
107
+ self._subcommand_configs[cmd] = config
108
+
109
+ def _add_config_arguments(self, subparser, config):
110
+ """
111
+ Add the CLI arguments from the config
112
+
113
+ Parameters
114
+ ----------
115
+ config : Config
116
+ Model Analyzer config object.
117
+ """
118
+ # configs is dictionary of config_fields objects from config_command_*
119
+ configs = config.get_config()
120
+ for config_field in configs.values():
121
+ parser_args = config_field.parser_args()
122
+
123
+ # Skip the non-CLI flags
124
+ if config_field.flags() is None:
125
+ continue
126
+
127
+ # 'store_true' and 'store_false' does not
128
+ # allow 'type' or 'choices' parameters
129
+ if "action" in parser_args and (
130
+ parser_args["action"] == "store_true"
131
+ or parser_args["action"] == "store_false"
132
+ ):
133
+ subparser.add_argument(
134
+ *config_field.flags(),
135
+ default=SUPPRESS,
136
+ help=config_field.description(),
137
+ **config_field.parser_args(),
138
+ )
139
+ else:
140
+ subparser.add_argument(
141
+ *config_field.flags(),
142
+ default=SUPPRESS,
143
+ choices=config_field.choices(),
144
+ help=config_field.description(),
145
+ type=config_field.cli_type(),
146
+ **config_field.parser_args(),
147
+ )
148
+
149
+ def _show_model_analyzer_version(self):
150
+ """
151
+ Displays the current version of Model Analyzer and exits.
152
+ """
153
+ try:
154
+ version = importlib_metadata.version(PACKAGE_NAME)
155
+ print(version)
156
+ sys.exit(0)
157
+ except importlib_metadata.PackageNotFoundError:
158
+ raise TritonModelAnalyzerException(f"Version information is not available")
159
+
160
+ def parse(
161
+ self, input_args: Optional[List] = None
162
+ ) -> Tuple[Namespace, Union[ConfigCommandProfile, ConfigCommandReport]]:
163
+ """
164
+ Parse CLI options using ArgumentParsers
165
+ and set config values.
166
+
167
+ Parameters
168
+ ----------
169
+ input_args: List
170
+ The list of arguments to be parsed
171
+ (if None then command line arguments will be used)
172
+
173
+ Returns
174
+ -------
175
+ args : Namespace
176
+ Object that contains the parse CLI commands
177
+ Used for the global options
178
+ config: CommandConfig
179
+ The config corresponding to the command being run,
180
+ already filled in with values from CLI or YAML.
181
+ """
182
+
183
+ args = self._parser.parse_args(input_args)
184
+
185
+ if args.version:
186
+ self._show_model_analyzer_version()
187
+
188
+ if args.subcommand is None:
189
+ self._parser.print_help()
190
+ self._parser.exit()
191
+ config = self._subcommand_configs[args.subcommand]
192
+ config.set_config_values(args)
193
+ return args, config
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Copyright 2021-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.