Skip to content

Commit 911e9a3

Browse files
GregoryComerfacebook-github-bot
authored andcommitted
Build optimized library with CMake (#2530)
Summary: Support optimized kernel library in CMake builds. Overriding pre-existing CI failures in llama runner and mac unit test. bypass-github-export-checks bypass-github-executorch-ci-checks Pull Request resolved: #2530 Test Plan: Built and ran example models using combined optimized+portable target. CI is clean, barring pre-existing failures. Also, confirmed that optimized kernel is being used by running add example and adding temporary logging to optimized kernel. Reviewed By: kimishpatel Differential Revision: D55118200 Pulled By: GregoryComer fbshipit-source-id: b094980e9fc402e316a4d7cfb24ee3646a00d64e
1 parent 24fe99c commit 911e9a3

File tree

23 files changed

+599
-41
lines changed

23 files changed

+599
-41
lines changed

CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,9 @@ endif()
309309
# operators necessary for the models that will run.
310310
#
311311
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/kernels/portable)
312+
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/kernels/optimized)
313+
314+
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/configurations)
312315

313316
#
314317
# gflags: Commandline flag host library.
@@ -336,7 +339,7 @@ cmake_dependent_option(
336339
EXECUTORCH_BUILD_HOST_TARGETS OFF)
337340
if(EXECUTORCH_BUILD_EXECUTOR_RUNNER)
338341
# Baseline libraries that executor_runner will link against.
339-
set(_executor_runner_libs executorch portable_ops_lib gflags)
342+
set(_executor_runner_libs executorch optimized_native_cpu_ops_lib gflags)
340343

341344
# Generate lib to register quantized ops
342345
if(REGISTER_QUANTIZED_OPS)

build/Codegen.cmake

Lines changed: 52 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,21 @@ function(gen_selected_ops ops_schema_yaml root_ops include_all_ops)
3737
endfunction()
3838

3939
# Codegen for registering kernels. Kernels are defined in functions_yaml and
40-
# custom_ops_yaml
41-
function(generate_bindings_for_kernels functions_yaml custom_ops_yaml)
40+
# custom_ops_yaml.
41+
#
42+
# Invoked as
43+
# generate_bindings_for_kernels(
44+
# FUNCTIONS_YAML functions_yaml
45+
# CUSTOM_OPS_YAML custom_ops_yaml
46+
# )
47+
function(generate_bindings_for_kernels)
48+
set(arg_names FUNCTIONS_YAML CUSTOM_OPS_YAML)
49+
cmake_parse_arguments(GEN "" "${arg_names}" "" ${ARGN})
50+
51+
message(STATUS "Generating kernel bindings:")
52+
message(STATUS " FUNCTIONS_YAML: ${GEN_FUNCTIONS_YAML}")
53+
message(STATUS " CUSTOM_OPS_YAML: ${GEN_CUSTOM_OPS_YAML}")
54+
4255
# Command to generate selected_operators.yaml from custom_ops.yaml.
4356
file(GLOB_RECURSE _codegen_templates "${EXECUTORCH_ROOT}/codegen/templates/*")
4457
file(GLOB_RECURSE _torchgen_srcs "${TORCH_ROOT}/torchgen/*.py")
@@ -60,11 +73,11 @@ function(generate_bindings_for_kernels functions_yaml custom_ops_yaml)
6073
${CMAKE_CURRENT_BINARY_DIR}/Functions.h
6174
${CMAKE_CURRENT_BINARY_DIR}/NativeFunctions.h)
6275

