Add named manual kernel registration API#20658
Conversation
Signed-off-by: goutamadwant <workwithgoutam@gmail.com>
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/20658
Note: Links to docs will display an error until the docs builds have been completed.
|
|
@pytorchbot label "release notes: api" |
|
Hi @goutamadwant, thanks for the PR! Could you address the errors in the lintrunner logs? Should be simple fixes |
Sure will take a look @nil-is-all |
Signed-off-by: goutamadwant <workwithgoutam@gmail.com>
|
@nil-is-all Addressed the lintrunner formatting issues and pushed the update. I reran the changed-file lintrunner check and the focused codegen unit tests locally. Let me know if there are any suggestions. thanks! |
|
@claude review this PR |
|
Claude finished @digantdesai's task in 4m 34s —— View job PR Review: Named manual kernel registration APII reviewed the diff against What's good
Issues / suggestions1. CMake couples the C++ function name to the CMake target name ( list(APPEND _gen_command --manual-registration
--manual-registration-lib-name=${GEN_LIB_NAME})
2. The CMake
3. Very generic CLI aliases ( 4. Minor: redundant anchors in the regex. Test verificationI attempted to run VerdictNo blocking correctness bugs in the Python codegen. The main thing I'd want addressed before merge is #1 (CMake target-name → C++ identifier coupling), since it can turn into a confusing build failure. #2 is a coverage gap worth a follow-up. The rest are minor/nits. |
Signed-off-by: goutamadwant <workwithgoutam@gmail.com>
|
@claude review this again Addressed the CMake target-name concern by sanitizing the manual registration library name before it is embedded in the generated C++ symbol. For example, target/library names with characters like I also updated the focused codegen tests and reran the changed-file lintrunner check locally. The new workflow runs are currently waiting for approval. |
shoumikhin
left a comment
There was a problem hiding this comment.
Thanks for picking up #11221 — opt-in flag with the default preserved is the right shape, and doing Buck + CMake together is appreciated. Approving. A couple of non-blocking things worth a look:
-
CMake↔codegen filename parity. The
MANUAL_REGISTRATIONbranch swaps the generated sources toRegisterKernelsEverything.cpp/RegisterKernels.h(vsRegisterCodegenUnboxedKernelsEverything.cpp). Worth confirming codegen actually emits those names in that mode and the Buck path stays consistent — a mismatch here would be a silent build break. -
CMake passes the raw
LIB_NAMEas the identifier (--manual-registration-lib-name=${GEN_LIB_NAME}). The validator requires^[A-Za-z_][A-Za-z0-9_]*$, so a target whose name has a-or.would hard-error codegen. Either sanitize-/.→_or document that manual-registration targets need identifier-safe names.
Nit: the flag has four spellings (--manual-registration-lib-name / --manual_registration_lib_name / --lib-name / --lib_name) — one canonical plus the underscore alias is plenty.
Nice validation + codegen tests otherwise; this is the right fix for the multi-lib registration collision.
Signed-off-by: goutamadwant <workwithgoutam@gmail.com>
|
Thanks for the review @shoumikhin I removed the generic For your other two points:
I also reran the focused manual registration tests and the changed-file lintrunner checks. Let me know if any other suggestions. thanks! |
shoumikhin
left a comment
There was a problem hiding this comment.
Inline findings from a holistic design and implementation review.
|
|
||
|
|
||
| def sanitize_manual_registration_lib_name(lib_name: str) -> str: | ||
| sanitized = MANUAL_REGISTRATION_LIB_NAME_SANITIZE_PATTERN.sub("_", lib_name).strip( |
There was a problem hiding this comment.
This sanitization is lossy, so distinct libraries can still generate the same global symbol. For example, foo-bar, foo.bar, and foo_bar all become register_foo_bar_kernels(), causing duplicate definitions when those libraries are linked together. Could we either reject non-identifier names or use a collision-resistant encoding/hash suffix? Avoiding registration-symbol collisions is the primary purpose of this API.
There was a problem hiding this comment.
@shoumikhin I removed the lossy sanitization. --manual-registration-lib-name now requires a valid C++ identifier, so names such as foo-bar and foo.bar fail instead of collapsing to the same generated symbol. Valid identifier names also remain unchanged and I added tests for invalid punctuation and leading digits.
| set(_srcs_list ${_out_dir}/RegisterCodegenUnboxedKernelsEverything.cpp | ||
| ${_out_dir}/Functions.h ${_out_dir}/NativeFunctions.h | ||
| ) | ||
| if(GEN_MANUAL_REGISTRATION) |
There was a problem hiding this comment.
MANUAL_REGISTRATION must now be repeated independently in both generate_bindings_for_kernels() and gen_operators_lib(). If a caller enables it on only one call, codegen and target_sources() expect different filenames (RegisterKernelsEverything.cpp versus RegisterCodegenUnboxedKernelsEverything.cpp), resulting in a missing-source build failure. Could we derive/store this mode per LIB_NAME, combine the configuration, or at least fail at configure time when the two calls disagree?
There was a problem hiding this comment.
Updated this so generate_bindings_for_kernels() records the manual-registration mode for each LIB_NAME, and gen_operators_lib() derives the mode from that configuration. Callers should no longer repeat MANUAL_REGISTRATION in both calls.
| genrule_cmd = genrule_cmd + [ | ||
| "--manual_registration", | ||
| ] | ||
| if manual_registration_lib_name: |
There was a problem hiding this comment.
If manual_registration_lib_name is supplied without manual_registration = True, this macro silently ignores the name. Direct codegen rejects the same combination with --manual-registration-lib-name requires --manual-registration. Could we add a Starlark fail() here so the public Buck API has the same validation contract?
There was a problem hiding this comment.
Added a Starlark fail() when manual_registration_lib_name is supplied without manual_registration = True, matching the validation contract of the Python codegen entry point.
| if(GEN_ADD_EXCEPTION_BOUNDARY) | ||
| set(_gen_command "${_gen_command}" --add-exception-boundary) | ||
| endif() | ||
| if(GEN_MANUAL_REGISTRATION) |
There was a problem hiding this comment.
Could we add an end-to-end CMake test for this branch? No in-tree CMake caller currently enables MANUAL_REGISTRATION, and the added Python tests only verify template rendering. A useful regression test would build two manually registered libraries, include both generated headers, call both named functions, and verify both kernel sets register. That would also catch mismatches between custom-command outputs and target_sources().
There was a problem hiding this comment.
@shoumikhin added an end-to-end CMake regression to the existing portable custom-ops workflow. It builds two independently named manual-registration libraries, includes both generated headers, calls both generated registration functions, and verifies that both operators are present in the runtime registry.
Let me know!
Signed-off-by: goutamadwant <workwithgoutam@gmail.com>
|
@shoumikhin addressed your comments / suggestions. let me know if this looks good. thanks! |
shoumikhin
left a comment
There was a problem hiding this comment.
Two things I'd like addressed on this.
-
The help text and the bzl docstring describe behavior the code does not implement. Both the
--manual-registration-lib-namehelp incodegen/gen.pyand theexecutorch_generated_libdocstring inshim_et/xplat/executorch/codegen/codegen.bzlsay "Characters that are not valid in a C++ identifier are converted to underscores." The code does the opposite:get_manual_registration_function_nameraisesValueErroron such a name, andgenerate_bindings_for_kernelsintools/cmake/Codegen.cmakehitsFATAL_ERROR. So a name likemy-ops.libis a hard build failure, not a sanitizedregister_my_ops_lib_kernels. Please update both strings to state that the lib name must already be a valid C++ identifier (I'd keep the strict validation and just correct the docs rather than add sanitization). -
In
tools/cmake/Codegen.cmake,gen_operators_librecovers the manual-registration flag by reading a GLOBAL property keyed onSHA256(LIB_NAME)thatgenerate_bindings_for_kernelsset earlier. This is an implicit contract between two separate function calls with an ordering hazard: ifgen_operators_libruns beforegenerate_bindings_for_kernelsfor the sameLIB_NAME, the property is empty, it silently selectsRegisterCodegenUnboxedKernelsEverything.cpp(which is never generated in manual mode), and the build fails at compile time with no indication of the cause. Please pass this explicitly instead: add aMANUAL_REGISTRATIONoption togen_operators_lib, symmetric withgenerate_bindings_for_kernels, and set it from the caller. That removes the hidden global state and the ordering trap. If you prefer to keep the property channel, at least drop the SHA256 hashing, sinceLIB_NAMEis already validated as a C++ identifier and is a legal property suffix, so the hash only hides the key fromcmake --trace.
@shoumikhin Addressed both these points in the latest push. below are the highlights.
test pass locally. Let me know if there are any other suggestions/comments. |
Summary
Adds an opt-in library-name parameter for manual kernel registration codegen so generated
RegisterKernels.{h,cpp}can expose a library-specific registration API such asregister_portable_ops_lib_kernels().The default manual registration API remains
register_all_kernels()when no library name is provided. Named registration requires a valid C++ identifier, preventing distinct library names from collapsing to the same generated symbol.CMake records the registration mode during code generation and reuses it when creating the operator library, so callers do not need to repeat the option. The Buck macro supports the same optional name and rejects a name supplied without manual registration.
Fixes #11221.
Test plan
PYTHONPATH=.. python3 -m unittest codegen.test.test_executorch_gen codegen.test.test_executorch_signatures codegen.test.test_executorch_types codegen.test.test_executorch_unboxing codegen.test.test_selective_buildpython3 -m py_compile codegen/gen.py codegen/test/test_executorch_gen.pylintrunnerchecksnamed_manual_registration_testtarget withTEST_NAMED_MANUAL_REGISTRATION=ONnamed_manual_registration_test, which registers two generated libraries and verifies both operators are presentgit diff --checkcc @larryliu0820 @JacobSzwejbka @lucylq