@@ -344,6 +344,35 @@ def test_log_extraction_prefers_cuda_oom_message(self):
344344 self .fail ("Expected payload from log extraction" )
345345 self .assertIn ("CUDA out of memory" , payload .get ("message" , "" ))
346346
347+ def test_log_extraction_prefers_allocator_oom_over_aoti_error (self ):
348+ """Allocator OOM warnings should beat generic compiled-kernel RuntimeErrors."""
349+ job_id = "test_log_allocator_oom"
350+ process = TrainerProcess (job_id )
351+
352+ with tempfile .TemporaryDirectory () as tmpdir :
353+ log_path = os .path .join (tmpdir , "stdout.log" )
354+ with open (log_path , "w" , encoding = "utf-8" ) as handle :
355+ handle .write ("starting epoch 5\n " )
356+ handle .write (
357+ "[W831 10:32:25.255074645 CUDACachingAllocator.cpp:508] "
358+ "expandable_segments: memory mapping failed with OOM on device 0 while trying to map 20971520 bytes.\n "
359+ )
360+ handle .write ("Traceback (most recent call last):\n " )
361+ handle .write (
362+ "RuntimeError: aoti_torch_empty_strided(3, int_array_74, int_array_75, "
363+ "cached_torch_dtype_bfloat16, cached_torch_device_type_cuda, 0, &buf80_handle) API call failed\n "
364+ )
365+
366+ process .log_file = log_path
367+ payload = process ._extract_error_from_logs (exit_code = 1 )
368+
369+ self .assertIsNotNone (payload )
370+ if payload is None :
371+ self .fail ("Expected payload from log extraction" )
372+ message = payload .get ("message" , "" )
373+ self .assertIn ("memory mapping failed with OOM" , message )
374+ self .assertNotIn ("aoti_torch_empty_strided" , message )
375+
347376 def test_log_extraction_prefers_signal_exit (self ):
348377 """Synthetic log extraction should highlight signal-based exits."""
349378 job_id = "test_log_signal_exit"
0 commit comments