63-
if(functions_yaml)
64-
list(APPEND _gen_command --functions-yaml-path=${functions_yaml})
76+
if(GEN_FUNCTIONS_YAML)
77+
list(APPEND _gen_command --functions-yaml-path=${GEN_FUNCTIONS_YAML})
6578
endif()
66-
if(custom_ops_yaml)
67-
list(APPEND _gen_command --custom-ops-yaml-path=${custom_ops_yaml})
79+
if(GEN_CUSTOM_OPS_YAML)
80+
list(APPEND _gen_command --custom-ops-yaml-path=${GEN_CUSTOM_OPS_YAML})
6881
list(
6982
APPEND
7083
_gen_command_sources
@@ -77,7 +90,7 @@ function(generate_bindings_for_kernels functions_yaml custom_ops_yaml)
7790
COMMENT "Generating code for kernel registration"
7891
OUTPUT ${_gen_command_sources}
7992
COMMAND ${_gen_command}
80-
DEPENDS ${_oplist_yaml} ${custom_ops_yaml} ${functions_yaml}
93+
DEPENDS ${_oplist_yaml} ${GEN_CUSTOM_OPS_YAML} ${GEN_FUNCTIONS_YAML}
8194
${_codegen_templates} ${_torchgen_srcs}
8295
WORKING_DIRECTORY ${EXECUTORCH_ROOT})
8396
# Make generated file list available in parent scope
@@ -107,18 +120,46 @@ function(gen_custom_ops_aot_lib lib_name kernel_sources)
107120
endfunction()
108121

109122
# Generate a runtime lib for registering operators in Executorch
110-
function(gen_operators_lib lib_name kernel_lib deps)
123+
function(gen_operators_lib lib_name)
124+
set(multi_arg_names KERNEL_LIBS DEPS)
125+
cmake_parse_arguments(GEN "" "" "${multi_arg_names}" ${ARGN})
126+
127+
message(STATUS "Generating operator lib:")
128+
message(STATUS " LIB_NAME: ${lib_name}")
129+
message(STATUS " KERNEL_LIBS: ${GEN_KERNEL_LIBS}")
130+
message(STATUS " DEPS: ${GEN_DEPS}")
131+
111132
add_library(${lib_name})
112133
target_sources(
113134
${lib_name}
114135
PRIVATE
115136
${CMAKE_CURRENT_BINARY_DIR}/RegisterCodegenUnboxedKernelsEverything.cpp
116137
${CMAKE_CURRENT_BINARY_DIR}/Functions.h
117138
${CMAKE_CURRENT_BINARY_DIR}/NativeFunctions.h)
118-
target_link_libraries(${lib_name} PRIVATE ${deps})
119-
if(kernel_lib)
120-
target_link_libraries(${lib_name} PRIVATE ${kernel_lib})
139+
target_link_libraries(${lib_name} PRIVATE ${GEN_DEPS})
140+
if(GEN_KERNEL_LIBS)
141+
target_link_libraries(${lib_name} PRIVATE ${GEN_KERNEL_LIBS})
121142
endif()
122143

123144
target_link_options_shared_lib(${lib_name})
124145
endfunction()
146+
147+
# Merge two kernel yaml files, prioritizing functions from FUNCTIONS_YAML
148+
# and taking functions from FALLBACK_YAML when no implementation is found.
149+
# This corresponds to the merge_yaml buck implementation in codegen/tools.
150+
function(merge_yaml)
151+
set(arg_names FUNCTIONS_YAML FALLBACK_YAML OUTPUT_DIR)
152+
cmake_parse_arguments(GEN "" "${arg_names}" "" ${ARGN})
153+
154+
set(_gen_command
155+
"${PYTHON_EXECUTABLE}" -m codegen.tools.merge_yaml
156+
--functions_yaml_path=${GEN_FUNCTIONS_YAML}
157+
--fallback_yaml_path=${GEN_FALLBACK_YAML}
158+
--output_dir=${GEN_OUTPUT_DIR})
159+
160+
add_custom_command(
161+
COMMENT "Merging kernel yaml files"
162+
OUTPUT ${GEN_OUTPUT_DIR}/merged.yaml
163+
COMMAND ${_gen_command}
164+
WORKING_DIRECTORY ${EXECUTORCH_ROOT})
165+
endfunction()

build/cmake_deps.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,22 @@ deps = [
4545
"executorch",
4646
]
4747

