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,280 @@
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 importlib
18
+ import os
19
+ from abc import ABCMeta, abstractmethod
20
+ from statistics import mean
21
+ from typing import Dict
22
+
23
+ from model_analyzer.model_analyzer_exceptions import TritonModelAnalyzerException
24
+
25
+
26
+ class RecordType(ABCMeta):
27
+ """
28
+ A metaclass that holds the instantiated Record types
29
+ """
30
+
31
+ record_types: Dict[str, "RecordType"] = {}
32
+
33
+ def __new__(cls, name, base, namespace):
34
+ """
35
+ This function is called upon declaration of any classes of type
36
+ RecordType
37
+ """
38
+
39
+ record_type = super().__new__(cls, name, base, namespace)
40
+
41
+ # If record_type.tag is a string, register it here
42
+ if isinstance(record_type.tag, str):
43
+ cls.record_types[record_type.tag] = record_type
44
+ return record_type
45
+
46
+ @classmethod
47
+ def get(cls, tag):
48
+ """
49
+ Parameters
50
+ ----------
51
+ tag : str
52
+ tag that a record type has registered it classname with
53
+
54
+ Returns
55
+ -------
56
+ The class of type RecordType corresponding to the tag
57
+ """
58
+
59
+ if tag not in cls.record_types:
60
+ try:
61
+ importlib.import_module("model_analyzer.record.types.%s" % tag)
62
+ except ImportError as e:
63
+ print(e)
64
+ return cls.record_types[tag]
65
+
66
+ @classmethod
67
+ def get_all_record_types(cls):
68
+ """
69
+ Returns
70
+ -------
71
+ dict
72
+ keys are tags and values are
73
+ all the types that have this as a
74
+ metaclass
75
+ """
76
+
77
+ type_module_directory = os.path.join(
78
+ globals()["__spec__"].origin.rsplit("/", 1)[0], "types"
79
+ )
80
+ for filename in os.listdir(type_module_directory):
81
+ if filename != "__init__.py" and filename.endswith(".py"):
82
+ try:
83
+ importlib.import_module(
84
+ f"model_analyzer.record.types.{filename[:-3]}"
85
+ )
86
+ except AttributeError:
87
+ raise TritonModelAnalyzerException(
88
+ "Error retrieving all record types"
89
+ )
90
+ return cls.record_types
91
+
92
+
93
+ class Record(metaclass=RecordType):
94
+ """
95
+ This class is used for representing
96
+ records
97
+ """
98
+
99
+ def __init__(self, value, timestamp):
100
+ """
101
+ Parameters
102
+ ----------
103
+ value : float or int
104
+ The value of the GPU metrtic
105
+ timestamp : int
106
+ The timestamp for the record in nanoseconds
107
+ """
108
+
109
+ assert type(value) is float or type(value) is int
110
+ assert type(timestamp) is int
111
+
112
+ self._value = value
113
+ self._timestamp = timestamp
114
+
115
+ @staticmethod
116
+ def aggregation_function():
117
+ """
118
+ The function that is used to aggregate
119
+ this type of record
120
+
121
+ Returns
122
+ -------
123
+ callable()
124
+ [Records] -> Record
125
+ """
126
+
127
+ return lambda records: max(records, key=lambda r: r.value())
128
+
129
+ @staticmethod
130
+ def value_function():
131
+ """
132
+ Returns the average value from a list
133
+
134
+ Returns
135
+ -------
136
+ Average value of the list
137
+ """
138
+ return mean
139
+
140
+ @staticmethod
141
+ @abstractmethod
142
+ def header(aggregation_tag=False):
143
+ """
144
+ Parameters
145
+ ----------
146
+ aggregation_tag : boolean
147
+ An optional tag that may be displayed as part of the header
148
+ indicating that this record has been aggregated using max, min or
149
+ average etc.
150
+
151
+ Returns
152
+ -------
153
+ str
154
+ The full name of the
155
+ metric.
156
+ """
157
+
158
+ @property
159
+ @abstractmethod
160
+ def tag(self):
161
+ """
162
+ Returns
163
+ -------
164
+ str
165
+ the name tag of the record type.
166
+ """
167
+
168
+ def to_dict(self):
169
+ return (self.tag, self.__dict__)
170
+
171
+ @classmethod
172
+ def from_dict(cls, record_dict):
173
+ record = cls(0)
174
+ for key in ["_value", "_timestamp"]:
175
+ if key in record_dict:
176
+ setattr(record, key, record_dict[key])
177
+ return record
178
+
179
+ def value(self):
180
+ """
181
+ This method returns the value of recorded metric
182
+
183
+ Returns
184
+ -------
185
+ float
186
+ value of the metric
187
+ """
188
+
189
+ return self._value
190
+
191
+ def timestamp(self):
192
+ """
193
+ This method should return the time at which the record was created.
194
+
195
+ Returns
196
+ -------
197
+ float
198
+ timestamp passed in during
199
+ record creation
200
+ """
201
+
202
+ return self._timestamp
203
+
204
+ def __mul__(self, other):
205
+ """
206
+ Defines left multiplication for records with floats or ints.
207
+
208
+ Returns
209
+ -------
210
+ Record
211
+ """
212
+
213
+ if isinstance(other, (int, float)):
214
+ return self.__class__(value=(self.value() * other))
215
+ else:
216
+ raise TypeError
217
+
218
+ def __rmul__(self, other):
219
+ """
220
+ Defines right multiplication
221
+ """
222
+
223
+ return self.__mul__(other)
224
+
225
+ def __truediv__(self, other):
226
+ """
227
+ Defines left multiplication for records with floats or ints
228
+
229
+ Returns
230
+ -------
231
+ Record
232
+ """
233
+
234
+ if isinstance(other, (int, float)):
235
+ return self.__class__(value=(self.value() / other))
236
+
237
+ else:
238
+ raise TypeError
239
+
240
+ @abstractmethod
241
+ def _positive_is_better(self) -> bool:
242
+ """
243
+ Returns a bool indicating if a larger positive value is better
244
+ for a given record type
245
+ """
246
+
247
+ def calculate_percentage_gain(self, other: "Record") -> float:
248
+ """
249
+ Calculates percentage gain between records
250
+ """
251
+
252
+ # When increasing values are better gain is based on the original value (other):
253
+ # example: 200 vs. 100 is (200 - 100) / 100 = 100%
254
+ # example: 100 vs. 200 is (100 - 200) / 200 = -50%
255
+ if self._positive_is_better():
256
+ return ((self.value() - other.value()) / other.value()) * 100
257
+
258
+ # When decreasing values are better gain is based on the new value (self):
259
+ # example: 100 vs. 200 is (200 - 100) / 100 = 100%
260
+ # example: 200 vs. 100 is (100 - 200) / 200 = -50%
261
+ else:
262
+ return ((other.value() - self.value()) / self.value()) * 100
263
+
264
+
265
+ class IncreasingRecord(Record):
266
+ """
267
+ Record where an increasing positive value is better
268
+ """
269
+
270
+ def _positive_is_better(self) -> bool:
271
+ return True
272
+
273
+
274
+ class DecreasingRecord(Record):
275
+ """
276
+ Record where an increasing positive value is worse
277
+ """
278
+
279
+ def _positive_is_better(self) -> bool:
280
+ return False
@@ -0,0 +1,256 @@
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 itertools
18
+ from collections import defaultdict
19
+
20
+ from model_analyzer.model_analyzer_exceptions import TritonModelAnalyzerException
21
+ from model_analyzer.record.record import Record
22
+
23
+
24
+ class RecordAggregator:
25
+ """
26
+ Stores a collection of Record objects.
27
+ """
28
+
29
+ def __init__(self):
30
+ self._records = defaultdict(list)
31
+
32
+ def insert(self, record):
33
+ """
34
+ Insert a record into the RecordAggregator
35
+
36
+ Parameters
37
+ ----------
38
+ record : Record
39
+ A record to be inserted
40
+ """
41
+
42
+ if isinstance(record, Record):
43
+ record_type = type(record)
44
+ self._records[record_type].append(record)
45
+ else:
46
+ raise TritonModelAnalyzerException(
47
+ "Can only add objects of type 'Record' to RecordAggregator"
48
+ )
49
+
50
+ def insert_all(self, record_list):
51
+ """
52
+ Insert records from a list of records
53
+ into the RecordAggregator
54
+
55
+ Parameters
56
+ ----------
57
+ record_list : List of Records
58
+ The records to insert
59
+ """
60
+
61
+ for record in record_list:
62
+ self.insert(record)
63
+
64
+ def add_key(self, record_type, records):
65
+ """
66
+ Adds or replaces all the records of a given record_type with the new
67
+ records
68
+
69
+ Parameters
70
+ ----------
71
+ record_type : Record
72
+ record_type to add to the records.
73
+ records : list
74
+ List of new records to be added.
75
+ """
76
+
77
+ self._records[record_type] = records
78
+
79
+ def filter_records(self, record_types=None, filters=None):
80
+ """
81
+ Get records that satisfy the given list of criteria.
82
+
83
+ Parameters
84
+ ----------
85
+
86
+ record_types : list of types of Records
87
+ the types of the records we are
88
+ imposing the filter criteria on.
89
+
90
+ filters : list of callables
91
+ conditions that determine whether
92
+ a given record should be returned.
93
+ If no filters specified, all records
94
+ of types specified by record_types will be
95
+ returned.
96
+ Note : This must be of the same length
97
+ as the list of record_types, or omitted.
98
+
99
+ Returns
100
+ -------
101
+ RecordAggregator
102
+ Returns a new RecordAggregator containing the filtered
103
+ records
104
+ """
105
+
106
+ filtered_records = RecordAggregator()
107
+ if not record_types and not filters:
108
+ for record_type, records in self._records.items():
109
+ filtered_records.add_key(record_type, records)
110
+ return filtered_records
111
+
112
+ if record_types and not filters:
113
+ try:
114
+ for record_type in record_types:
115
+ filtered_records.add_key(record_type, self._records[record_type])
116
+ return filtered_records
117
+ except KeyError as k:
118
+ raise TritonModelAnalyzerException(
119
+ f"Record type '{k.header()}' not found in this RecordAggregator"
120
+ )
121
+ if filters and not record_types:
122
+ raise TritonModelAnalyzerException(
123
+ "Must specify the record types corresponding to each filter criterion."
124
+ )
125
+ if len(record_types) != len(filters):
126
+ raise TritonModelAnalyzerException(
127
+ "Must specify the same number of record types as filter criteria."
128
+ )
129
+
130
+ # Remove records that do not satisfy criteria
131
+ for h, f in zip(record_types, filters):
132
+ for record in self._records[h]:
133
+ if f(record):
134
+ filtered_records.insert(record)
135
+
136
+ return filtered_records
137
+
138
+ def groupby(self, record_types, groupby_criterion):
139
+ """
140
+ Group all the records of a certain type together if they have the
141
+ same value for a given groupbby criteria.
142
+
143
+ Parameters
144
+ ----------
145
+ record_types : list
146
+ A list of record type
147
+ groupby_criterion : callable
148
+ This callable will receive a single record as the argument and
149
+ must return the value that will be used for groupby
150
+
151
+ Returns
152
+ -------
153
+ dict
154
+ A dictionary of dictionaries where the first level keys are the
155
+ record type and the second level keys are unique values returned
156
+ by groupby_criteria and the values are the aggregated records.
157
+ """
158
+
159
+ field_values = {
160
+ record_type: set(
161
+ [groupby_criterion(record) for record in self._records[record_type]]
162
+ )
163
+ for record_type in record_types
164
+ }
165
+ groupby_result = defaultdict(list)
166
+ for record_type in record_types:
167
+ groupby_result[record_type] = defaultdict(list)
168
+ for field_value in field_values[record_type]:
169
+ aggregated_result = self.filter_records(
170
+ record_types=[record_type],
171
+ filters=[lambda r: groupby_criterion(r) == field_value],
172
+ ).aggregate(record_types=[record_type])
173
+ groupby_result[record_type][field_value] = aggregated_result[
174
+ record_type
175
+ ]
176
+ return groupby_result
177
+
178
+ def record_types(self):
179
+ """
180
+ Returns
181
+ -------
182
+ list of str
183
+ a list of the types of records in this
184
+ RecordAgrregator
185
+ """
186
+
187
+ return list(self._records)
188
+
189
+ def total(self, record_type=None):
190
+ """
191
+ Get the total number of records in
192
+ the RecordAggregator
193
+
194
+ Parameters
195
+ ----------
196
+ record_type : a class name of type Record
197
+ The type of records to count,
198
+ if None, count all types
199
+
200
+ Returns
201
+ -------
202
+ int
203
+ number of records in
204
+ the RecordAggregator
205
+ """
206
+
207
+ if record_type:
208
+ if record_type not in self._records:
209
+ raise TritonModelAnalyzerException(
210
+ f"Record type '{record_type.header()}' not found in this RecordAggregator"
211
+ )
212
+ return len(self._records[record_type])
213
+ return sum(len(self._records[k]) for k in self._records)
214
+
215
+ def aggregate(self, record_types=None):
216
+ """
217
+ Parameters
218
+ ----------
219
+ record_types : List of Record types
220
+ The type of records to aggregate.
221
+ If None, aggregates all records
222
+
223
+ Returns
224
+ -------
225
+ dict
226
+ keys are requested record types
227
+ and values are the aggregated values
228
+ """
229
+
230
+ if not record_types:
231
+ record_types = self.record_types()
232
+ aggregated_records = {
233
+ record_type: record_type.aggregation_function()(self._records[record_type])
234
+ for record_type in record_types
235
+ }
236
+ return aggregated_records
237
+
238
+ def get_records(self):
239
+ """
240
+ Get all the records.
241
+
242
+ Returns
243
+ -------
244
+ dict
245
+ A dictionary where the keys are record types and the values are
246
+ an array of records with the specified type
247
+ """
248
+
249
+ return self._records
250
+
251
+ def _flatten_records(self, records):
252
+ """
253
+ Flatten the records array by joining all the arrays together.
254
+ """
255
+
256
+ return list(itertools.chain.from_iterable(records))
@@ -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,93 @@
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
+ from functools import total_ordering
18
+
19
+ from model_analyzer.record.record import IncreasingRecord
20
+
21
+
22
+ @total_ordering
23
+ class CPUAvailableRAM(IncreasingRecord):
24
+ """
25
+ The Available CPU memory
26
+ """
27
+
28
+ tag = "cpu_available_ram"
29
+
30
+ def __init__(self, value, timestamp=0):
31
+ """
32
+ Parameters
33
+ ----------
34
+ value : float
35
+ CPU free memory
36
+ timestamp : int
37
+ The timestamp for the record in nanoseconds
38
+ """
39
+
40
+ super().__init__(value, timestamp)
41
+
42
+ @staticmethod
43
+ def header(aggregation_tag=False):
44
+ """
45
+ Parameters
46
+ ----------
47
+ aggregation_tag: bool
48
+ An optional tag that may be displayed
49
+ as part of the header indicating that
50
+ this record has been aggregated using
51
+ max, min or average etc.
52
+
53
+ Returns
54
+ -------
55
+ str
56
+ The full name of the
57
+ metric.
58
+ """
59
+
60
+ return ("Max " if aggregation_tag else "") + "RAM Available (MB)"
61
+
62
+ def __eq__(self, other):
63
+ """
64
+ Allows checking for
65
+ equality between two records
66
+ """
67
+
68
+ return self.value() == other.value()
69
+
70
+ def __lt__(self, other):
71
+ """
72
+ Allows checking if
73
+ this record is less than
74
+ the other
75
+ """
76
+
77
+ return self.value() < other.value()
78
+
79
+ def __add__(self, other):
80
+ """
81
+ Allows adding two records together
82
+ to produce a brand new record.
83
+ """
84
+
85
+ return CPUAvailableRAM(value=(self.value() + other.value()))
86
+
87
+ def __sub__(self, other):
88
+ """
89
+ Allows subtracting two records together
90
+ to produce a brand new record.
91
+ """
92
+
93
+ return CPUAvailableRAM(value=(self.value() - other.value()))