Skip to content

Commit

Permalink
Added Java Bindings for Adapters API (#1030)
Browse files Browse the repository at this point in the history
* Added Java Bindings for Adapters API and test cases.
* Enable Java CI tests on win-x64, win-arm64, linux-x64 and osx-arm64.
* Fix existing Java test cases.
* Fix some style issues reported by spotless.

Internal work item: https://task.ms/aii/52363
  • Loading branch information
skyline75489 authored Dec 3, 2024
1 parent c5745fd commit 44a8f22
Show file tree
Hide file tree
Showing 34 changed files with 675 additions and 222 deletions.
17 changes: 17 additions & 0 deletions .github/workflows/linux-cpu-x64-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@ jobs:
with:
dotnet-version: '8.0.x'

- name: Setup Java 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: 'gradle'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
with:
gradle-version: '8.6'

- name: Get the Latest OnnxRuntime Nightly Version
shell: pwsh
run: |
Expand Down Expand Up @@ -96,6 +108,11 @@ jobs:
cd test/csharp
dotnet test /p:Configuration=Release /p:NativeBuildOutputDir="../../build/cpu/" /p:OrtLibDir="../../ort/lib/" --verbosity normal
- name: Build the Java API and Run the Java Tests
run: |
set -e -x
python3 build.py --config=Release --build_dir build/cpu --build_java --parallel --cmake_generator "Ninja"
- name: Run tests
run: |
set -e -x
Expand Down
19 changes: 19 additions & 0 deletions .github/workflows/mac-cpu-arm64-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ jobs:
with:
python-version: '3.12.x'

- name: Setup Java 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: 'gradle'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
with:
gradle-version: '8.6'

- name: Get the Latest OnnxRuntime Nightly Version
run: |
ORT_NIGHTLY_VERSION=$(curl -s "${{ env.ORT_NIGHTLY_REST_API }}" | jq -r '.value[0].versions[0].normalizedVersion')
Expand Down Expand Up @@ -76,6 +88,7 @@ jobs:
source genai-macos-venv/bin/activate
export HF_TOKEN="12345"
export ORTGENAI_LOG_ORT_LIB=1
python3 -m pip install requests
python3 test/python/test_onnxruntime_genai.py --cwd test/python --test_models test/test_models
- name: Build the C# API and Run the C# Tests
Expand All @@ -84,6 +97,12 @@ jobs:
cd test/csharp
dotnet test /p:Configuration=Release /p:NativeBuildOutputDir="../../build/cpu/osx-arm64" --verbosity normal
- name: Build the Java API and Run the Java Tests
run: |
set -e -x
source genai-macos-venv/bin/activate
python3 build.py --config=Release --build_dir build/cpu/osx-arm64 --build_java --parallel --cmake_generator "Unix Makefiles"
- name: Run tests
run: |
set -e -x
Expand Down
29 changes: 23 additions & 6 deletions .github/workflows/win-cpu-arm64-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ jobs:
with:
nuget-version: '5.x'

- name: Setup Java 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
cache: 'gradle'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
with:
gradle-version: '8.6'

- name: Download OnnxRuntime Nightly
shell: powershell
run: |
Expand All @@ -54,18 +66,14 @@ jobs:
- name: Configure CMake
run: |
python -m pip install wheel
python -m pip install wheel requests
cmake --preset windows_arm64_cpu_release
- name: Build with CMake
run: |
cmake --build --preset windows_arm64_cpu_release --parallel
- name: Build the C# API and Run the C# Tests
run: |
cd test\csharp
dotnet test /p:NativeBuildOutputDir="$env:GITHUB_WORKSPACE\$env:binaryDir\Release" /p:OrtLibDir="$env:GITHUB_WORKSPACE\ort\lib"
- name: Install the Python Wheel and Test Dependencies
run: |
python -m pip install "numpy<2" coloredlogs flatbuffers packaging protobuf sympy pytest
Expand All @@ -76,6 +84,15 @@ jobs:
run: |
python test/python/test_onnxruntime_genai.py --cwd "test\python" --test_models "test\test_models"
- name: Build the C# API and Run the C# Tests
run: |
cd test\csharp
dotnet test /p:NativeBuildOutputDir="$env:GITHUB_WORKSPACE\$env:binaryDir\Release" /p:OrtLibDir="$env:GITHUB_WORKSPACE\ort\lib"
- name: Build the Java API and Run the Java Tests
run: |
python build.py --config=Release --build_dir $env:binaryDir --build_java --parallel
- name: Verify Build Artifacts
if: always()
continue-on-error: true
Expand Down
16 changes: 16 additions & 0 deletions .github/workflows/win-cpu-x64-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,18 @@ jobs:
with:
dotnet-version: '8.0.x'

- name: Setup Java 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: 'gradle'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
with:
gradle-version: '8.6'

- name: Download OnnxRuntime Nightly
shell: pwsh
run: |
Expand Down Expand Up @@ -92,6 +104,10 @@ jobs:
cd test\csharp
dotnet test /p:NativeBuildOutputDir="$env:GITHUB_WORKSPACE\$env:binaryDir\Release" /p:OrtLibDir="$env:GITHUB_WORKSPACE\ort\lib" --verbosity normal
- name: Build the Java API and Run the Java Tests
run: |
python3 build.py --config=Release --build_dir $env:binaryDir --build_java --parallel
- name: Verify Build Artifacts
if: always()
continue-on-error: true
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@ examples/csharp/HelloPhi/models
/src/java/.gradle
/src/java/local.properties
/src/java/build
/src/java/CMakeFiles
/src/java/CMakeCache.txt
14 changes: 10 additions & 4 deletions build.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,11 +229,13 @@ def _validate_build_dir(args: argparse.Namespace):
# also tweak build directory name for mac builds
target_sys = "macOS"

args.build_dir = Path("build") / target_sys
# set to a config specific build dir if no build_dir specified from command arguments
args.build_dir = Path("build") / target_sys / args.config

# set to a config specific build dir. it should exist unless we're creating the cmake setup
is_strict = not args.update
args.build_dir = args.build_dir.resolve(strict=is_strict) / args.config
# Use user-specified build_dir and ignore args.config
# This is to better accommodate the existing cmake presets which can uses arbitrary paths.
args.build_dir = args.build_dir.resolve(strict=is_strict)


def _validate_cuda_args(args: argparse.Namespace):
Expand Down Expand Up @@ -453,7 +455,7 @@ def update(args: argparse.Namespace, env: dict[str, str]):

is_x64_host = platform.machine() == "AMD64"
if is_x64_host:
toolset_options += ["host=x64"]
pass

if args.use_cuda:
toolset_options += ["cuda=" + str(args.cuda_home)]
Expand Down Expand Up @@ -624,6 +626,10 @@ def test(args: argparse.Namespace, env: dict[str, str]):
csharp_test_command += _get_csharp_properties(args, ort_lib_dir=lib_dir)
util.run(csharp_test_command, env=env, cwd=str(REPO_ROOT / "test" / "csharp"))

if args.build_java:
ctest_cmd = [str(args.ctest_path), "--build-config", args.config, "--verbose", "--timeout", "10800"]
util.run(ctest_cmd, cwd=str(args.build_dir / "src" / "java"))

if args.android:
_run_android_tests(args)

Expand Down
73 changes: 46 additions & 27 deletions src/java/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ endif()

set(JAVA_SRC_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
# <build output dir>/src/java (path used with add_subdirectory in root CMakeLists.txt)
set(JAVA_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR})
set(JAVA_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR})

