Skip to content

Enable ARM (aarch64) support for cuvs-java and cuvs-lucene - #2541

Draft
imotov wants to merge 6 commits into
NVIDIA:mainfrom
imotov:issue-1236-enable-arm-for-cuvs-java
Draft

Enable ARM (aarch64) support for cuvs-java and cuvs-lucene#2541
imotov wants to merge 6 commits into
NVIDIA:mainfrom
imotov:issue-1236-enable-arm-for-cuvs-java

Conversation

@imotov

@imotov imotov commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

The C++ core already builds and is tested on both amd64 and arm64; cuvs-java had a hardcoded amd64-only gate that cuvs-lucene inherited.

Java bytecode is portable, but cuvs-java isn't pure Java — it uses the Panama FFM API to call into native libcuvs_c.so, and those bindings are generated by jextract, which bakes struct/function ABI layouts (computed by parsing the C headers with clang for the host's target triple) into the generated .class files at build time. Reusing an amd64-generated binding on aarch64 should work, since no arch-conditional logic in the jextract-visible header surface changes any type layout, struct offset, or function signature between x86_64 and aarch64 Linux.

We therefore expect the plain (no-native-bundled) jar to be arch-portable in practice. To verify that, the aarch64 cuvs-lucene CI job installs the amd64-built jar and runs cuvs-lucene's full test suite against it on aarch64 hardware with an aarch64-native libcuvs_c.so.

Closes #1236.

The C++ core already builds and is tested on both amd64 and arm64;
cuvs-java had a hardcoded amd64-only gate that cuvs-lucene inherited.

Java bytecode is portable, but cuvs-java isn't pure Java — it uses the
Panama FFM API to call into native libcuvs_c.so, and those bindings
are generated by jextract, which bakes struct/function ABI layouts
(computed by parsing the C headers with clang for the host's target
triple) into the generated .class files at build time. Reusing an
amd64-generated binding on aarch64 should work, since no
arch-conditional logic in the jextract-visible header surface changes
any type layout, struct offset, or function signature between x86_64
and aarch64 Linux.

We therefore expect the plain (no-native-bundled) jar to be
arch-portable in practice. To verify that, the aarch64 cuvs-lucene CI
job installs the amd64-built jar and runs cuvs-lucene's full test
suite against it on aarch64 hardware with an aarch64-native
libcuvs_c.so.

Closes NVIDIA#1236.
@copy-pr-bot

copy-pr-bot Bot commented Sep 1, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@imotov

imotov commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 762531b

@imotov imotov self-assigned this Sep 1, 2026
@imotov imotov added improvement Improves an existing functionality non-breaking Introduces a non-breaking change labels Sep 1, 2026
@imotov
imotov marked this pull request as ready for review September 2, 2026 16:04
@imotov
imotov requested review from a team as code owners September 2, 2026 16:04
@imotov
imotov requested a review from jameslamb September 2, 2026 16:04

@jameslamb jameslamb left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementation looks good to me but I'm a bit confused about the goal, left some questions. Sorry in advance if they are naive / ignorant 😅

Comment thread .github/workflows/build.yaml Outdated
script: "ci/build_java.sh"
artifact-name: "cuvs-java-cuda${{ matrix.CUDA_VER }}"
# amd64 is the official published artifact; keep its name unqualified and only suffix other arches so they don't collide with it.
artifact-name: "cuvs-java-cuda${{ matrix.CUDA_VER }}${{ matrix.ARCH != 'amd64' && format('-{0}', matrix.ARCH) || '' }}"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean here by "official published artifact" and what specifically would break if we appended the architecture unconditionally to it?

I think this is just the name of a GitHub Actions artifact used for passing files around between CI runs, not an identifier that makes it to Maven Central or anything.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, maybe here's my confusion. Seeing this in the PR description:

We therefore expect the plain (no-native-bundled) jar to be arch-portable in practice

Is that "plain jar" what's built by build_java.sh? And if so, shouldn't this job continue to just be run on amd64?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jameslamb Yep, that's a tricky one. So if you have any ideas on how to do it better, I could definitely use them. The problem is that part of cuvs-java is generated by Panama from C headers. Theoretically, that part is platform-dependent. In practice, though, in our case it's the same for both architectures. So on one hand, publishing two basically identical jars for different architectures seems silly; on the other hand, we should make sure that 1) it builds on arm, 2) it works on arm, and 3) we can use the amd64-built jar on arm - i.e. that our practical assumption that the jars are functionally the same actually holds.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me rephrase... if "we can use the amd64-build jar on arm" is true, why does "it builds on arm" matter?

Do we have users who are building these jars from source in arm64 environments?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think any users build it from source on arm64 today, since there is a check preventing cuvs-java from running on arm64, which this PR removes. So until this commit is merged, nobody can use it on arm64 anyway. However, I think after this PR is merged it will useful to build on arm64 to catch breaking changes on that platform. Maybe the right answer is to build and test fully on arm64, and then separately test that arm64 works with the amd64 build?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed building cuvs-java and cuvs-lucene on arm64 and instead added a couple of scripts to just run the tests with jars downloaded from amd64 build.

@imotov
imotov marked this pull request as draft September 3, 2026 02:46
@imotov

imotov commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 292ed0f

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

improvement Improves an existing functionality non-breaking Introduces a non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cuvs-java: support linux ARM

2 participants