48+
[targets.optimized_kernels]
49+
buck_targets = [
50+
"//kernels/optimized:generated_lib",
51+
]
52+
filters = [
53+
".cpp$",
54+
]
55+
excludes = [
56+
# Exclude the codegen templates, which are picked up because the buck target
57+
# is the generated_lib and not the unwrapped set of kernels.
58+
"^codegen/templates",
59+
]
60+
deps = [
61+
"executorch",
62+
]
63+
4864
[targets.quantized_kernels]
4965
buck_targets = [
5066
"//kernels/quantized:generated_lib",

codegen/tools/merge_yaml.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,20 @@
1212

1313
import yaml
1414

15-
from executorch.codegen.tools.yaml_util import BlankLineDumper
16-
1715
try:
1816
from yaml import CSafeLoader as Loader
1917
except ImportError:
2018
from yaml import SafeLoader as Loader # type: ignore[misc]
2119

2220

21+
class BlankLineDumper(yaml.SafeDumper):
22+
def write_line_break(self, data=None):
23+
super().write_line_break(data)
24+
# insert a new line between entries.
25+
if len(self.indents) == 1:
26+
super().write_line_break()
27+
28+
2329
def merge(functions_yaml_path: str, fallback_yaml_path: Optional[str], output_dir: str):
2430
output_file = os.path.join(output_dir, "merged.yaml")
2531

configurations/CMakeLists.txt

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
# All rights reserved.
3+
#
4+
# This source code is licensed under the BSD-style license found in the
5+
# LICENSE file in the root directory of this source tree.
6+
7+
cmake_minimum_required(VERSION 3.19)
8+
9+
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
10+
if(NOT CMAKE_CXX_STANDARD)
11+
set(CMAKE_CXX_STANDARD 17)
12+
endif()
13+
14+
if(NOT PYTHON_EXECUTABLE)
15+
set(PYTHON_EXECUTABLE python3)
16+
endif()
17+
# Source root directory for executorch.
18+
if(NOT EXECUTORCH_ROOT)
19+
set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/..)
20+
endif()
21+
# Source root directory for pytorch. This is needed for kernel binding.
22+
if(NOT TORCH_ROOT)
23+
set(TORCH_ROOT ${EXECUTORCH_ROOT}/third-party/pytorch)
24+
endif()
25+
26+
set(_common_compile_options -Wno-deprecated-declarations)
27+
28+
include(${EXECUTORCH_ROOT}/build/Utils.cmake)
29+
include(${EXECUTORCH_ROOT}/build/Codegen.cmake)
30+
31+
32+
# Merge optimized and portable definitions, taking optimized where available.
33+
merge_yaml(
34+
FUNCTIONS_YAML ${EXECUTORCH_ROOT}/kernels/optimized/optimized-oss.yaml
35+
FALLBACK_YAML ${EXECUTORCH_ROOT}/kernels/portable/functions.yaml
36+
OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}
37+
)
38+
39+
gen_selected_ops("${CMAKE_CURRENT_BINARY_DIR}/merged.yaml" "" "")
40+
41+
generate_bindings_for_kernels(
42+
FUNCTIONS_YAML ${CMAKE_CURRENT_BINARY_DIR}/merged.yaml)
43+
message("Generated files ${gen_command_sources}")
44+
45+
# optimized_native_cpu_ops_lib: Register optimized op kernels into the runtime
46+
gen_operators_lib(
47+
"optimized_native_cpu_ops_lib"
48+
KERNEL_LIBS portable_kernels optimized_kernels
49+
DEPS executorch)
50+
51+
install(TARGETS optimized_native_cpu_ops_lib DESTINATION lib)

docs/source/kernel-library-custom-aten-kernel.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,16 +143,16 @@ We provide build time macros to help users to build their kernel registration li
143143

144144
#### CMake
145145