# Should we use onnxruntime-genai or onnxruntime-genai-static? Using onnxruntime-genai for now.
# Should we use onnxruntime-genai or onnxruntime-genai-static? Using onnxruntime-genai for now.
# Add dependency on native target
set(JAVA_DEPENDS onnxruntime-genai)

Expand All @@ -34,20 +34,20 @@ elseif (ANDROID)
endif()

# this jar is solely used to signaling mechanism for dependency management in CMake
# if any of the Java sources change, the jar (and generated headers) will be regenerated
# if any of the Java sources change, the jar (and generated headers) will be regenerated
# and the onnxruntime-genai-jni target will be rebuilt
set(JAVA_OUTPUT_JAR ${JAVA_OUTPUT_DIR}/build/libs/onnxruntime-genai.jar)
set(GRADLE_ARGS clean jar -x test)

# this jar is solely used to signaling mechanism for dependency management in CMake
# if any of the Java sources change, the jar (and generated headers) will be regenerated
# if any of the Java sources change, the jar (and generated headers) will be regenerated
# and the onnxruntime-genai-jni target will be rebuilt
set(JAVA_OUTPUT_JAR ${JAVA_SRC_ROOT}/build/libs/onnxruntime-genai.jar)
set(GRADLE_ARGS clean jar -x test)

