99import glob
1010import numpy as np
1111import matplotlib
12+
1213matplotlib .use ("Agg" ) # Use non-interactive backend
1314import matplotlib .pyplot as plt
1415from datetime import datetime
@@ -60,7 +61,7 @@ def _extract_node_info(result):
6061 # Get hostname from system_info (preferred) or fall back to filename
6162 system_info = result .get ("system_info" , {})
6263 hostname = system_info .get ("hostname" , "" )
63-
64+
6465 # If no hostname in system_info, try extracting from filename
6566 if not hostname :
6667 filename = result .get ("_file" , "" )
@@ -69,10 +70,10 @@ def _extract_node_info(result):
6970 # Remove iteration number if present (_1, _2, etc.)
7071 if "_" in hostname and hostname .split ("_" )[- 1 ].isdigit ():
7172 hostname = "_" .join (hostname .split ("_" )[:- 1 ])
72-
73+
7374 # Determine if this is a dev node
7475 is_dev = hostname .endswith ("-dev" )
75-
76+
7677 return hostname , is_dev
7778
7879
@@ -101,16 +102,18 @@ def create_simple_performance_trends(results, output_dir):
101102 return
102103
103104 # Group results by node
104- node_performance = defaultdict (lambda : {
105- "insert_rates" : [],
106- "insert_times" : [],
107- "iterations" : [],
108- "is_dev" : False ,
109- })
105+ node_performance = defaultdict (
106+ lambda : {
107+ "insert_rates" : [],
108+ "insert_times" : [],
109+ "iterations" : [],
110+ "is_dev" : False ,
111+ }
112+ )
110113
111114 for result in results :
112115 hostname , is_dev = _extract_node_info (result )
113-
116+
114117 if hostname not in node_performance :
115118 node_performance [hostname ] = {
116119 "insert_rates" : [],
@@ -135,45 +138,45 @@ def create_simple_performance_trends(results, output_dir):
135138 if len (fs_performance ) > 1 :
136139 # Multi-filesystem mode: separate lines for each filesystem
137140 fig , (ax1 , ax2 ) = plt .subplots (1 , 2 , figsize = (15 , 6 ))
138-
141+
139142 colors = ["b" , "r" , "g" , "m" , "c" , "y" , "k" ]
140143 color_idx = 0
141-
144+
142145 for config_key , perf_data in fs_performance .items ():
143146 if not perf_data ["insert_rates" ]:
144147 continue
145-
148+
146149 color = colors [color_idx % len (colors )]
147150 iterations = list (range (1 , len (perf_data ["insert_rates" ]) + 1 ))
148-
149- # Plot insert rate
151+
152+ # Plot insert rate
150153 ax1 .plot (
151154 iterations ,
152- perf_data ["insert_rates" ],
155+ perf_data ["insert_rates" ],
153156 f"{ color } -o" ,
154157 linewidth = 2 ,
155158 markersize = 6 ,
156159 label = config_key .upper (),
157160 )
158-
161+
159162 # Plot insert time
160163 ax2 .plot (
161164 iterations ,
162165 perf_data ["insert_times" ],
163- f"{ color } -o" ,
166+ f"{ color } -o" ,
164167 linewidth = 2 ,
165168 markersize = 6 ,
166169 label = config_key .upper (),
167170 )
168-
171+
169172 color_idx += 1
170-
173+
171174 ax1 .set_xlabel ("Iteration" )
172175 ax1 .set_ylabel ("Vectors/Second" )
173176 ax1 .set_title ("Milvus Insert Rate by Storage Filesystem" )
174177 ax1 .grid (True , alpha = 0.3 )
175178 ax1 .legend ()
176-
179+
177180 ax2 .set_xlabel ("Iteration" )
178181 ax2 .set_ylabel ("Total Time (seconds)" )
179182 ax2 .set_title ("Milvus Insert Time by Storage Filesystem" )
@@ -182,13 +185,13 @@ def create_simple_performance_trends(results, output_dir):
182185 else :
183186 # Single filesystem mode: original behavior
184187 fig , (ax1 , ax2 ) = plt .subplots (1 , 2 , figsize = (15 , 6 ))
185-
188+
186189 # Extract insert data from single filesystem
187190 config_key = list (fs_performance .keys ())[0 ] if fs_performance else None
188191 if config_key :
189192 perf_data = fs_performance [config_key ]
190193 iterations = list (range (1 , len (perf_data ["insert_rates" ]) + 1 ))
191-
194+
192195 # Plot insert rate
193196 ax1 .plot (
194197 iterations ,
@@ -198,10 +201,10 @@ def create_simple_performance_trends(results, output_dir):
198201 markersize = 6 ,
199202 )
200203 ax1 .set_xlabel ("Iteration" )
201- ax1 .set_ylabel ("Vectors/Second" )
204+ ax1 .set_ylabel ("Vectors/Second" )
202205 ax1 .set_title ("Vector Insert Rate Performance" )
203206 ax1 .grid (True , alpha = 0.3 )
204-
207+
205208 # Plot insert time
206209 ax2 .plot (
207210 iterations ,
@@ -212,9 +215,9 @@ def create_simple_performance_trends(results, output_dir):
212215 )
213216 ax2 .set_xlabel ("Iteration" )
214217 ax2 .set_ylabel ("Total Time (seconds)" )
215- ax2 .set_title ("Vector Insert Time Performance" )
218+ ax2 .set_title ("Vector Insert Time Performance" )
216219 ax2 .grid (True , alpha = 0.3 )
217-
220+
218221 plt .tight_layout ()
219222 plt .savefig (os .path .join (output_dir , "performance_trends.png" ), dpi = 150 )
220223 plt .close ()
@@ -226,109 +229,133 @@ def create_heatmap_analysis(results, output_dir):
226229 return
227230
228231 # Group data by filesystem configuration
229- fs_performance = defaultdict (lambda : {
230- "query_data" : [],
231- "config_key" : "" ,
232- })
232+ fs_performance = defaultdict (
233+ lambda : {
234+ "query_data" : [],
235+ "config_key" : "" ,
236+ }
237+ )
233238
234239 for result in results :
235240 fs_type , block_size , config_key = _extract_filesystem_config (result )
236-
241+
237242 query_perf = result .get ("query_performance" , {})
238243 for topk , topk_data in query_perf .items ():
239244 for batch , batch_data in topk_data .items ():
240245 qps = batch_data .get ("queries_per_second" , 0 )
241- fs_performance [config_key ]["query_data" ].append ({
242- "topk" : topk ,
243- "batch" : batch ,
244- "qps" : qps ,
245- })
246+ fs_performance [config_key ]["query_data" ].append (
247+ {
248+ "topk" : topk ,
249+ "batch" : batch ,
250+ "qps" : qps ,
251+ }
252+ )
246253 fs_performance [config_key ]["config_key" ] = config_key
247254
248255 # Check if we have multi-filesystem data
249256 if len (fs_performance ) > 1 :
250257 # Multi-filesystem mode: separate heatmaps for each filesystem
251258 num_fs = len (fs_performance )
252- fig , axes = plt .subplots (1 , num_fs , figsize = (5 * num_fs , 6 ))
259+ fig , axes = plt .subplots (1 , num_fs , figsize = (5 * num_fs , 6 ))
253260 if num_fs == 1 :
254261 axes = [axes ]
255-
262+
256263 # Define common structure for consistency
257264 topk_order = ["topk_1" , "topk_10" , "topk_100" ]
258265 batch_order = ["batch_1" , "batch_10" , "batch_100" ]
259-
266+
260267 for idx , (config_key , perf_data ) in enumerate (fs_performance .items ()):
261268 # Create matrix for this filesystem
262269 matrix = np .zeros ((len (topk_order ), len (batch_order )))
263-
270+
264271 # Fill matrix with data
265272 query_dict = {}
266273 for item in perf_data ["query_data" ]:
267274 query_dict [(item ["topk" ], item ["batch" ])] = item ["qps" ]
268-
275+
269276 for i , topk in enumerate (topk_order ):
270277 for j , batch in enumerate (batch_order ):
271278 matrix [i , j ] = query_dict .get ((topk , batch ), 0 )
272-
279+
273280 # Plot heatmap
274- im = axes [idx ].imshow (matrix , cmap = ' viridis' , aspect = ' auto' )
281+ im = axes [idx ].imshow (matrix , cmap = " viridis" , aspect = " auto" )
275282 axes [idx ].set_title (f"{ config_key .upper ()} Query Performance" )
276283 axes [idx ].set_xticks (range (len (batch_order )))
277- axes [idx ].set_xticklabels ([b .replace ("batch_" , "Batch " ) for b in batch_order ])
284+ axes [idx ].set_xticklabels (
285+ [b .replace ("batch_" , "Batch " ) for b in batch_order ]
286+ )
278287 axes [idx ].set_yticks (range (len (topk_order )))
279288 axes [idx ].set_yticklabels ([t .replace ("topk_" , "Top-" ) for t in topk_order ])
280-
289+
281290 # Add text annotations
282291 for i in range (len (topk_order )):
283292 for j in range (len (batch_order )):
284- axes [idx ].text (j , i , f'{ matrix [i , j ]:.0f} ' ,
285- ha = "center" , va = "center" , color = "white" , fontweight = "bold" )
286-
293+ axes [idx ].text (
294+ j ,
295+ i ,
296+ f"{ matrix [i , j ]:.0f} " ,
297+ ha = "center" ,
298+ va = "center" ,
299+ color = "white" ,
300+ fontweight = "bold" ,
301+ )
302+
287303 # Add colorbar
288304 cbar = plt .colorbar (im , ax = axes [idx ])
289- cbar .set_label (' Queries Per Second (QPS)' )
305+ cbar .set_label (" Queries Per Second (QPS)" )
290306 else :
291307 # Single filesystem mode
292308 fig , ax = plt .subplots (1 , 1 , figsize = (8 , 6 ))
293-
309+
294310 if fs_performance :
295311 config_key = list (fs_performance .keys ())[0 ]
296312 perf_data = fs_performance [config_key ]
297-
313+
298314 # Create matrix
299315 topk_order = ["topk_1" , "topk_10" , "topk_100" ]
300316 batch_order = ["batch_1" , "batch_10" , "batch_100" ]
301317 matrix = np .zeros ((len (topk_order ), len (batch_order )))
302-
318+
303319 # Fill matrix with data
304320 query_dict = {}
305321 for item in perf_data ["query_data" ]:
306322 query_dict [(item ["topk" ], item ["batch" ])] = item ["qps" ]
307-
323+
308324 for i , topk in enumerate (topk_order ):
309325 for j , batch in enumerate (batch_order ):
310326 matrix [i , j ] = query_dict .get ((topk , batch ), 0 )
311-
327+
312328 # Plot heatmap
313- im = ax .imshow (matrix , cmap = ' viridis' , aspect = ' auto' )
329+ im = ax .imshow (matrix , cmap = " viridis" , aspect = " auto" )
314330 ax .set_title ("Milvus Query Performance Heatmap" )
315331 ax .set_xticks (range (len (batch_order )))
316332 ax .set_xticklabels ([b .replace ("batch_" , "Batch " ) for b in batch_order ])
317333 ax .set_yticks (range (len (topk_order )))
318334 ax .set_yticklabels ([t .replace ("topk_" , "Top-" ) for t in topk_order ])
319-
335+
320336 # Add text annotations
321337 for i in range (len (topk_order )):
322338 for j in range (len (batch_order )):
323- ax .text (j , i , f'{ matrix [i , j ]:.0f} ' ,
324- ha = "center" , va = "center" , color = "white" , fontweight = "bold" )
325-
339+ ax .text (
340+ j ,
341+ i ,
342+ f"{ matrix [i , j ]:.0f} " ,
343+ ha = "center" ,
344+ va = "center" ,
345+ color = "white" ,
346+ fontweight = "bold" ,
347+ )
348+
326349 # Add colorbar
327350 cbar = plt .colorbar (im , ax = ax )
328- cbar .set_label (' Queries Per Second (QPS)' )
329-
351+ cbar .set_label (" Queries Per Second (QPS)" )
352+
330353 plt .tight_layout ()
331- plt .savefig (os .path .join (output_dir , "performance_heatmap.png" ), dpi = 150 , bbox_inches = "tight" )
354+ plt .savefig (
355+ os .path .join (output_dir , "performance_heatmap.png" ),
356+ dpi = 150 ,
357+ bbox_inches = "tight" ,
358+ )
332359 plt .close ()
333360
334361
@@ -359,4 +386,4 @@ def main():
359386
360387
361388if __name__ == "__main__" :
362- main ()
389+ main ()
0 commit comments