66
77
88import contextlib
9- import copy
10- import ctypes
11- import functools
12- import gc
139import logging
1410import os
1511import shutil
2925from executorch .backends .cuda .triton .replacement_pass import (
3026 ReplaceEdgeOpWithTritonOpPass ,
3127)
32- from executorch .exir ._serialize ._cord import FileBackedData
3328from executorch .exir ._warnings import experimental
3429from executorch .exir .backend .backend_details import BackendDetails
3530from executorch .exir .backend .compile_spec_schema import CompileSpec
@@ -65,14 +60,6 @@ def _is_cpu_clone_active() -> bool:
6560 return getattr (_CPU_CLONE_GUARD , "active" , False )
6661
6762
68- def _trim_host_memory () -> None :
69- gc .collect ()
70- try :
71- ctypes .CDLL (None ).malloc_trim (0 )
72- except AttributeError :
73- pass
74-
75-
7663def _full_zeros_preserving_strides (x : torch .Tensor , device ) -> torch .Tensor :
7764 """Allocate a zero-filled tensor matching ``x``'s size/stride/dtype on ``device``.
7865
@@ -95,29 +82,18 @@ def _is_emptied(x) -> bool:
9582 )
9683
9784
98- def _tensor_properties_for_low_memory (tensor , original ):
99- if _is_emptied (tensor ):
100- return None
101- return original (tensor )
102-
103-
10485@contextlib .contextmanager
10586def _compile_time_cpu_clones (target_device : torch .device ):
10687 """Force AOTI's mutated-buffer clones onto CPU while preserving the
10788 serialized constants' target device."""
108- from torch ._inductor import (
109- codecache as _codecache ,
110- compile_fx as _cfx ,
111- graph as _graph ,
112- )
89+ from torch ._inductor import compile_fx as _cfx , graph as _graph
11390 from torch ._inductor .codegen .cpp_wrapper_cpu import CppWrapperCpu as _Cpp
11491 from torch ._inductor .graph import GraphLowering as _GL
11592
11693 orig_clone = _cfx .clone_preserve_strides
11794 orig_codegen_device = _Cpp .codegen_device
11895 orig_get_const = _GL .get_original_value_of_constant
11996 orig_is_same = _graph .is_same_tensor
120- orig_tensor_properties = _codecache .TensorProperties
12197
12298 def _is_same_skip_emptied (data , value ):
12399 # KV buffers freed via resize_(0) all have data_ptr 0, so the stock
@@ -176,9 +152,6 @@ def _codegen_device_target_aware(self, device):
176152 _Cpp .codegen_device = _codegen_device_target_aware
177153 _GL .get_original_value_of_constant = _get_const_synthesize_zeros
178154 _graph .is_same_tensor = _is_same_skip_emptied
179- _codecache .TensorProperties = functools .partial (
180- _tensor_properties_for_low_memory , original = orig_tensor_properties
181- )
182155 prev_active = getattr (_CPU_CLONE_GUARD , "active" , False )
183156 _CPU_CLONE_GUARD .active = True
184157 try :
@@ -189,7 +162,6 @@ def _codegen_device_target_aware(self, device):
189162 _Cpp .codegen_device = orig_codegen_device
190163 _GL .get_original_value_of_constant = orig_get_const
191164 _graph .is_same_tensor = orig_is_same
192- _codecache .TensorProperties = orig_tensor_properties
193165
194166
195167def _is_kv_buffer (name , v ) -> bool :
@@ -298,38 +270,6 @@ def _on_off_compile_spec_value(spec: CompileSpec) -> bool:
298270 return value == "ON"
299271
300272
301- def _write_aoti_weights_blob (weights , blob_path : str ) -> None :
302- _trim_host_memory ()
303- tensors = [tensor for tensor , _ in weights .values ()]
304- all_cuda = all (tensor .is_cuda for tensor in tensors )
305- chunk_size = 8 * 1024 * 1024
306-
307- with open (blob_path , "wb" ) as output :
308- for tensor in tensors :
309- if tensor .is_mkldnn :
310- raise RuntimeError ("MKLDNN constants are not supported by CUDA AOTI" )
311- storage = tensor .untyped_storage ()
312- nbytes = storage .nbytes ()
313- if nbytes and tensor .is_cuda :
314- byte_tensor = torch .empty (
315- 0 , dtype = torch .uint8 , device = tensor .device
316- ).set_ (storage , 0 , (nbytes ,), (1 ,))
317- for offset in range (0 , nbytes , chunk_size ):
318- cpu_chunk = byte_tensor [offset : offset + chunk_size ].cpu ()
319- output .write (memoryview (cpu_chunk .numpy ()))
320- del byte_tensor , cpu_chunk
321- elif nbytes :
322- raw_array = (ctypes .c_ubyte * nbytes ).from_address (storage .data_ptr ())
323- raw_view = memoryview (raw_array ).cast ("B" )
324- for offset in range (0 , nbytes , chunk_size ):
325- output .write (raw_view [offset : offset + chunk_size ])
326- del raw_view , raw_array
327- if not all_cuda and (padding := (- nbytes ) % 64 ):
328- output .write (bytes (padding ))
329- del storage
330- _trim_host_memory ()
331-
332-
333273@final
334274@experimental (
335275 "This API and all of cuda backend related functionality are experimental."
@@ -444,56 +384,6 @@ def save_data_externally(cls) -> bool:
444384 """
445385 return True
446386
447- @classmethod
448- def load_weights_blob (
449- cls , blob_path : str , compile_specs : List [CompileSpec ]
450- ) -> tuple [Any , str ]:
451- if not cls ._is_low_memory_mode (compile_specs ):
452- return super ().load_weights_blob (blob_path , compile_specs )
453- blob_data = FileBackedData .move_from (blob_path )
454- return blob_data , blob_data .sha256 ().hex ()
455-
456- @classmethod
457- def materialize_weights_blob (
458- cls , paths : Any , compile_specs : List [CompileSpec ]
459- ) -> Any :
460- if not cls ._is_low_memory_mode (compile_specs ) or not isinstance (paths , list ):
461- return paths
462-
463- from torch .export .pt2_archive ._package_weights import Weights
464-
465- weights = [path for path in paths if isinstance (path , Weights )]
466- if not weights :
467- return paths
468- if len (weights ) != 1 :
469- raise RuntimeError (
470- f"Expected one CUDA AOTI weights output, got { len (weights )} "
471- )
472-
473- so_path = next (
474- path
475- for path in paths
476- if isinstance (path , str ) and path .endswith (".wrapper.so" )
477- )
478- blob_path = os .path .splitext (so_path )[0 ] + "_weights.blob"
479- _write_aoti_weights_blob (weights [0 ], blob_path )
480- return [path for path in paths if not isinstance (path , Weights )] + [blob_path ]
481-
482- @classmethod
483- def copy_exported_program_for_preprocess (
484- cls , edge_program , compile_specs : List [CompileSpec ]
485- ):
486- if not cls ._is_low_memory_mode (compile_specs ):
487- return copy .deepcopy (edge_program )
488-
489- tensor_memo = {
490- id (tensor ): tensor
491- for values in (edge_program .state_dict , edge_program .constants )
492- for tensor in values .values ()
493- if isinstance (tensor , torch .Tensor )
494- }
495- return copy .deepcopy (edge_program , tensor_memo )
496-
497387 @classmethod
498388 def get_supported_fallback_kernels (cls ) -> Dict [str , Any ]:
499389 return {
@@ -569,9 +459,7 @@ def get_aoti_compile_options(
569459 "aot_inductor.package" : True ,
570460 "aot_inductor.package_constants_in_so" : False ,
571461 # Store weight constants on disk in a binary blob
572- "aot_inductor.package_constants_on_disk_format" : cls ._weights_format (
573- compile_specs
574- ),
462+ "aot_inductor.package_constants_on_disk_format" : "binary_blob" ,
575463 # Enable maximum automatic tuning for optimal performance
576464 "max_autotune" : True ,
577465 # Use TRITON for GEMM (General Matrix Multiply) operations tuning only to avoid using operators in libtorch
@@ -706,7 +594,6 @@ def _combined():
706594 stack .enter_context (
707595 _compile_time_cpu_clones (torch .device (cls .get_device_name ()))
708596 )
709- _trim_host_memory ()
710597 yield
711598
712599 return _combined ()
@@ -719,14 +606,6 @@ def _is_low_memory_mode(compile_specs: List[CompileSpec]) -> bool:
719606 return spec .value .decode ("utf-8" ).upper () == "ON"
720607 return False
721608
722- @classmethod
723- def _weights_format (cls , compile_specs : List [CompileSpec ]) -> str :
724- return (
725- "pickle_weights"
726- if cls ._is_low_memory_mode (compile_specs )
727- else "binary_blob"
728- )
729-
730609 @classmethod
731610 def move_program_to_device (
732611 cls ,
0 commit comments