add_custom_command(OUTPUT ${JAVA_OUTPUT_JAR}
COMMAND ${GRADLE_EXECUTABLE} ${GRADLE_OPTIONS} ${GRADLE_ARGS}
WORKING_DIRECTORY ${JAVA_SRC_ROOT}
add_custom_command(OUTPUT ${JAVA_OUTPUT_JAR}
COMMAND ${GRADLE_EXECUTABLE} ${GRADLE_OPTIONS} ${GRADLE_ARGS}
WORKING_DIRECTORY ${JAVA_SRC_ROOT}
DEPENDS ${genai4j_gradle_files} ${genai4j_srcs})
add_custom_target(onnxruntime-genai4j DEPENDS ${JAVA_OUTPUT_JAR})

Expand All @@ -60,13 +60,13 @@ file(GLOB genai4j_native_src
"${JAVA_SRC_ROOT}/src/main/native/*.h"
"${SRC_ROOT}/ort_genai_c.h"
)

add_library(onnxruntime-genai-jni SHARED ${genai4j_native_src})
set_property(TARGET onnxruntime-genai-jni PROPERTY CXX_STANDARD 17)
add_dependencies(onnxruntime-genai-jni onnxruntime-genai4j)
# the JNI headers are generated in the genai4j target
target_include_directories(onnxruntime-genai-jni PRIVATE ${SRC_ROOT}
${JAVA_SRC_ROOT}/build/headers
${JAVA_SRC_ROOT}/build/headers
${JNI_INCLUDE_DIRS})
target_link_libraries(onnxruntime-genai-jni PUBLIC onnxruntime-genai)

Expand Down Expand Up @@ -104,13 +104,13 @@ file(MAKE_DIRECTORY ${JAVA_PACKAGE_LIB_DIR})

# Add the native genai library to the native-lib dir
add_custom_command(TARGET onnxruntime-genai-jni POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:onnxruntime-genai>
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:onnxruntime-genai>
${JAVA_PACKAGE_LIB_DIR}/$<TARGET_FILE_NAME:onnxruntime-genai>)

# Add the JNI bindings to the native-jni dir
add_custom_command(TARGET onnxruntime-genai-jni POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:onnxruntime-genai-jni>
${JAVA_PACKAGE_LIB_DIR}/$<TARGET_FILE_NAME:onnxruntime-genai-jni>)

Expand Down Expand Up @@ -140,21 +140,21 @@ if (ANDROID)
file(MAKE_DIRECTORY ${ANDROID_PACKAGE_HEADERS_DIR})
file(MAKE_DIRECTORY ${ANDROID_PACKAGE_ABI_DIR})

# copy C/C++ API headers to be packed into Android AAR package
add_custom_command(TARGET onnxruntime-genai-jni POST_BUILD
# copy C/C++ API headers to be packed into Android AAR package
add_custom_command(TARGET onnxruntime-genai-jni POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${SRC_ROOT}/ort_genai.h ${ANDROID_PACKAGE_HEADERS_DIR})
add_custom_command(TARGET onnxruntime-genai-jni POST_BUILD
add_custom_command(TARGET onnxruntime-genai-jni POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${SRC_ROOT}/ort_genai_c.h ${ANDROID_PACKAGE_HEADERS_DIR})

# Copy onnxruntime-genai.so and onnxruntime-genai-jni.so for building Android AAR package
add_custom_command(TARGET onnxruntime-genai-jni POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:onnxruntime-genai>
${ANDROID_PACKAGE_ABI_DIR}/$<TARGET_LINKER_FILE_NAME:onnxruntime-genai>)

add_custom_command(TARGET onnxruntime-genai-jni POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:onnxruntime-genai-jni>
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:onnxruntime-genai-jni>
${ANDROID_PACKAGE_ABI_DIR}/$<TARGET_LINKER_FILE_NAME:onnxruntime-genai-jni>)

# Generate the Android AAR package
Expand All @@ -176,20 +176,20 @@ if (ANDROID)
file(GLOB android_test_files "${ANDROID_TEST_SRC_ROOT}/*")
file(COPY ${android_test_files} DESTINATION ${ANDROID_TEST_PACKAGE_DIR})

set(ANDROID_TEST_PACKAGE_LIB_DIR ${ANDROID_TEST_PACKAGE_DIR}/app/libs)
set(ANDROID_TEST_PACKAGE_LIB_DIR ${ANDROID_TEST_PACKAGE_DIR}/app/libs)
set(ANDROID_TEST_PACKAGE_APP_ASSETS_DIR ${ANDROID_TEST_PACKAGE_DIR}/app/src/main/assets)
file(MAKE_DIRECTORY ${ANDROID_TEST_PACKAGE_LIB_DIR})
file(MAKE_DIRECTORY ${ANDROID_TEST_PACKAGE_APP_ASSETS_DIR})

# Copy the test model to the assets folder in the test app
add_custom_command(TARGET onnxruntime-genai-jni POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different
${REPO_ROOT}/test/test_models/hf-internal-testing/tiny-random-gpt2-fp32
${ANDROID_TEST_PACKAGE_APP_ASSETS_DIR}/model)

# Copy the Android AAR package we built to the libs folder of our test app
add_custom_command(TARGET onnxruntime-genai-jni POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${ANDROID_PACKAGE_OUTPUT_DIR}/outputs/aar/onnxruntime-genai-debug.aar
${ANDROID_TEST_PACKAGE_LIB_DIR}/onnxruntime-genai.aar)

Expand All @@ -207,19 +207,38 @@ if (ENABLE_TESTS)
# On windows ctest requires a test to be an .exe(.com) file
# With gradle wrapper we get gradlew.bat. We delegate execution to a separate .cmake file
# That can handle both .exe and .bat
add_test(NAME onnxruntime-genai4j_test
COMMAND ${CMAKE_COMMAND}
-DGRADLE_EXECUTABLE=${GRADLE_EXECUTABLE}
-DBIN_DIR=${JAVA_OUTPUT_DIR}
add_test(NAME onnxruntime-genai4j_test
COMMAND ${CMAKE_COMMAND}
-DGRADLE_EXECUTABLE=${GRADLE_EXECUTABLE}
-DBIN_DIR=${JAVA_OUTPUT_DIR}
-DJAVA_SRC_ROOT=${JAVA_SRC_ROOT}
-DJAVA_PACKAGE_LIB_DIR=${JAVA_PACKAGE_LIB_DIR}
-P ${JAVA_SRC_ROOT}/windows-unittests.cmake)
else()
add_test(NAME onnxruntime-genai4j_test
COMMAND ${GRADLE_EXECUTABLE} cmakeCheck
add_test(NAME onnxruntime-genai4j_test
COMMAND ${GRADLE_EXECUTABLE} cmakeCheck
-DcmakeBuildDir=${JAVA_OUTPUT_DIR} -DnativeLibDir=${JAVA_PACKAGE_LIB_DIR}
WORKING_DIRECTORY ${JAVA_SRC_ROOT})
endif()

if(WIN32)
set(ONNXRUNTIME_GENAI_DEPENDENCY "*.dll")
elseif(APPLE)
set(ONNXRUNTIME_GENAI_DEPENDENCY "*.dylib")
else()
set(ONNXRUNTIME_GENAI_DEPENDENCY "*.so")
endif()

file(GLOB ort_native_libs "${ORT_LIB_DIR}/${ONNXRUNTIME_GENAI_DEPENDENCY}")

# Copy ORT native libs for Java tests
foreach(LIB_FILE ${ort_native_libs})
add_custom_command(
TARGET onnxruntime-genai-jni POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${LIB_FILE}
${JAVA_PACKAGE_LIB_DIR}/)
endforeach()

set_property(TEST onnxruntime-genai4j_test APPEND PROPERTY DEPENDS onnxruntime-genai-jni)
endif()
1 change: 1 addition & 0 deletions src/java/build-android.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ artifacts {

dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testImplementation 'org.junit.platform:junit-platform-launcher:1.10.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
}

Expand Down
1 change: 1 addition & 0 deletions src/java/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ if (cmakeNativeLibDir != null) {

dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.2'
testImplementation 'org.junit.platform:junit-platform-launcher:1.10.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.2'
}

Expand Down
Loading

0 comments on commit 44a8f22

Please sign in to comment.