@@ -1731,8 +1731,9 @@ def test_update_kv_caches_after_scan_invalid_type(self):
17311731 maxtext_utils .update_kv_caches_after_scan (kv_caches_tuple , returned_kv_cache , scan_length = 1 , block_len = 2 )
17321732
17331733
1734- class TestGetOffloadRematNames (unittest .TestCase ):
1735- """Tests for maxtext_utils.get_offload_remat_names."""
1734+ @pytest .mark .cpu_only
1735+ class TestGetSaveAndOffloadNames (unittest .TestCase ):
1736+ """Tests for maxtext_utils.get_save_and_offload_names (pure config logic, no device needed)."""
17361737
17371738 @staticmethod
17381739 def _cfg (remat_policy , tensors_on_device = None , tensors_to_offload = None ):
@@ -1743,33 +1744,42 @@ def _cfg(remat_policy, tensors_on_device=None, tensors_to_offload=None):
17431744 )
17441745
17451746 def test_named_preset_matches_equivalent_custom (self ):
1746- """qkv_proj_offloaded resolves identically to custom with the same offloads."""
1747- preset = maxtext_utils .get_offload_remat_names (self ._cfg ("qkv_proj_offloaded" ))
1748- custom = maxtext_utils .get_offload_remat_names (
1749- self ._cfg ("custom" , tensors_on_device = [], tensors_to_offload = ["query_proj" , "value_proj" , "key_proj" , "kv_proj" ])
1747+ """qkv_proj_offloaded's offload names resolve identically to an equivalent custom config.
1748+
1749+ A real custom config keeps decoder_layer_input on device by default, so its full tuple
1750+ differs from the preset by that (benign, boundary) save entry -- assert only the offload halves.
1751+ """
1752+ _ , preset_offload = maxtext_utils .get_save_and_offload_names (self ._cfg ("qkv_proj_offloaded" ))
1753+ _ , custom_offload = maxtext_utils .get_save_and_offload_names (
1754+ self ._cfg (
1755+ "custom" ,
1756+ tensors_on_device = ["decoder_layer_input" ],
1757+ tensors_to_offload = ["query_proj" , "value_proj" , "key_proj" , "kv_proj" ],
1758+ )
17501759 )
1751- self .assertEqual (preset , custom )
1760+ self .assertEqual (custom_offload , preset_offload )
17521761
17531762 def test_kv_proj_retained_in_offload_presets (self ):
17541763 """Regression guard: kv_proj must stay in the offload presets (it is a real checkpoint name)."""
1755- _ , qkv_offload = maxtext_utils .get_offload_remat_names (self ._cfg ("qkv_proj_offloaded" ))
1756- _ , minimal_offload = maxtext_utils .get_offload_remat_names (self ._cfg ("minimal_offloaded" ))
1764+ _ , qkv_offload = maxtext_utils .get_save_and_offload_names (self ._cfg ("qkv_proj_offloaded" ))
1765+ _ , minimal_offload = maxtext_utils .get_save_and_offload_names (self ._cfg ("minimal_offloaded" ))
17571766 self .assertIn ("kv_proj" , qkv_offload )
17581767 self .assertIn ("kv_proj" , minimal_offload )
17591768
17601769 def test_custom_reads_config_lists (self ):
1761- save , offload = maxtext_utils .get_offload_remat_names (
1770+ save , offload = maxtext_utils .get_save_and_offload_names (
17621771 self ._cfg ("custom" , tensors_on_device = ["context" ], tensors_to_offload = ["out_proj" ])
17631772 )
17641773 self .assertEqual (save , ["context" ])
17651774 self .assertEqual (offload , ["out_proj" ])
17661775
17671776 def test_custom_handles_none_lists (self ):
1768- self .assertEqual (maxtext_utils .get_offload_remat_names (self ._cfg ("custom" )), ([], []))
1777+ self .assertEqual (maxtext_utils .get_save_and_offload_names (self ._cfg ("custom" )), ([], []))
17691778
1770- def test_non_offloading_policies_return_none (self ):
1779+ def test_non_offloading_policies_return_empty (self ):
1780+ """Policies that don't use the save/offload split contribute no names to it."""
17711781 for policy in ("full" , "minimal" , "save_out_proj" , "save_qkv_proj" , "none" ):
1772- self .assertIsNone (maxtext_utils .get_offload_remat_names (self ._cfg (policy )))
1782+ self .assertEqual (maxtext_utils .get_save_and_offload_names (self ._cfg (policy )), ([], [] ))
17731783
17741784
17751785if __name__ == "__main__" :
0 commit comments