mirror of
https://github.com/tensorflow/tensorflow.git
synced 2024-11-21 21:05:19 +00:00
5b7a8b07e6
We load CUDA libraries lazily using dlopen()/dlsym() primarily to comply with the manylinux rules for Python wheels, which require that libraries in a wheel only link directly against an allowlist of libraries. In order to access CUDA using dlopen()/dlsym() without changing any of our CUDA-using code, TSL contains stub implementations of CUDA APIs that, when invoked, load the relevant library, obtain the requested symbol using dlsym(), and call into that symbol. The current CUDA stub libraries were constructed using a tool based on clang inside Google, which parses the CUDA headers and generates stub code for each API. It is therefore difficult to update the stubs without access to that tool. Each stub generated by the tool is a C++ function, which is very verbose. Further, a number of manual edits are required to the generated code, making maintenance tedious. However, there is a better way. implib.so (https://github.com/yugr/Implib.so) is a tool for automatically generating stubs from a .so file. This tool is considerably simpler because it generates a stub using assembly language, in which it turns out we do not need to know the type signature of the function being called. A completely generic trampoline function will do, with little or no bespoke knowledge of each function. We can adapt it to solve our CUDA stub problem. implib-gen.py, which is the tool implib.so provides, isn't perfect for our needs, because it requires access to the .so file at stub generation time, which we don't have in our Bazel build. Instead, we can split it into two phases: get_symbols.py, which, given a .so file extracts a list of public symbols that should be present in a stub. That list of symbols is checked into the TSL tree. make_stub.py, which, given a list of symbols, generates trampolines for each function. This change changes the TSL CUDA build to use make_stub.py to generate stubs from the list of symbols at Bazel build time, allowing us to delete over 130k lines of autogenerated C++ stub code. PiperOrigin-RevId: 567635940
39 lines
989 B
Python
39 lines
989 B
Python
"""Given a .so file, lists symbols that should be included in a stub.
|
|
|
|
Example usage:
|
|
$ bazel run -c opt @local_tsl//third_party/implib_so:get_symbols
|
|
/usr/local/cuda/lib64/libcudart.so > third_party/tsl/tsl/cuda/cudart.symbols
|
|
"""
|
|
|
|
import argparse
|
|
import importlib
|
|
|
|
# We can't import implib-gen directly because it has a dash in its name.
|
|
implib = importlib.import_module('implib-gen')
|
|
|
|
|
|
def _is_exported_function(s):
|
|
return (
|
|
s['Bind'] != 'LOCAL'
|
|
and s['Type'] == 'FUNC'
|
|
and s['Ndx'] != 'UND'
|
|
and s['Name'] not in ['', '_init', '_fini']
|
|
and s['Default']
|
|
)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description='Extracts a list of symbols from a shared library'
|
|
)
|
|
parser.add_argument('library', help='Path to the .so file.')
|
|
args = parser.parse_args()
|
|
syms = implib.collect_syms(args.library)
|
|
funs = [s['Name'] for s in syms if _is_exported_function(s)]
|
|
for f in sorted(funs):
|
|
print(f)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|