88import argparse
99import sys
1010from pathlib import Path
11+ import json
12+ from contextlib import redirect_stdout , redirect_stderr
1113
1214from graph_net .paddle import utils
1315from graph_net import test_compiler_util
@@ -111,8 +113,12 @@ def get_compiled_model(model, compiler, model_path):
111113
112114
113115def measure_performance (model_call , synchronizer_func , warmup , trials ):
114- for _ in range (warmup ):
115- model_call ()
116+ outputs = None
117+ for i in range (warmup ):
118+ out_run = model_call ()
119+ if i == 0 :
120+ outputs = out_run
121+
116122 synchronizer_func ()
117123
118124 e2e_times = []
@@ -121,21 +127,44 @@ def measure_performance(model_call, synchronizer_func, warmup, trials):
121127 with test_compiler_util .naive_timer (duration_box , synchronizer_func ):
122128 model_call ()
123129 e2e_times .append (duration_box .value )
124- print (f"Trial { i + 1 } : e2e={ duration_box .value :.4f} ms" )
130+ # This print will be captured by the log redirect in main
131+ print (f"Trial { i + 1 } : e2e={ duration_box .value :.4f} ms" , flush = True )
132+
133+ return outputs , test_compiler_util .get_timing_stats (e2e_times )
125134
126- return test_compiler_util .get_timing_stats (e2e_times )
135+
136+ def save_outputs_to_json (outputs , file_path ):
137+ """
138+ Serializes paddle tensor outputs to a JSON file.
139+ """
140+ if isinstance (outputs , paddle .Tensor ):
141+ outputs = [outputs ]
142+
143+ serializable_outputs = []
144+ if outputs is not None :
145+ for tensor in outputs :
146+ if tensor is not None :
147+ # Convert tensor to numpy array, then to nested Python list
148+ serializable_outputs .append (tensor .numpy ().tolist ())
149+ else :
150+ serializable_outputs .append (None )
151+
152+ with open (file_path , 'w' , encoding = 'utf-8' ) as f :
153+ json .dump (serializable_outputs , f , indent = 4 )
127154
128155
129156def test_single_model (args , model_path ):
130157 set_seed (123 )
131158
132- print (f"[Config] device: { args .device } " )
133- print (f"[Config] compiler: { args .compiler } " )
134- print (f"[Config] hardware: { get_hardware_name (args .device )} " )
135- print (f"[Config] framework_version: { paddle .__version__ } " )
136- print (f"[Config] warmup: { args .warmup } " )
137- print (f"[Config] trials: { args .trials } " )
159+ # These prints will be captured by the log redirect in main
160+ print (f"[Config] device: { args .device } " , flush = True )
161+ print (f"[Config] compiler: { args .compiler } " , flush = True )
162+ print (f"[Config] hardware: { get_hardware_name (args .device )} " , flush = True )
163+ print (f"[Config] framework_version: { paddle .__version__ } " , flush = True )
164+ print (f"[Config] warmup: { args .warmup } " , flush = True )
165+ print (f"[Config] trials: { args .trials } " , flush = True )
138166
167+ outputs = None
139168 success = False
140169 try :
141170 synchronizer_func = paddle .device .synchronize
@@ -144,32 +173,32 @@ def test_single_model(args, model_path):
144173 model = load_model (model_path )
145174 model .eval ()
146175
147- print (f"Run model with compiler: { args .compiler } " )
176+ print (f"Run model with compiler: { args .compiler } " , flush = True )
148177 if args .compiler == "nope" :
149178 compiled_model = model
150179 else :
151180 compiled_model = get_compiled_model (model , args .compiler , model_path )
152181
153- time_stats = measure_performance (
182+ outputs , time_stats = measure_performance (
154183 lambda : compiled_model (** input_dict ),
155184 synchronizer_func ,
156185 args .warmup ,
157186 args .trials
158187 )
159188 success = True
160189
161- print (f"[Result] model_path: { model_path } " )
162- print (f"[Result] compiler: { args .compiler } " )
163- print (f"[Result] device: { args .device } " )
164- print (f"[Result] e2e_mean: { time_stats ['mean' ]:.5f} " )
165- print (f"[Result] e2e_std: { time_stats ['std' ]:.5f} " )
190+ print (f"[Result] model_path: { model_path } " , flush = True )
191+ print (f"[Result] compiler: { args .compiler } " , flush = True )
192+ print (f"[Result] device: { args .device } " , flush = True )
193+ print (f"[Result] e2e_mean: { time_stats ['mean' ]:.5f} " , flush = True )
194+ print (f"[Result] e2e_std: { time_stats ['std' ]:.5f} " , flush = True )
166195
167196 except Exception as e :
168- print (f"Run model failed: { str (e )} " )
169- print (traceback .format_exc ())
170- return False
197+ print (f"Run model failed: { str (e )} " , flush = True )
198+ print (traceback .format_exc (), flush = True )
199+ return False , None
171200
172- return success
201+ return success , outputs
173202
174203
175204def main ():
@@ -215,9 +244,18 @@ def main():
215244 default = None ,
216245 help = "Path to allow list file"
217246 )
247+ parser .add_argument (
248+ "--test-device-path" ,
249+ type = str ,
250+ required = True ,
251+ help = "Path to save logs and output json files"
252+ )
218253
219254 args = parser .parse_args ()
220255
256+ # Create the output directory if it doesn't exist
257+ os .makedirs (args .test_device_path , exist_ok = True )
258+
221259 test_samples = []
222260 if args .allow_list is not None :
223261 assert os .path .isfile (args .allow_list )
@@ -231,15 +269,46 @@ def main():
231269 sample_idx = 0
232270 failed_samples = []
233271
272+ # --- MODIFICATION START ---
273+ # Store the root path object
274+ root_path_obj = Path (args .model_path )
275+ # --- MODIFICATION END ---
276+
234277 for model_path in path_utils .get_recursively_model_path (args .model_path ):
235278 if not test_samples or os .path .abspath (model_path ) in test_samples :
236- print (f"[{ sample_idx } ] fixed_random_seed_device_runner, model_path: { model_path } " )
237279
238- success = test_single_model (args , model_path )
239- if not success :
240- failed_samples .append (model_path )
280+ # --- MODIFICATION START ---
281+ # Get relative path from the root model_path
282+ relative_path = Path (model_path ).relative_to (root_path_obj )
283+ # Replace path separators (like / or \) with _ to create a flat file name
284+ model_name = str (relative_path ).replace (os .path .sep , "_" )
285+ # --- MODIFICATION END ---
286+
287+ log_file_path = os .path .join (args .test_device_path , f"{ model_name } .log" )
288+ json_file_path = os .path .join (args .test_device_path , f"{ model_name } _outputs.json" )
289+
290+ # --- Redirect stdout/stderr to log file ---
291+ with open (log_file_path , 'w' , encoding = 'utf-8' ) as log_f :
292+ with redirect_stdout (log_f ), redirect_stderr (log_f ):
293+
294+ print (f"[{ sample_idx } ] fixed_random_seed_device_runner, model_path: { model_path } " , flush = True )
295+
296+ success , outputs = test_single_model (args , model_path )
297+
298+ if not success :
299+ failed_samples .append (model_path )
300+ else :
301+ # Save outputs to JSON
302+ try :
303+ save_outputs_to_json (outputs , json_file_path )
304+ except Exception as e :
305+ print (f"Failed to save outputs to JSON { json_file_path } : { str (e )} " , flush = True )
306+ print (traceback .format_exc (), flush = True )
307+ failed_samples .append (model_path ) # Count as failure
308+
241309 sample_idx += 1
242310
311+ # --- Print final summary to console ---
243312 print (f"Totally { sample_idx } verified samples, failed { len (failed_samples )} samples." )
244313 for model_path in failed_samples :
245314 print (f"- { model_path } " )
0 commit comments