Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

whisper.android: How to build with CLBlast #1809

Merged
merged 7 commits into from Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 15 additions & 1 deletion .github/workflows/build.yml
Expand Up @@ -416,6 +416,14 @@ jobs:
steps:
- name: Clone
uses: actions/checkout@v3
with:
path: whisper

- name: Clone
uses: actions/checkout@v3
with:
repository: ggerganov/ggml
path: ggml

- name: Install Java
uses: actions/setup-java@v3
Expand All @@ -428,9 +436,15 @@ jobs:

- name: Build
run: |
cd examples/whisper.android
cd whisper/examples/whisper.android
./gradlew assembleRelease --no-daemon

- name: Build with external ggml
run: |
export PATH_TO_GGML=$PWD/ggml
cd whisper/examples/whisper.android
./gradlew assembleRelease --no-daemon -PGGML_HOME=$PATH_TO_GGML

android_java:
runs-on: ubuntu-latest

Expand Down
44 changes: 44 additions & 0 deletions examples/whisper.android/README.md
Expand Up @@ -12,3 +12,47 @@ To use:
(PS: Do not move this android project folder individually to other folders, because this android project folder depends on the files of the whole project.)

<img width="300" alt="image" src="https://user-images.githubusercontent.com/1670775/221613663-a17bf770-27ef-45ab-9a46-a5f99ba65d2a.jpg">

## CLBlast

> [!NOTE]
> - OpenCL does not have the same level of support as CUDA or Metal.
> - Turning on CLBlast may degrade OpenCL performance if your device isn't already tuned. See [tuning.md](https://github.com/CNugteren/CLBlast/blob/162783a414969464ce3aa5adf5c2554afa5ee93e/doc/tuning.md#already-tuned-for-devices) for a list of devices that are already tuned and what to do if yours is missing.

Build CLBlast.

```
# In path/to/CLBlast (we assume OpenCL-Headers relative location)
$ANDROID_SDK_PATH/cmake/3.22.1/bin/cmake .. \
-DCMAKE_SYSTEM_NAME=Android \
-DCMAKE_SYSTEM_VERSION=33 \
-DCMAKE_ANDROID_ARCH_ABI=arm64-v8a \
-DCMAKE_ANDROID_NDK=$ANDROID_NDK_PATH \
-DCMAKE_ANDROID_STL_TYPE=c++_static \
-DOPENCL_ROOT=$(readlink -f ../../OpenCL-Headers) \
-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH \
-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=BOTH

# Build libclblast.so
make -j4
```

Pull `libGLES_mali.so` to `libOpenCL.so`.

```bash
# In path/to/whisper.android
mkdir lib/src/main/jniLibs/arm64-v8a
adb pull /system/vendor/lib64/egl/libGLES_mali.so lib/src/main/jniLibs/arm64-v8a/libOpenCL.so
```

In gradle.properties, set `GGML_HOME` to the location of GGML, as well as
required options for turning on CLBlast.

```
GGML_HOME=/path/to/ggml
GGML_CLBLAST=ON
CLBLAST_HOME=/path/to/CLBlast
OPENCL_LIB=/path/to/libOpenCL.so
OPENCL_ROOT=/path/to/OpenCL-Headers
```

22 changes: 22 additions & 0 deletions examples/whisper.android/lib/build.gradle
Expand Up @@ -16,6 +16,28 @@ android {
ndk {
abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64'
}
externalNativeBuild {
cmake {
// When set, builds whisper.android against the version located
// at GGML_HOME instead of the copy bundled with whisper.cpp.
if (
project.hasProperty('GGML_HOME') &&
project.findProperty('GGML_CLBLAST') == 'ON'
) {
// Turning on CLBlast requires GGML_HOME
arguments "-DGGML_HOME=${project.property('GGML_HOME')}",
"-DGGML_CLBLAST=ON",
"-DOPENCL_LIB=${project.property('OPENCL_LIB')}",
"-DCLBLAST_HOME=${project.property('CLBLAST_HOME')}",
"-DOPENCL_ROOT=${project.property('OPENCL_ROOT')}",
"-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=BOTH",
"-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH"
} else if (project.hasProperty('GGML_HOME')) {
arguments "-DGGML_HOME=${project.property('GGML_HOME')}"
}

}
}
}

buildTypes {
Expand Down
40 changes: 32 additions & 8 deletions examples/whisper.android/lib/src/main/jni/whisper/CMakeLists.txt
Expand Up @@ -3,17 +3,28 @@ cmake_minimum_required(VERSION 3.10)
project(whisper.cpp)

set(CMAKE_CXX_STANDARD 11)
set(WHISPER_LIB_DIR ${CMAKE_SOURCE_DIR}/../../../../../../../)
set(WHISPER_LIB_DIR ${CMAKE_SOURCE_DIR}/../../../../../../..)

# Path to external GGML, otherwise uses the copy in whisper.cpp.
option(GGML_HOME "whisper: Path to external GGML source" OFF)

set(
SOURCE_FILES
${WHISPER_LIB_DIR}/whisper.cpp
${CMAKE_SOURCE_DIR}/jni.c
)

if (NOT GGML_HOME)
set(
SOURCE_FILES
${SOURCE_FILES}
${WHISPER_LIB_DIR}/ggml.c
${WHISPER_LIB_DIR}/ggml-alloc.c
${WHISPER_LIB_DIR}/ggml-backend.c
${WHISPER_LIB_DIR}/ggml-quants.c
${WHISPER_LIB_DIR}/whisper.cpp
${CMAKE_SOURCE_DIR}/jni.c
)

)
endif()

find_library(LOG_LIB log)

Expand All @@ -24,12 +35,12 @@ function(build_library target_name)
${SOURCE_FILES}
)

target_link_libraries(${target_name} ${LOG_LIB} android)

if (${target_name} STREQUAL "whisper_v8fp16_va")
target_compile_options(${target_name} PRIVATE -march=armv8.2-a+fp16)
set(GGML_COMPILE_OPTIONS -march=armv8.2-a+fp16)
elseif (${target_name} STREQUAL "whisper_vfpv4")
target_compile_options(${target_name} PRIVATE -mfpu=neon-vfpv4)
set(GGML_COMPILE_OPTIONS -mfpu=neon-vfpv4)
endif ()

if (NOT ${CMAKE_BUILD_TYPE} STREQUAL "Debug")
Expand All @@ -43,14 +54,27 @@ function(build_library target_name)
target_link_options(${target_name} PRIVATE -flto)

endif ()
endfunction()

build_library("whisper") # Default target
if (GGML_HOME)
include(FetchContent)
FetchContent_Declare(ggml SOURCE_DIR ${GGML_HOME})
FetchContent_MakeAvailable(ggml)

target_compile_options(ggml PRIVATE ${GGML_COMPILE_OPTIONS})
target_link_libraries(${target_name} ${LOG_LIB} android ggml)
else()
target_link_libraries(${target_name} ${LOG_LIB} android)
endif()


endfunction()

if (${ANDROID_ABI} STREQUAL "arm64-v8a")
build_library("whisper_v8fp16_va")
elseif (${ANDROID_ABI} STREQUAL "armeabi-v7a")
build_library("whisper_vfpv4")
endif ()

build_library("whisper") # Default target

include_directories(${WHISPER_LIB_DIR})