55import importlib .metadata
66
77from cuda import cuda
8- from cuda .core .experimental ._utils import handle_return
8+ from cuda .core .experimental ._utils import handle_return , precondition
99
1010_backend = {
1111 "old" : {
@@ -106,30 +106,43 @@ class ObjectCode:
106106
107107 """
108108
109- __slots__ = ("_handle" , "_code_type" , "_module" , "_loader" , "_sym_map" )
109+ __slots__ = ("_handle" , "_backend_version" , "_jit_options" , " _code_type" , "_module" , "_loader" , "_sym_map" )
110110 _supported_code_type = ("cubin" , "ptx" , "ltoir" , "fatbin" )
111111
112112 def __init__ (self , module , code_type , jit_options = None , * , symbol_mapping = None ):
113113 if code_type not in self ._supported_code_type :
114114 raise ValueError
115115 _lazy_init ()
116+
117+ # handle is assigned during _lazy_load
116118 self ._handle = None
119+ self ._jit_options = jit_options
120+
121+ self ._backend_version = "new" if (_py_major_ver >= 12 and _driver_ver >= 12000 ) else "old"
122+ self ._loader = _backend [self ._backend_version ]
123+
124+ self ._code_type = code_type
125+ self ._module = module
126+ self ._sym_map = {} if symbol_mapping is None else symbol_mapping
117127
118- backend = "new" if (_py_major_ver >= 12 and _driver_ver >= 12000 ) else "old"
119- self ._loader = _backend [backend ]
128+ # TODO: do we want to unload in a finalizer? Probably not..
120129
130+ def _lazy_load_module (self , * args , ** kwargs ):
131+ if self ._handle is not None :
132+ return
133+ jit_options = self ._jit_options
134+ module = self ._module
121135 if isinstance (module , str ):
122136 # TODO: this option is only taken by the new library APIs, but we have
123137 # a bug that we can't easily support it just yet (NVIDIA/cuda-python#73).
124138 if jit_options is not None :
125139 raise ValueError
126- module = module .encode ()
127140 self ._handle = handle_return (self ._loader ["file" ](module ))
128141 else :
129142 assert isinstance (module , bytes )
130143 if jit_options is None :
131144 jit_options = {}
132- if backend == "new" :
145+ if self . _backend_version == "new" :
133146 args = (
134147 module ,
135148 list (jit_options .keys ()),
@@ -141,15 +154,15 @@ def __init__(self, module, code_type, jit_options=None, *, symbol_mapping=None):
141154 0 ,
142155 )
143156 else : # "old" backend
144- args = (module , len (jit_options ), list (jit_options .keys ()), list (jit_options .values ()))
157+ args = (
158+ module ,
159+ len (jit_options ),
160+ list (jit_options .keys ()),
161+ list (jit_options .values ()),
162+ )
145163 self ._handle = handle_return (self ._loader ["data" ](* args ))
146164
147- self ._code_type = code_type
148- self ._module = module
149- self ._sym_map = {} if symbol_mapping is None else symbol_mapping
150-
151- # TODO: do we want to unload in a finalizer? Probably not..
152-
165+ @precondition (_lazy_load_module )
153166 def get_kernel (self , name ):
154167 """Return the :obj:`Kernel` of a specified name from this object code.
155168
@@ -168,6 +181,7 @@ def get_kernel(self, name):
168181 name = self ._sym_map [name ]
169182 except KeyError :
170183 name = name .encode ()
184+
171185 data = handle_return (self ._loader ["kernel" ](self ._handle , name ))
172186 return Kernel ._from_obj (data , self )
173187
0 commit comments