146-
`generate_bindings_for_kernels(functions_yaml, custom_ops_yaml)` takes a yaml file for core ATen op out variants and also a yaml file for custom ops, generate C++ bindings for kernel registration. It also depends on the selective build artifact generated by `gen_selected_ops()`, see selective build doc for more information. Then `gen_operators_lib` will package those bindings to be a C++ library. As an example:
146+
`generate_bindings_for_kernels(FUNCTIONS_YAML functions_yaml CUSTOM_OPS_YAML custom_ops_yaml)` takes a yaml file for core ATen op out variants and also a yaml file for custom ops, generate C++ bindings for kernel registration. It also depends on the selective build artifact generated by `gen_selected_ops()`, see selective build doc for more information. Then `gen_operators_lib` will package those bindings to be a C++ library. As an example:
147147
```cmake
148148
# SELECT_OPS_LIST: aten::add.out,aten::mm.out
149149
gen_selected_ops("" "${SELECT_OPS_LIST}" "")
150150
151151
# Look for functions.yaml associated with portable libs and generate C++ bindings
152-
generate_bindings_for_kernels(${EXECUTORCH_ROOT}/kernels/portable/functions.yaml "")
152+
generate_bindings_for_kernels(FUNCTIONS_YAML ${EXECUTORCH_ROOT}/kernels/portable/functions.yaml)
153153
154154
# Prepare a C++ library called "generated_lib" with _kernel_lib being the portable library, executorch is a dependency of it.
155-
gen_operators_lib("generated_lib" ${_kernel_lib} executorch)
155+
gen_operators_lib("generated_lib" KERNEL_LIBS ${_kernel_lib} DEPS executorch)
156156
157157
# Link "generated_lib" into the application:
158158
target_link_libraries(executorch_binary generated_lib)

examples/apple/mps/CMakeLists.txt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,12 @@ include(${EXECUTORCH_ROOT}/build/Utils.cmake)
6868
include(${EXECUTORCH_ROOT}/build/Codegen.cmake)
6969
gen_selected_ops("" "" "ON")
7070
generate_bindings_for_kernels(
71-
${EXECUTORCH_ROOT}/kernels/portable/functions.yaml ""
71+
FUNCTIONS_YAML ${EXECUTORCH_ROOT}/kernels/portable/functions.yaml
7272
)
73-
gen_operators_lib("portable_ops_lib" portable_kernels executorch)
73+
gen_operators_lib(
74+
"portable_ops_lib"
75+
KERNEL_LIBS portable_kernels
76+
DEPS executorch)
7477

7578
set(mps_executor_runner_libs "-framework Foundation"
7679
"-weak_framework MetalPerformanceShaders"

examples/arm/CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,7 @@ include(${EXECUTORCH_ROOT}/build/Codegen.cmake)
4444
# Executorch (for runtime). Here select all ops in functions.yaml
4545
gen_selected_ops("" "${EXECUTORCH_SELECT_OPS_LIST}" "")
4646
generate_bindings_for_kernels(
47-
${EXECUTORCH_ROOT}/kernels/portable/functions.yaml "")
48-
gen_operators_lib("arm_portable_ops_lib" portable_kernels executorch)
47+
FUNCTIONS_YAML ${EXECUTORCH_ROOT}/kernels/portable/functions.yaml)
48+
gen_operators_lib("arm_portable_ops_lib"
49+
KERNEL_LIBS portable_kernels
50+
DEPS executorch)

examples/portable/custom_ops/CMakeLists.txt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ elseif(REGISTER_EXAMPLE_CUSTOM_OP EQUAL 2)
8181
gen_selected_ops("" "my_ops::mul4.out" "")
8282
endif()
8383
# Expect gen_selected_ops output file to be selected_operators.yaml
84-
generate_bindings_for_kernels("" ${CMAKE_CURRENT_LIST_DIR}/custom_ops.yaml)
84+
generate_bindings_for_kernels(
85+
CUSTOM_OPS_YAML ${CMAKE_CURRENT_LIST_DIR}/custom_ops.yaml)
8586
message("Generated files ${gen_command_sources}")
8687

8788
# Prepare for C++ libraries.
@@ -109,7 +110,10 @@ add_library(custom_kernels ${kernel_sources})
109110
target_link_libraries(custom_kernels PRIVATE executorch)
110111
target_compile_options(custom_kernels PUBLIC ${_common_compile_options})
111112

112-
gen_operators_lib("custom_ops_lib" custom_kernels executorch)
113+
gen_operators_lib(
114+
"custom_ops_lib"
115+
KERNEL_LIBS custom_kernels
116+
DEPS executorch)
113117

114118
list(TRANSFORM _executor_runner__srcs PREPEND "${EXECUTORCH_ROOT}/")
115119

examples/qualcomm/CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,11 @@ set(_qnn_executor_runner__srcs ${_executor_runner__srcs})
5858
include(${EXECUTORCH_ROOT}/build/Codegen.cmake)
5959
gen_selected_ops("" "" "ON")
6060
generate_bindings_for_kernels(
61-
${EXECUTORCH_ROOT}/kernels/portable/functions.yaml ""
61+
FUNCTIONS_YAML ${EXECUTORCH_ROOT}/kernels/portable/functions.yaml
6262
)
63-
gen_operators_lib("full_portable_ops_lib" portable_kernels executorch)
63+
gen_operators_lib("full_portable_ops_lib"
64+
KERNEL_LIBS portable_kernels
65+
DEPS executorch)
6466
target_compile_options(full_portable_ops_lib
6567
INTERFACE
6668
-DET_EVENT_TRACER_ENABLED

examples/sdk/CMakeLists.txt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,12 @@ target_compile_options(executorch INTERFACE -DET_EVENT_TRACER_ENABLED)
5151
gen_selected_ops("" "" "ON")
5252
# Expect gen_selected_ops output file to be selected_operators.yaml
5353
generate_bindings_for_kernels(
54-
${EXECUTORCH_ROOT}/kernels/portable/functions.yaml ""
54+
FUNCTIONS_YAML ${EXECUTORCH_ROOT}/kernels/portable/functions.yaml
5555
)
56-
gen_operators_lib("portable_ops_lib" portable_kernels executorch)
56+
gen_operators_lib(
57+
"portable_ops_lib"
58+
KERNEL_LIBS portable_kernels
59+
DEPS executorch)
5760

5861
target_compile_options(portable_ops_lib INTERFACE -DET_EVENT_TRACER_ENABLED)
5962
target_include_directories(

examples/selective_build/CMakeLists.txt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,13 @@ gen_selected_ops(
9999
"${EXECUTORCH_SELECT_OPS_LIST}"
100100
"${EXECUTORCH_SELECT_ALL_OPS}")
101101

102-
generate_bindings_for_kernels(${EXECUTORCH_ROOT}/kernels/portable/functions.yaml
103-
"${_custom_ops_yaml}")
104-
gen_operators_lib("select_build_lib" ${_kernel_lib} executorch)
102+
generate_bindings_for_kernels(
103+
FUNCTIONS_YAML ${EXECUTORCH_ROOT}/kernels/portable/functions.yaml
104+
CUSTOM_OPS_YAML "${_custom_ops_yaml}")
105+
gen_operators_lib(
106+
"select_build_lib"
107+
KERNEL_LIBS ${_kernel_lib}
108+
DEPS executorch)
105109

106110
list(TRANSFORM _executor_runner__srcs PREPEND "${EXECUTORCH_ROOT}/")
107111

examples/xtensa/ops/CMakeLists.txt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,11 @@ target_link_libraries(custom_ops PRIVATE xtensa_kernels)
4242
# Generate C++ bindings to register kernels into both PyTorch (for AOT) and
4343
# Executorch (for runtime). Here select all ops in functions.yaml
4444
gen_selected_ops("${CMAKE_CURRENT_LIST_DIR}/functions.yaml" "" "")
45-
generate_bindings_for_kernels(${CMAKE_CURRENT_SOURCE_DIR}/functions.yaml "")
45+
generate_bindings_for_kernels(
46+
FUNCTIONS_YAML ${CMAKE_CURRENT_SOURCE_DIR}/functions.yaml)
4647
message("Generated files ${gen_command_sources}")
4748

48-
gen_operators_lib("xtensa_ops_lib" custom_ops aten_ops_xtensa)
49+
gen_operators_lib(
50+
"xtensa_ops_lib"
51+
KERNEL_LIBS custom_ops
52+
DEPS aten_ops_xtensa)

0 commit comments

Comments
 (0)