feat: prefer recipe ported einops - #1092
Conversation
|
for completeness, we can bump the commit hash from and trying to rerun the command shows at this point I simply asked and llm to fix the recipe so the port works correctly and copy pasted the command and error output above. the exact output of this process can be seen in #1093 |
|
I think we should have a single standard to start this. I would prefer if we required users to specify the source and the commit in the recipe itself instead of having them locally clone and checkout to a particular branch first. Or, that should be a better default behaviour, IMO.
We should port tests, too. Then it will be down on us to make modifications there e.g., for running specific tests on our CI, etc. Cc: @danieldk here as well. |
|
Going to run the commands from the PR description and share my findings here as well. |
| find="from .packing import pack, unpack\n" \ | ||
| with="from .packing import pack, unpack\nfrom . import array_api\n" | ||
|
|
||
| // The rewritten tests and the flake. |
There was a problem hiding this comment.
We should not have to rewrite the tests much though. I think in the tests we would like to ensure that they use get_kernel() which already seems to be the case. So, I think we should rather provide similar instructions in the recipe to account for this.
pytest.mark.kernels_ci should probably be left to us because it's better if we decided which tests are lightweight and important enough to run on our CI.
There was a problem hiding this comment.
And also, I think tests should not be overlays no? Currently, we include them inside of the actual kernel source.
There was a problem hiding this comment.
the tests actually come from upstream and the port was updated so we rewrite the import to use get_kernels, this added some more lines to the port - but now we do not have any tests in the overlay file.
however if we were to add tests that were not originally upstream and rewritable - they would belong in the overlays folder - since that should contains all of the code that is not upstream. the "kernel source" which is now in the einops/src file should not contain any code that is not output from the port too. we keep this clear separation so the einops/src only contains generated code (we never mix non generated code with the tools output)
There was a problem hiding this comment.
I agree. Those tests (that we modify heavily) should probably be reserved for just CI-level testing. Those are fine to have in overlays.
|
#1100 -- used the tool on |
|
/kernel-bot build-and-stage einops |
|
Build request processed. Command: Dispatched (2):
|
|
@drbh can we build using the bot without the PR not having landed in |
|
|
||
| replace in="tests/test_einsum.py" count=1 \ | ||
| find=#""" | ||
| from einops.tests import collect_test_backends |
There was a problem hiding this comment.
This seems quite verbose? It would be nicer to have something less literal and more declarative that is "for every import of the kernel of the shape import kernel replace by kernel = get_kernel(...) and every import of the shape from kernel import foo replace by foo = kernel.foo. All these full snippets are going to be very fragile for active upstream projects.
|
/kernel-bot build-and-stage einops |
|
Build request processed. Command: Dispatched (2):
Hub uploads: |
sayakpaul
left a comment
There was a problem hiding this comment.
Thanks, left some comments. I like the idea of validating a port, really cool!
| # A ported kernel's <kernel>/src is generated from <kernel>/port/port.kdl and | ||
| # committed. Regenerate it here and fail if it drifted, so that a stale overlay | ||
| # silently reverting an in-tree fix, a hand-edited build.toml field the manifest | ||
| # op drops, or an overlay file edited without its generated twin are all loud. |
There was a problem hiding this comment.
What do we consider to be a drift here?
There was a problem hiding this comment.
drift here is just einops/src not matching what the recipe outputs. the cases this catches are an overlay file going stale and undoing a fix that was made directly in src, a manual edit to build.toml that the manifest op drops on the next run, and the recipe being edited without rerunning the port (port-provenance.json stores the recipe hash so that one shows up as a diff in the provenance file). updated the comment in the workflow to list these
| types: [opened, synchronize, reopened] | ||
| paths: | ||
| - "*/port/**" | ||
| - "*/src/**" |
There was a problem hiding this comment.
So for kernels containing valid porting recipes, we expect their sources to be present under src, which is as expected 👍
| env: | ||
| # kernel-port still lives on the kernel-port-tool branch; point this at | ||
| # github:huggingface/kernels#kernel-port once that branch merges. | ||
| KERNEL_PORT: "nix run github:huggingface/kernels/kernel-port-tool#kernel-port --" |
There was a problem hiding this comment.
Let's add a TODO here to update when the PR is eventually merged.
There was a problem hiding this comment.
Also, once this is shipped do we expect users to run with nix run or through the kernel-builder CLI?
There was a problem hiding this comment.
Let's add a TODO here to update when the PR is eventually merged.
done, also pinned the runner to a commit on the kernel-port-tool branch instead of the branch head so changes there dont affect open prs
Also, once this is shipped do we expect users to run with nix run or through the kernel-builder CLI?
nix run for now since the tool only exists on the branch. once it merges I think we can expose it as a kernel-builder subcommand and update KERNEL_PORT in the workflow, the script just reads that env var so either works
| @@ -0,0 +1,12 @@ | |||
| { | |||
| "format": 1, | |||
There was a problem hiding this comment.
Self TODO: review the provenance generation logic.
| @@ -0,0 +1,80 @@ | |||
| recipe version=1 | |||
There was a problem hiding this comment.
Okay so IIUC we didn't need any overlay in this case? I thought the flake.nix would go to the overlay directory? How are we handling that?
There was a problem hiding this comment.
yea no overlay is needed for einops since everything comes from upstream. flake.nix is not generated so it stays at einops/flake.nix with path = ./src and only the tool output lives under src/. build.yaml already picks up <kernel>/src/build.toml when it exists
There was a problem hiding this comment.
flake.nix is not generated so it stays at einops/flake.nix
Oh okay. Earlier, I think we wanted to keep the external files in the overlay. What is the general guidelines behind putting stuff under an overlay folder then?
this pr fixes the macos ci failures where `get-kernel-check` rejects a kernel that built fine. first hit on the einops port in huggingface/kernels-community#1092 tldr; the check handed `$out` to the resolver and let it pick a variant by detecting the backend at runtime. metal is the only backend detected from live hardware (`torch.backends.mps.is_available()`, everything else is baked into the torch build). the sandboxed macos build cannot see the gpu, so the `torch-metal` variant is never selected and the check fails even though the artifact is fine repro (no kernel build needed) ```bash mkdir -p /tmp/fake-kernel/torch-metal && touch /tmp/fake-kernel/torch-metal/metadata.json kernels/.venv/bin/python -c "from pathlib import Path; import kernels; kernels.get_local_kernel(Path('/tmp/fake-kernel'))" ``` ``` ValueError: Cannot parse metadata from `"/tmp/fake-kernel/torch-metal/metadata.json"`: EOF while parsing a value at line 1 column 0 ``` on a mac with a visible gpu the variant is selected fine (it gets as far as reading the empty `metadata.json`). same command inside a seatbelt sandbox ```bash sandbox-exec -p '(version 1)(allow default)(deny iokit-open)' \ kernels/.venv/bin/python -c "from pathlib import Path; import kernels; kernels.get_local_kernel(Path('/tmp/fake-kernel'))" ``` ``` FileNotFoundError: Cannot find a build variant for this system in /tmp/fake-kernel: ``` `sandbox-exec` is the same seatbelt mechanism the nix darwin sandbox uses. denying iokit hides the gpu, `mps.is_available()` returns false, and the same directory no longer resolves note* this is also why only some metal builds fail in ci. arch metal builds set `__noChroot = metalSupport` since they need the host metal toolchain, so the gpu is still visible during the check. noarch metal builds like einops run fully sandboxed and always fail. the first command also fails on linux since there is no mps at all the check now globs `$out` for `*/metadata.json` and points the resolver at that exact variant dir instead of auto detecting from the build host. each extension derivation produces exactly one variant, so zero or multiple variants still fail the check
Signed-off-by: David Holtz <david.richard.holtz@gmail.com>
Signed-off-by: David Holtz <david.richard.holtz@gmail.com>
Signed-off-by: David Holtz <david.richard.holtz@gmail.com>
Signed-off-by: David Holtz <david.richard.holtz@gmail.com>
Signed-off-by: David Holtz <david.richard.holtz@gmail.com>
Signed-off-by: David Holtz <david.richard.holtz@gmail.com>
Signed-off-by: David Holtz <david.richard.holtz@gmail.com>
*updated to match latest changeset
this pr is an example of using the kernel porting tool to port the upstream einops into the kernel builder format
first we clone the upstream source*
next we
running the command will show how each line of the recipe impacted the transformation and outputs all of the files added and deleted in the process.
check-ports.yamlreruns the port in ci and fails ifeinops/srcdoes not match the output, so the generated tree is still reviewable but cannot drift from the recipe. prs only check the ports they touchnote:
flake.nixis not generated so it stays ateinops/flake.nixand points nix at./src,build.yamlalready handles this layout (#1109)