@@ -286,5 +286,228 @@ async def test_missing_reply_has_deadline(self):
286286 )
287287
288288
289+ mllog_lib = load ("mllog_utils_under_test" , ROOT / "tunix/utils/mllog_utils.py" )
290+
291+
292+ class OfflineEvalRcpTest (unittest .IsolatedAsyncioTestCase ):
293+
294+ def test_compute_val_start_step (self ):
295+ self .assertEqual (mllog_lib .compute_val_start_step (256 ), 18 )
296+ self .assertEqual (mllog_lib .compute_val_start_step (128 ), 33 )
297+ self .assertEqual (mllog_lib .compute_val_start_step (256 , 5 ), 5 )
298+ with self .assertRaises (ValueError ):
299+ mllog_lib .compute_val_start_step (0 )
300+
301+ def test_checkpoint_manifest_read_write_and_contiguity (self ):
302+ with tempfile .TemporaryDirectory () as tmpdir :
303+ manifest_path = str (Path (tmpdir ) / "eval_checkpoints.jsonl" )
304+ mllog_lib .append_checkpoint_manifest (
305+ manifest_path ,
306+ {
307+ "step" : 19 ,
308+ "samples_count" : 4864 ,
309+ "checkpoint_timestamp_ms" : 2000 ,
310+ "checkpoint_path" : "gs://ckpt/19/model_params" ,
311+ "val_start_at" : 18 ,
312+ "max_steps" : 50 ,
313+ },
314+ )
315+ mllog_lib .append_checkpoint_manifest (
316+ manifest_path ,
317+ {
318+ "step" : 18 ,
319+ "samples_count" : 4608 ,
320+ "checkpoint_timestamp_ms" : 1000 ,
321+ "checkpoint_path" : "gs://ckpt/18/model_params" ,
322+ "val_start_at" : 18 ,
323+ "max_steps" : 50 ,
324+ },
325+ )
326+ records = mllog_lib .load_checkpoint_manifest (
327+ manifest_path , check_contiguous = True
328+ )
329+ self .assertEqual ([r ["step" ] for r in records ], [18 , 19 ])
330+
331+ # Non-contiguous step should raise ValueError
332+ mllog_lib .append_checkpoint_manifest (
333+ manifest_path ,
334+ {
335+ "step" : 21 ,
336+ "samples_count" : 5376 ,
337+ "checkpoint_timestamp_ms" : 4000 ,
338+ "checkpoint_path" : "gs://ckpt/21/model_params" ,
339+ "val_start_at" : 18 ,
340+ "max_steps" : 50 ,
341+ },
342+ )
343+ with self .assertRaisesRegex (ValueError , "Non-contiguous" ):
344+ mllog_lib .load_checkpoint_manifest (
345+ manifest_path , check_contiguous = True
346+ )
347+
348+ def test_summarize_includes_pass_at_4 (self ):
349+ rows = [
350+ {"instance_id" : "inst_1" , "attempt" : i , "resolved" : i == 0 , "reward" : 1.0 if i == 0 else 0.0 , "status" : "ok" }
351+ for i in range (4 )
352+ ]
353+ summary = eval_lib .summarize (rows , ["inst_1" ], 4 )
354+ self .assertIn ("4" , summary ["pass_at_k" ])
355+ self .assertAlmostEqual (summary ["pass_at_k" ]["4" ], 1.0 )
356+ self .assertAlmostEqual (summary ["mean_reward" ], 0.25 )
357+
358+ def test_offline_eval_rcp_sequence_converged_and_aborted (self ):
359+ fake_mllogger = mock .MagicMock ()
360+ with (
361+ mock .patch .object (mllog_lib , "mllogger" , fake_mllogger ),
362+ mock .patch .object (mllog_lib , "_is_master_process" , return_value = True ),
363+ mock .patch .object (mllog_lib , "_flush_to_gcs_if_needed" ),
364+ ):
365+ args = types .SimpleNamespace (
366+ batch_size = 16 , num_generations = 16 , max_steps = 50
367+ )
368+ mllog_lib .train_stop (args , step = 50 , time_ms = 5000 )
369+ fake_mllogger .end .assert_called_once_with (
370+ key = "block_stop" ,
371+ metadata = {"step" : 50 , "samples_count" : 12800 },
372+ time_ms = 5000 ,
373+ )
374+ fake_mllogger .reset_mock ()
375+
376+ # Step 18: accuracy 0.68 < 0.69 -> no run_stop
377+ passed_18 = mllog_lib .log_offline_eval_step (
378+ step = 18 ,
379+ samples_count = 4608 ,
380+ eval_accuracy = 0.68 ,
381+ target_accuracy = 0.69 ,
382+ checkpoint_timestamp_ms = 1000 ,
383+ is_last_checkpoint = False ,
384+ validation_time = 12.5 ,
385+ )
386+ self .assertFalse (passed_18 )
387+ end_keys_18 = [c .kwargs ["key" ] for c in fake_mllogger .end .call_args_list ]
388+ self .assertEqual (end_keys_18 , ["eval_stop" ])
389+ fake_mllogger .reset_mock ()
390+
391+ # Step 19: accuracy 0.71 >= 0.69 -> backdated run_stop(time_ms=2000, status="success")
392+ passed_19 = mllog_lib .log_offline_eval_step (
393+ step = 19 ,
394+ samples_count = 4864 ,
395+ eval_accuracy = 0.71 ,
396+ target_accuracy = 0.69 ,
397+ checkpoint_timestamp_ms = 2000 ,
398+ is_last_checkpoint = False ,
399+ validation_time = 14.0 ,
400+ )
401+ self .assertTrue (passed_19 )
402+ fake_mllogger .end .assert_any_call (
403+ key = "run_stop" ,
404+ metadata = {"status" : "success" , "samples_count" : 4864 },
405+ time_ms = 2000 ,
406+ )
407+ train_samples_calls = [
408+ c for c in fake_mllogger .event .call_args_list if c .kwargs .get ("key" ) == "train_samples"
409+ ]
410+ self .assertEqual (len (train_samples_calls ), 0 )
411+ fake_mllogger .reset_mock ()
412+
413+ # Step 50 (final): accuracy 0.68 < 0.69 -> backdated run_stop(time_ms=5000, status="aborted")
414+ passed_50 = mllog_lib .log_offline_eval_step (
415+ step = 50 ,
416+ samples_count = 12800 ,
417+ eval_accuracy = 0.68 ,
418+ target_accuracy = 0.69 ,
419+ checkpoint_timestamp_ms = 5000 ,
420+ is_last_checkpoint = True ,
421+ validation_time = 15.0 ,
422+ )
423+ self .assertFalse (passed_50 )
424+ fake_mllogger .end .assert_any_call (
425+ key = "run_stop" ,
426+ metadata = {"status" : "aborted" , "samples_count" : 12800 },
427+ time_ms = 5000 ,
428+ )
429+
430+ def test_mlperf_6_1_0_init_print_disclosures (self ):
431+ fake_mllogger = mock .MagicMock ()
432+ with (
433+ mock .patch .object (mllog_lib , "mllogger" , fake_mllogger ),
434+ mock .patch .object (mllog_lib , "_is_master_process" , return_value = True ),
435+ mock .patch .object (mllog_lib , "_flush_to_gcs_if_needed" ),
436+ ):
437+ args = types .SimpleNamespace (
438+ batch_size = 16 ,
439+ num_generations = 16 ,
440+ max_steps = 50 ,
441+ max_prompt_length = 4096 ,
442+ max_response_length = 61440 ,
443+ target_accuracy = 0.69 ,
444+ )
445+ mllog_lib .init_print (args , train_dataset = list (range (1000 )))
446+ emitted = {
447+ c .kwargs ["key" ]: c .kwargs ["value" ]
448+ for c in fake_mllogger .event .call_args_list
449+ }
450+ self .assertEqual (emitted ["eval_samples" ], 251 )
451+ self .assertEqual (emitted ["max_sequence_length" ], 65536 )
452+ self .assertEqual (emitted ["opt_adamw_beta_2" ], 0.999 )
453+ self .assertEqual (emitted ["opt_adamw_weight_decay" ], 0.0 )
454+ self .assertAlmostEqual (emitted ["opt_gradient_clip_norm" ], 0.125 )
455+ self .assertEqual (emitted ["lowest_numerical_precision_in_linear" ], "bfloat16" )
456+ self .assertEqual (emitted ["lowest_numerical_precision_in_attn" ], "bfloat16" )
457+ self .assertEqual (emitted ["lowest_numerical_precision_in_comm" ], "bfloat16" )
458+ self .assertEqual (emitted ["config_filename" ], "qwen35_397b_grpo" )
459+
460+ async def test_controller_manifest_loop_stops_on_convergence (self ):
461+ with tempfile .TemporaryDirectory () as tmpdir :
462+ manifest_path = str (Path (tmpdir ) / "eval_checkpoints.jsonl" )
463+ for step , ts_ms in ((18 , 1000 ), (19 , 2000 ), (20 , 3000 )):
464+ mllog_lib .append_checkpoint_manifest (
465+ manifest_path ,
466+ {
467+ "step" : step ,
468+ "samples_count" : step * 256 ,
469+ "checkpoint_timestamp_ms" : ts_ms ,
470+ "checkpoint_path" : f"gs://ckpt/{ step } /model_params" ,
471+ "val_start_at" : 18 ,
472+ "max_steps" : 20 ,
473+ },
474+ )
475+
476+ evaluated_steps = []
477+
478+ async def fake_single_controller (step_args ):
479+ evaluated_steps .append (step_args .checkpoint_step )
480+ reached = step_args .checkpoint_step == 19
481+ return {
482+ "checkpoint_step" : step_args .checkpoint_step ,
483+ "checkpoint_timestamp_ms" : step_args .checkpoint_timestamp_ms ,
484+ "samples_count" : step_args .samples_count ,
485+ "target_reached" : reached ,
486+ "rcp_logged" : True ,
487+ }
488+
489+ a = eval_lib .parse_args ([
490+ "--checkpoint_manifest_file" ,
491+ manifest_path ,
492+ "--output_dir" ,
493+ str (Path (tmpdir ) / "results" ),
494+ ])
495+ with (
496+ mock .patch .dict (
497+ sys .modules ,
498+ {"tunix.utils" : types .SimpleNamespace (mllog_utils = mllog_lib )},
499+ ),
500+ mock .patch .object (
501+ eval_lib , "_run_single_controller" , side_effect = fake_single_controller
502+ ),
503+ ):
504+ summary = await eval_lib .run_controller (a )
505+
506+ self .assertEqual (evaluated_steps , [18 , 19 ])
507+ self .assertTrue (summary ["target_reached" ])
508+ self .assertEqual (summary ["checkpoint_step" ], 19 )
509+ self .assertEqual (summary ["checkpoint_timestamp_ms" ], 2000 )
510+
511+
289512if __name__ == "__main__" :
290513 unittest .main ()
0 commit comments