Skip to content

Commit

Permalink
Release loaded DLL libraries in destructor of class Executor (#510)
Browse files Browse the repository at this point in the history
* added version 15 support for Shape operator

* fix Slice Operator

* release loaded DLL in destructor

* added HLSL test pipeline on windows

---------

Co-authored-by: donglinb <donglinb>
  • Loading branch information
donglinb authored Jul 19, 2023
1 parent 3e1992a commit 35e1a76
Show file tree
Hide file tree
Showing 3 changed files with 562 additions and 4 deletions.
35 changes: 31 additions & 4 deletions src/python/nnfusion/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,15 @@ def __init__(self, nnf_rt_dir, device=None):

# prepare init/free/kernel_entry
self.init_flag = False
if os.path.exists(os.path.join(nnf_rt_dir, "antares.dll")):
HLSLTensor.init_antares_lib(os.path.join(nnf_rt_dir, "antares.dll"))
# dxil.dll and dxcompiler.dll must be manually imported
self.lib_dxil, self.lib_dxcompiler = None, None
if os.path.exists(os.path.join(nnf_rt_dir, "dxil.dll")):
ctypes.cdll.LoadLibrary(os.path.join(nnf_rt_dir, "dxil.dll"))
self.lib_dxil = ctypes.cdll.LoadLibrary(os.path.join(nnf_rt_dir, "dxil.dll"))
if os.path.exists(os.path.join(nnf_rt_dir, "dxcompiler.dll")):
ctypes.cdll.LoadLibrary(os.path.join(nnf_rt_dir, "dxcompiler.dll"))
self.lib_dxcompiler = ctypes.cdll.LoadLibrary(os.path.join(nnf_rt_dir, "dxcompiler.dll"))
# antares.dll must be loaded after dxil.dll and dxcompiler.dll
if os.path.exists(os.path.join(nnf_rt_dir, "antares.dll")):
HLSLTensor.init_antares_lib(os.path.join(nnf_rt_dir, "antares.dll"))
self.libnnf = ctypes.cdll.LoadLibrary(self.libnnf_path)
if hasattr(self.libnnf, "kernel_entry_host"):
self.kernel_entry = self.libnnf.kernel_entry_host
Expand Down Expand Up @@ -278,11 +280,36 @@ def __del__(self):
if self.init_flag and nnf_rt_free:
nnf_rt_free()
self.init_flag = False
self._release_dynamic_libraries()

def __call__(self, *args, **kwargs):
# self.feed_tensors(*args, **kwargs)
return self.feed_data(*args, **kwargs)

def _release_dynamic_libraries(self):
# There are four DLLs loaded: antares.dll, dxcompiler.dll, dxil.dll, nnfusion_rt.dll
# But the antares.dll is warpped in the class HLSLTensor and loaded only once during process
# Thus the other three DLLs are loaded for each test case and need to be explicitly released
if platform.system().lower() == "windows":
ctypes.windll.kernel32.FreeLibrary.argtypes = [ctypes.c_void_p]
# release nnfusion_rt.dll
handle = self.libnnf._handle
del self.libnnf
ctypes.windll.kernel32.FreeLibrary(handle)
# release dxil.dll
if self.lib_dxil:
handle = self.lib_dxil._handle
del self.lib_dxil
ctypes.windll.kernel32.FreeLibrary(handle)
# release dxcompiler.dll
if self.lib_dxcompiler:
handle = self.lib_dxcompiler._handle
del self.lib_dxcompiler
ctypes.windll.kernel32.FreeLibrary(handle)
elif platform.system().lower() == "linux":
pass # TODO: release libraries in linux
return

def _dict_to_pointer_list(self, inputs, outputs, strict=True):
signature = [None] * (len(self.input_descs) + len(self.output_descs))
params = [None] * (len(self.input_descs) + len(self.output_descs))
Expand Down
87 changes: 87 additions & 0 deletions test/python/nnfusion_wsl_codegen_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import os
import sys
import json
import socket
import argparse
import subprocess
from contextlib import contextmanager
from wslpath import wslpath
# pip install wslpath-python


@contextmanager
def cd(newdir):
prevdir = os.getcwd()
os.chdir(os.path.expanduser(newdir))
try:
yield
finally:
os.chdir(prevdir)


def run(exec_path, port = 65432, host = '127.0.0.1'):
cmd_options = [
'-f onnx',
'-p "batch_size:1"',
'-fmulti_shape=false',
'-fort_folding=false',
'-fdefault_device=HLSL',
'-fhlsl_codegen_type=cpp',
'-fantares_mode=true',
'-fblockfusion_level=0',
'-fkernel_fusion_level=0',
'-fkernel_tuning_steps=0',
'-ffold_where=0',
'-fsymbolic=0',
'-fsplit_softmax=0',
'-fhost_entry=0',
'-fir_based_fusion=1',
'-fextern_result_memory=1',
'-fuse_cpuprofiler=1',
'-ftuning_platform="win64"',
'-fantares_codegen_server=127.0.0.1:8880',
]
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((host, port))
s.listen()
while True:
conn, addr = s.accept()
with conn:
print(f'Connected by {addr}')
while True:
data = conn.recv(10240)
if not data:
break
params = data.decode()
ret = {
'ret' : True,
'error' : '',
}
try:
params = json.loads(params)
model_path = wslpath(params['model'])
output_dir = wslpath(params['output_dir'])
with cd(output_dir):
cmd = ' '.join([exec_path, model_path] + cmd_options)
out = subprocess.run(cmd, stderr = subprocess.STDOUT, shell = True, encoding = 'utf8')
if out.returncode != 0:
ret['ret'] = False
ret['error'] = out.stderr
print('model_path:', model_path)
print('output_dir:', output_dir)
print('return code:', out.returncode)
print('stdout:', out.stdout)
print('stderr:', out.stderr)
except Exception as e:
print(e)
ret['ret'] = False
ret['error'] = str(e)
conn.sendall(bytes(json.dumps(ret), 'utf-8'))


if __name__ == '__main__':
parser = argparse.ArgumentParser('NNFusion WSL Codegen Server')
parser.add_argument('exec_path', type = str, help = 'path to nnfusion executable')
parser.add_argument('--port', type = int, default = 65432, help = 'comunication port between WSL and host')
args = parser.parse_args()
run(os.path.abspath(args.exec_path), args.port)
Loading

0 comments on commit 35e1a76

Please sign in to comment.