Skip to content

Commit c0b42d2

Browse files
larryliu0820facebook-github-bot
authored andcommitted
Introduce pybind11 and build extension/pybindings/portable_lib (#332)
Summary: Build Pybind11 shared library and load it into python environment. This way we can use `Module` python API to run end2end tests. Add `test_end2end.py` in `pytest.ini` so that we have e2e test coverage. Pull Request resolved: #332 Reviewed By: tarun292 Differential Revision: D49254089 Pulled By: larryliu0820 fbshipit-source-id: cc3698bdd6620176d64e14027a37ed5b9897704a
1 parent c226e6f commit c0b42d2

File tree

16 files changed

+175
-44
lines changed

16 files changed

+175
-44
lines changed

.github/workflows/_unittest.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,22 @@ jobs:
3636
# Setup MacOS dependencies as there is no Docker support on MacOS atm
3737
PYTHON_EXECUTABLE=python bash .ci/scripts/setup-linux.sh "${BUILD_TOOL}"
3838
39+
# Build //extension/pybindings:portable_lib. Example path:
40+
# buck-out/v2/gen/root/524f8da68ea2a374/extension/pybindings/__portable_lib__/portable_lib.so
41+
SO_LIB_DIR=$(buck2 build //extension/pybindings:portable_lib --show-output | cut -d' ' -f2 | xargs dirname)
42+
43+
# Let LD_LIBRARY_PATH include libtorch_python directory
44+
PYTHON_LIB_DIR=$(python -c 'from distutils.sysconfig import get_python_lib; print(get_python_lib())')
45+
export LD_LIBRARY_PATH="${PYTHON_LIB_DIR}/torch/lib"
46+
47+
# Let PYTHONPATH include the output directory so that portable_lib.so can be loaded into Python.
48+
export PYTHONPATH="${SO_LIB_DIR}:${PYTHON_LIB_DIR}/torch/lib"
49+
50+
# Generate a shim file in extension/pybindings/portable_lib/
51+
SHIM_PY="${PYTHON_LIB_DIR}/executorch/extension/pybindings/portable_lib.py"
52+
touch ${SHIM_PY}
53+
echo "from portable_lib import _load_for_executorch_from_buffer,_load_bundled_program_from_buffer,_load_for_executorch_from_bundled_program" > ${SHIM_PY}
54+
3955
# Run pytest with coverage
4056
pytest -n auto --cov=./ --cov-report=xml
4157
@@ -59,6 +75,22 @@ jobs:
5975
# Setup MacOS dependencies as there is no Docker support on MacOS atm
6076
PYTHON_EXECUTABLE=python bash .ci/scripts/setup-macos.sh "${BUILD_TOOL}"
6177
78+
# Build //extension/pybindings:portable_lib. Example path:
79+
# buck-out/v2/gen/root/524f8da68ea2a374/extension/pybindings/__portable_lib__/portable_lib.dylib
80+
SO_LIB_DIR=$(buck2 build //extension/pybindings:portable_lib --show-output | cut -d' ' -f2 | xargs dirname)
81+
82+
# Let LD_LIBRARY_PATH include libtorch_python directory
83+
PYTHON_LIB_DIR=$(python -c 'from distutils.sysconfig import get_python_lib; print(get_python_lib())')
84+
export LD_LIBRARY_PATH="${PYTHON_LIB_DIR}/torch/lib"
85+
86+
# Let PYTHONPATH include the output directory so that portable_lib.dylib can be loaded into Python.
87+
export PYTHONPATH="${SO_LIB_DIR}:${PYTHON_LIB_DIR}/torch/lib"
88+
89+
# Generate a shim file in extension/pybindings/portable_lib/
90+
SHIM_PY="${PYTHON_LIB_DIR}/executorch/extension/pybindings/portable_lib.py"
91+
touch ${SHIM_PY}
92+
echo "from portable_lib import _load_for_executorch_from_buffer,_load_bundled_program_from_buffer,_load_for_executorch_from_bundled_program" > ${SHIM_PY}
93+
6294
# Run pytest with coverage
6395
pytest -n auto --cov=./ --cov-report=xml
6496
# Run gtest

backends/transforms/TARGETS

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
#load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime")
2-
load("@fbcode_macros//build_defs:python_library.bzl", "python_library")
1+
load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime")
32

4-
python_library(
3+
runtime.python_library(
54
name = "lib",
65
srcs = [
76
"__init__.py",
@@ -14,9 +13,12 @@ python_library(
1413
],
1514
)
1615

17-
python_library(
16+
runtime.python_library(
1817
name = "addmm_mm_to_linear",
1918
srcs = ["addmm_mm_to_linear.py"],
19+
visibility = [
20+
"//executorch/backends/...",
21+
],
2022
deps = [
2123
"//caffe2:torch",
2224
"//executorch/exir:pass_base",

backends/xnnpack/test/TARGETS

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
load("@fbcode_macros//build_defs:python_unittest.bzl", "python_unittest")
1+
load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime")
22
load(":targets.bzl", "define_common_targets")
33

44
define_common_targets()
55

6-
python_unittest(
6+
runtime.python_test(
77
name = "test_xnnpack",
88
srcs = [
99
"test_xnnpack.py",
@@ -16,7 +16,6 @@ python_unittest(
1616
],
1717
tags = ["long_running"],
1818
deps = [
19-
"//caffe2:torch",
2019
"//executorch/backends/xnnpack:xnnpack_backend",
2120
"//executorch/backends/xnnpack:xnnpack_preprocess",
2221
"//executorch/backends/xnnpack/partition:xnnpack_partitioner",
@@ -30,9 +29,12 @@ python_unittest(
3029
"//executorch/sdk/bundled_program:core",
3130
"//executorch/sdk/bundled_program/serialize:lib",
3231
],
32+
external_deps = [
33+
"libtorch",
34+
],
3335
)
3436

35-
python_unittest(
37+
runtime.python_test(
3638
name = "test_xnnpack_quantized",
3739
srcs = [
3840
"test_xnnpack_quantized.py",
@@ -44,7 +46,6 @@ python_unittest(
4446
],
4547
tags = ["long_running"],
4648
deps = [
47-
"//caffe2:torch",
4849
"//executorch/backends/xnnpack:xnnpack_backend",
4950
"//executorch/backends/xnnpack:xnnpack_preprocess",
5051
"//executorch/backends/xnnpack/partition:xnnpack_partitioner",
@@ -59,9 +60,12 @@ python_unittest(
5960
"//executorch/sdk/bundled_program:core",
6061
"//executorch/sdk/bundled_program/serialize:lib",
6162
],
63+
external_deps = [
64+
"libtorch",
65+
],
6266
)
6367

64-
python_unittest(
68+
runtime.python_test(
6569
name = "test_xnnpack_quantized_models",
6670
srcs = [
6771
"test_xnnpack_quantized_models.py",
@@ -73,7 +77,6 @@ python_unittest(
7377
],
7478
tags = ["long_running"],
7579
deps = [
76-
"//caffe2:torch",
7780
"//executorch/backends/xnnpack:xnnpack_backend",
7881
"//executorch/backends/xnnpack:xnnpack_preprocess",
7982
"//executorch/backends/xnnpack/partition:xnnpack_partitioner",
@@ -88,9 +91,12 @@ python_unittest(
8891
"//executorch/sdk/bundled_program/serialize:lib",
8992
"//pytorch/vision:torchvision",
9093
],
94+
external_deps = [
95+
"libtorch",
96+
],
9197
)
9298

93-
python_unittest(
99+
runtime.python_test(
94100
name = "test_xnnpack_passes",
95101
srcs = glob([
96102
"passes/*.py",
@@ -99,7 +105,6 @@ python_unittest(
99105
"test_xnnpack_utils_classes.py",
100106
],
101107
deps = [
102-
"//caffe2:torch",
103108
"//executorch/backends/xnnpack/passes:xnnpack_passes",
104109
"//executorch/backends/xnnpack/test/tester:tester",
105110
"//executorch/backends/xnnpack/utils:xnnpack_utils",
@@ -108,21 +113,26 @@ python_unittest(
108113
"//executorch/exir/backend/canonical_partitioners:canonical_partitioner_lib",
109114
"//executorch/exir/dialects:lib",
110115
],
116+
external_deps = [
117+
"libtorch",
118+
],
111119
)
112120

113-
python_unittest(
121+
runtime.python_test(
114122
name = "test_xnnpack_ops",
115123
srcs = glob([
116124
"ops/*.py",
117125
]),
118126
deps = [
119-
"//caffe2:torch",
120127
"//executorch/backends/xnnpack/partition:xnnpack_partitioner",
121128
"//executorch/backends/xnnpack/test/tester:tester",
122129
],
130+
external_deps = [
131+
"libtorch",
132+
],
123133
)
124134

125-
python_unittest(
135+
runtime.python_test(
126136
name = "test_xnnpack_models",
127137
srcs = glob([
128138
"models/*.py",
@@ -131,8 +141,10 @@ python_unittest(
131141
deps = [
132142
"fbsource//third-party/pypi/timm:timm",
133143
"fbsource//third-party/pypi/torchsr:torchsr", # @manual
134-
"//caffe2:torch",
135144
"//executorch/backends/xnnpack/test/tester:tester",
136145
"//pytorch/vision:torchvision", # @manual
137146
],
147+
external_deps = [
148+
"libtorch",
149+
],
138150
)

extension/aten_util/targets.bzl

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,7 @@ def define_common_targets():
2929
"//executorch/runtime/core:core",
3030
"//executorch/runtime/core/exec_aten:lib",
3131
],
32-
fbcode_deps = [
33-
"//caffe2:ATen-core",
34-
"//caffe2:ATen-cpu",
35-
"//caffe2/c10:c10",
36-
],
37-
xplat_deps = [
38-
"//xplat/caffe2:torch_mobile_core",
39-
"//xplat/caffe2/c10:c10",
32+
external_deps = [
33+
"torch-core-cpp",
4034
],
4135
)

extension/pybindings/TARGETS

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
# Any targets that should be shared between fbcode and xplat must be defined in
33
# targets.bzl. This file can contain fbcode-only targets.
44

5-
load("@fbcode//executorch/extension/pybindings:pybindings.bzl", "ATEN_MODULE_DEPS", "MODELS_ATEN_OPS_ATEN_MODE_GENERATED_LIB", "MODELS_ATEN_OPS_LEAN_MODE_GENERATED_LIB", "PORTABLE_MODULE_DEPS", "executorch_pybindings")
65
load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime")
6+
load("@fbsource//xplat/executorch/extension/pybindings:pybindings.bzl", "ATEN_MODULE_DEPS", "MODELS_ATEN_OPS_ATEN_MODE_GENERATED_LIB", "MODELS_ATEN_OPS_LEAN_MODE_GENERATED_LIB", "PORTABLE_MODULE_DEPS", "executorch_pybindings")
77

88
# Export this so the internal fb/ subdir can create pybindings with custom internal deps
99
# without forking the pybinding source.
@@ -36,19 +36,22 @@ runtime.genrule(
3636
)
3737

3838
executorch_pybindings(
39+
compiler_flags = ["-std=c++17"],
3940
cppdeps = PORTABLE_MODULE_DEPS,
4041
python_module_name = "core",
4142
visibility = ["PUBLIC"],
4243
)
4344

4445
executorch_pybindings(
46+
compiler_flags = ["-std=c++17"],
4547
cppdeps = PORTABLE_MODULE_DEPS + MODELS_ATEN_OPS_LEAN_MODE_GENERATED_LIB,
4648
python_module_name = "portable_lib",
4749
types = ["//executorch/extension/pybindings:pybindings_types_gen[portable_lib.pyi]"],
4850
visibility = ["PUBLIC"],
4951
)
5052

5153
executorch_pybindings(
54+
compiler_flags = ["-std=c++17"],
5255
cppdeps = ATEN_MODULE_DEPS + MODELS_ATEN_OPS_ATEN_MODE_GENERATED_LIB,
5356
python_module_name = "aten_lib",
5457
types = ["//executorch/extension/pybindings:pybindings_types_gen[aten_lib.pyi]"],

pytest.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ addopts =
3636
kernels/test/test_case_gen.py
3737
# backends/arm
3838
backends/arm/test
39+
# test
40+
test/end2end/test_end2end.py
3941

4042
# run the same tests multiple times to determine their
4143
# flakiness status. Default to 50 re-runs
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
def get_all_cpu_backend_targets():
2+
"""Returns a list of all CPU backend targets.
3+
4+
For experimenting and testing, not for production, since it will typically
5+
include more than necessary for a particular product.
6+
"""
7+
return [
8+
"//executorch/backends/xnnpack:xnnpack_backend",
9+
]
10+
11+
def get_all_cpu_aot_and_backend_targets():
12+
"""Returns a list of all CPU backend targets with aot (ahead of time).
13+
14+
For experimenting and testing, not for production, since it will typically
15+
include more than necessary for a particular product.
16+
"""
17+
return [
18+
"//executorch/backends/xnnpack:xnnpack_preprocess",
19+
"//executorch/backends/xnnpack/partition:xnnpack_partitioner",
20+
] + get_all_cpu_backend_targets()

shim/xplat/executorch/build/env_interface.bzl

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,11 @@ _EXTERNAL_DEPS = {
3939
"gtest": "//third-party:gtest",
4040
"gtest_aten": "//third-party:gtest_aten",
4141
"libtorch": "//third-party:libtorch",
42+
"libtorch_python": "//third-party:libtorch_python",
4243
"prettytable": "//third-party:prettytable",
43-
"pybind11": [], # TODO(larryliu0820): Add support
44+
"pybind11": "//third-party:pybind11",
4445
# Core C++ PyTorch functionality like Tensor and ScalarType.
45-
"torch-core-cpp": [], # TODO(larryliu0820): Add support
46+
"torch-core-cpp": "//third-party:libtorch",
4647
"torchgen": "//third-party:torchgen",
4748
}
4849

@@ -95,6 +96,13 @@ def _patch_deps(kwargs, dep_type):
9596
def _patch_platform_build_mode_flags(kwargs):
9697
return kwargs
9798

99+
def _patch_force_static(kwargs):
100+
"""For OSS cxx library, force static linkage unless specify otherwise.
101+
"""
102+
if "force_static" not in kwargs:
103+
kwargs["force_static"] = True
104+
return kwargs
105+
98106
def _remove_platform_specific_args(kwargs):
99107
"""Removes platform specific arguments for BUCK builds
100108
@@ -118,6 +126,7 @@ def _remove_platform_specific_args(kwargs):
118126
def _remove_unsupported_kwargs(kwargs):
119127
"""Removes environment unsupported kwargs
120128
"""
129+
kwargs.pop("tags", None) # tags = ["long_running"] doesn't work in oss
121130
kwargs.pop("types", None) # will have to find a different way to handle .pyi files in oss
122131
return kwargs
123132

@@ -204,6 +213,7 @@ env = struct(
204213
patch_deps = _patch_deps,
205214
patch_cxx_compiler_flags = _patch_cxx_compiler_flags,
206215
patch_executorch_genrule_cmd = _patch_executorch_genrule_cmd,
216+
patch_force_static = _patch_force_static,
207217
patch_headers = _patch_headers,
208218
patch_platform_build_mode_flags = _patch_platform_build_mode_flags,
209219
patch_platforms = _patch_platforms,

shim/xplat/executorch/build/runtime_wrapper.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ def _cxx_library_common(*args, **kwargs):
230230
env.patch_headers(kwargs)
231231
env.patch_pp_flags(kwargs)
232232
env.patch_cxx_compiler_flags(kwargs)
233+
env.patch_force_static(kwargs)
233234

234235
env.cxx_library(*args, **kwargs)
235236

shim/xplat/executorch/codegen/codegen.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ def exir_custom_ops_aot_lib(
315315
supports_python_dlopen = True,
316316
platforms = platforms,
317317
compiler_flags = compiler_flags,
318+
force_static = False,
318319
)
319320

320321
def executorch_generated_lib(

shim/xplat/executorch/extension/pybindings/pybindings.bzl

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@ MODELS_ATEN_OPS_LEAN_MODE_GENERATED_LIB = [
77
]
88

99
PORTABLE_MODULE_DEPS = [
10-
"//caffe2:ATen",
11-
"//caffe2:torch",
12-
"//caffe2:torch_extension",
1310
"//executorch/runtime/kernel:operator_registry",
1411
"//executorch/runtime/executor:program",
1512
"//executorch/sdk/bundled_program/schema:bundled_program_schema_fbs",
@@ -32,9 +29,6 @@ ATEN_MODULE_DEPS = [
3229
"//executorch/extension/memory_allocator:malloc_memory_allocator",
3330
"//executorch/util:read_file",
3431
"//executorch/sdk/bundled_program:runtime_aten",
35-
"//caffe2:torch",
36-
"//caffe2:torch_extension",
37-
"//caffe2:ATen",
3832
"//executorch/runtime/executor/test:test_backend_compiler_lib_aten",
3933
]
4034

@@ -44,14 +38,15 @@ MODELS_ATEN_OPS_ATEN_MODE_GENERATED_LIB = [
4438
"//executorch/kernels/aten:generated_lib_aten",
4539
]
4640

47-
def executorch_pybindings(python_module_name, srcs = [], cppdeps = [], visibility = ["//executorch/..."], types = []):
41+
def executorch_pybindings(python_module_name, srcs = [], cppdeps = [], visibility = ["//executorch/..."], types = [], compiler_flags = []):
4842
runtime.cxx_python_extension(
4943
name = python_module_name,
5044
srcs = [
5145
"//executorch/extension/pybindings:pybindings.cpp",
5246
] + srcs,
5347
types = types,
5448
base_module = "executorch.extension.pybindings",
49+
compiler_flags = compiler_flags,
5550
preprocessor_flags = [
5651
"-DEXECUTORCH_PYTHON_MODULE_NAME={}".format(python_module_name),
5752
],
@@ -61,6 +56,7 @@ def executorch_pybindings(python_module_name, srcs = [], cppdeps = [], visibilit
6156
] + cppdeps,
6257
external_deps = [
6358
"pybind11",
59+
"libtorch_python",
6460
],
6561
use_static_deps = True,
6662
_is_external_target = bool(visibility != ["//executorch/..."]),

test/end2end/TARGETS

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ python_unittest(
5555
"//executorch/exir/tests:transformer",
5656
"//executorch/extension/pybindings:aten_lib",
5757
"//executorch/extension/pytree:pybindings",
58-
"//executorch/kernels/portable:custom_ops_generated_lib",
5958
"//executorch/sdk/bundled_program:config",
6059
"//executorch/sdk/bundled_program:core",
6160
"//executorch/sdk/bundled_program/serialize:lib",
@@ -87,7 +86,6 @@ python_unittest(
8786
"//executorch/exir/tests:transformer",
8887
"//executorch/extension/pybindings:portable_lib",
8988
"//executorch/extension/pytree:pybindings",
90-
"//executorch/kernels/portable:custom_ops_generated_lib",
9189
"//executorch/sdk/bundled_program:config",
9290
"//executorch/sdk/bundled_program:core",
9391
"//executorch/sdk/bundled_program/serialize:lib",

test/end2end/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)