From aea8581bb8e5c1c9bfb37e90d96f6b744a1e765f Mon Sep 17 00:00:00 2001 From: Roy Shilkrot Date: Tue, 16 Apr 2024 19:00:08 -0400 Subject: [PATCH 1/4] Add support for CLBlast library and clbast::clblast target --- .github/workflows/build.yml | 6 +-- .gitignore | 2 + CMakeLists.txt | 78 +++++++++++++++++++++++++++++++++---- build-windows.ps1 | 7 +++- cmake/FindCLBlast.cmake | 43 ++++++++++++++++++++ 5 files changed, 123 insertions(+), 13 deletions(-) create mode 100644 .gitignore create mode 100644 cmake/FindCLBlast.cmake diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 10e1b08..e29c3e3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -93,7 +93,7 @@ jobs: matrix: config: - "Release" - cublas: [cpu, 12.2.0, 11.8.0] + cublas: [cpu, 12.2.0, 11.8.0, clblast] steps: - name: "Get version" @@ -110,14 +110,14 @@ jobs: uses: "actions/checkout@v4" - name: Install CUDA Toolkit - if: ${{ matrix.cublas != 'cpu' }} + if: ${{ matrix.cublas != 'cpu' }} && ${{ matrix.cublas != 'clblast' }} id: cuda-toolkit uses: Jimver/cuda-toolkit@v0.2.11 with: cuda: '${{ matrix.cublas }}' - name: Set CUDA_TOOLKIT_ROOT_DIR if CUDA is installed - if: ${{ matrix.cublas != 'cpu' }} + if: ${{ matrix.cublas != 'cpu' }} && ${{ matrix.cublas != 'clblast' }} run: | "CUDA_TOOLKIT_ROOT_DIR=$env:CUDA_PATH" >> $env:GITHUB_ENV diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1576f97 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/ +release/ diff --git a/CMakeLists.txt b/CMakeLists.txt index ffda9a0..ff627b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,12 +3,14 @@ cmake_minimum_required(VERSION 3.21) project(Whispercpp_prebuilt) include(ExternalProject) +include(FetchContent) option(WHISPERCPP_WITH_CUDA "Build Whisper with CUDA support" OFF) +option(WHISPERCPP_WITH_CLBLAST "Build Whisper with CLBlast support" OFF) set(CMAKE_OSX_ARCHITECTURES_ "$ENV{MACOS_ARCH}") -set(Whispercpp_Build_GIT_TAG "f22d27a385d34b1e544031efe8aa2e3d73922791") +set(Whispercpp_Build_GIT_TAG "v1.5.5") if(${CMAKE_BUILD_TYPE} STREQUAL Release OR ${CMAKE_BUILD_TYPE} STREQUAL RelWithDebInfo) set(Whispercpp_BUILD_TYPE Release) @@ -49,6 +51,46 @@ if(WIN32) set(WHISPER_ADDITIONAL_ENV "CUDAToolkit_ROOT=${CUDA_TOOLKIT_ROOT_DIR}") set(WHISPER_ADDITIONAL_CMAKE_ARGS -DWHISPER_BLAS=OFF -DWHISPER_CUBLAS=ON -DWHISPER_OPENBLAS=OFF -DCMAKE_GENERATOR_TOOLSET=cuda=${CUDA_TOOLKIT_ROOT_DIR}) + elseif(WHISPERCPP_WITH_CLBLAST) + # Build with CLBlast + set(CLBLAST_URL "https://github.com/CNugteren/CLBlast/releases/download/1.6.2/CLBlast-1.6.2-windows-x64.zip") + set(CLBLAST_SHA256 "09776AFACF89A960C59A0F072FE8595D8F49593B343E25C901F357DAC680018F") + FetchContent_Declare( + CLBlast + DOWNLOAD_EXTRACT_TIMESTAMP true + URL ${CLBLAST_URL} + URL_HASH SHA256=${CLBLAST_SHA256}) + FetchContent_MakeAvailable(CLBlast) + find_program(SEVEN_ZIP_EXECUTABLE 7z) + if(NOT SEVEN_ZIP_EXECUTABLE) + message(FATAL_ERROR "7z executable not found!") + endif() + execute_process( + COMMAND ${SEVEN_ZIP_EXECUTABLE} x -y ${clblast_SOURCE_DIR}/CLBlast-1.6.2-windows-x64.7z + WORKING_DIRECTORY ${clblast_SOURCE_DIR} + RESULT_VARIABLE SEVEN_ZIP_RESULT + OUTPUT_QUIET + ) + if(NOT SEVEN_ZIP_RESULT EQUAL 0) + message(FATAL_ERROR "Failed to extract CLBlast: ${SEVEN_ZIP_ERROR}") + endif() + set(clblast_SOURCE_DIR ${clblast_SOURCE_DIR}/CLBlast-1.6.2-windows-x64) + + message(STATUS "clblast_SOURCE_DIR: ${clblast_SOURCE_DIR}") + set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) + find_package(CLBlast REQUIRED) + + set(OPENCL_SDK_URL "https://github.com/KhronosGroup/OpenCL-SDK/releases/download/v2023.12.14/OpenCL-SDK-v2023.12.14-Win-x64.zip") + set(OPENCL_SDK_SHA256 "4C49F37A97B1B6D191B076C1E5D095B180E44BDC72DB32EC8B9748FF6ECFAEB6") + FetchContent_Declare( + OpenCL_SDK + DOWNLOAD_EXTRACT_TIMESTAMP true + URL ${OPENCL_SDK_URL} + URL_HASH SHA256=${OPENCL_SDK_SHA256}) + FetchContent_MakeAvailable(OpenCL_SDK) + + set(WHISPER_ADDITIONAL_CMAKE_ARGS -DWHISPER_BLAS=OFF -DWHISPER_CUBLAS=OFF -DWHISPER_OPENBLAS=OFF + -DWHISPER_CLBLAST=ON -Dclblast_SOURCE_DIR=${clblast_SOURCE_DIR} -Dopencl_sdk_SOURCE_DIR=${opencl_sdk_SOURCE_DIR}) else() # Build with OpenBLAS set(OpenBLAS_URL "https://github.com/xianyi/OpenBLAS/releases/download/v0.3.24/OpenBLAS-0.3.24-x64.zip") @@ -72,7 +114,7 @@ if(WIN32) DOWNLOAD_EXTRACT_TIMESTAMP true GIT_REPOSITORY https://github.com/ggerganov/whisper.cpp.git GIT_TAG ${Whispercpp_Build_GIT_TAG} - BUILD_COMMAND ${CMAKE_COMMAND} --build --config ${Whispercpp_BUILD_TYPE} + BUILD_COMMAND ${CMAKE_COMMAND} --build --config ${Whispercpp_BUILD_TYPE} --verbose BUILD_BYPRODUCTS /lib/static/${CMAKE_STATIC_LIBRARY_PREFIX}whisper${CMAKE_STATIC_LIBRARY_SUFFIX} /bin/${CMAKE_SHARED_LIBRARY_PREFIX}whisper${CMAKE_SHARED_LIBRARY_SUFFIX} @@ -88,11 +130,11 @@ if(WIN32) -DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM} -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 -DCMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES_} -DCMAKE_CXX_FLAGS=${WHISPER_EXTRA_CXX_FLAGS} -DCMAKE_C_FLAGS=${WHISPER_EXTRA_CXX_FLAGS} -DBUILD_SHARED_LIBS=ON -DWHISPER_BUILD_TESTS=OFF - -DWHISPER_BUILD_EXAMPLES=OFF ${WHISPER_ADDITIONAL_CMAKE_ARGS}) + -DWHISPER_BUILD_EXAMPLES=OFF -DCMAKE_MODULE_PATH=${CMAKE_SOURCE_DIR}/cmake ${WHISPER_ADDITIONAL_CMAKE_ARGS}) - if(NOT WHISPERCPP_WITH_CUDA) + if(NOT WHISPERCPP_WITH_CUDA AND NOT WHISPERCPP_WITH_CLBLAST) add_dependencies(Whispercpp_Build OpenBLAS) - endif(NOT WHISPERCPP_WITH_CUDA) + endif() else() # On Linux and MacOS build a static Whisper library ExternalProject_Add( @@ -123,12 +165,32 @@ if(WIN32) install(DIRECTORY ${INSTALL_DIR}/include DESTINATION ${CMAKE_SOURCE_DIR}/release) install(DIRECTORY ${INSTALL_DIR}/bin DESTINATION ${CMAKE_SOURCE_DIR}/release) - if(NOT WHISPERCPP_WITH_CUDA) + if(NOT WHISPERCPP_WITH_CUDA AND NOT WHISPERCPP_WITH_CLBLAST) # add openblas to the link line install(DIRECTORY ${OpenBLAS_DIR}/lib DESTINATION ${CMAKE_SOURCE_DIR}/release) install(DIRECTORY ${OpenBLAS_DIR}/include DESTINATION ${CMAKE_SOURCE_DIR}/release) install(DIRECTORY ${OpenBLAS_DIR}/bin DESTINATION ${CMAKE_SOURCE_DIR}/release) - else(NOT WHISPERCPP_WITH_CUDA) + elseif(WHISPERCPP_WITH_CLBLAST) + file(TO_CMAKE_PATH ${clblast_SOURCE_DIR} clblast_SOURCE_DIR) + # find the clblast DLLs in the bin directory of the CLBlast installation + file(GLOB CLBLAST_DLLS "${clblast_SOURCE_DIR}/bin/clblast.dll") + # if the files cannot be found, abort + if(NOT CLBLAST_DLLS) + message(FATAL_ERROR "Could not find CLBlast DLLs in ${clblast_SOURCE_DIR}/bin") + endif() + # copy the DLLs to the OBS plugin directory + install(FILES ${CLBLAST_DLLS} DESTINATION ${CMAKE_SOURCE_DIR}/release/bin) + + file(TO_CMAKE_PATH ${opencl_sdk_SOURCE_DIR} opencl_sdk_SOURCE_DIR) + # find the opencl SDK DLLs in the bin directory of the OpenCL SDK installation + file(GLOB OPENCL_SDK_DLLS "${opencl_sdk_SOURCE_DIR}/bin/OpenCL.dll") + # if the files cannot be found, abort + if(NOT OPENCL_SDK_DLLS) + message(FATAL_ERROR "Could not find OpenCL SDK DLLs in ${opencl_sdk_SOURCE_DIR}/bin") + endif() + # copy the DLLs to the OBS plugin directory + install(FILES ${OPENCL_SDK_DLLS} DESTINATION ${CMAKE_SOURCE_DIR}/release/bin) + else() # normalize CUDA path with file(TO_CMAKE_PATH) file(TO_CMAKE_PATH ${CUDA_TOOLKIT_ROOT_DIR} CUDA_TOOLKIT_ROOT_DIR) # find the CUDA DLLs for cuBLAS in the bin directory of the CUDA installation e.g. cublas64_NN.dll @@ -145,7 +207,7 @@ if(WIN32) endif() # copy the DLLs to the OBS plugin directory install(FILES ${CUBLAS_DLLS} ${CUBLASLT_DLLS} ${CUDART_DLLS} DESTINATION ${CMAKE_SOURCE_DIR}/release/bin) - endif(NOT WHISPERCPP_WITH_CUDA) + endif() else() # copy lib/ include/ and bin/ from ${INSTALL_DIR} to the release directory in the root of the project install(DIRECTORY ${INSTALL_DIR}/lib DESTINATION ${CMAKE_SOURCE_DIR}/release) diff --git a/build-windows.ps1 b/build-windows.ps1 index 16089c3..31bd002 100644 --- a/build-windows.ps1 +++ b/build-windows.ps1 @@ -4,7 +4,7 @@ Param( # check env var CPU_OR_CUDA if ($env:CPU_OR_CUDA -eq $null) { - Write-Host "Please set env var CPU_OR_CUDA to 'cpu' or the CUDA version you want to use" + Write-Host "Please set env var CPU_OR_CUDA to 'cpu', 'clblast' or the CUDA version you want to use" exit } @@ -12,6 +12,9 @@ $cmakeArgs = @() if ($env:CPU_OR_CUDA -eq "cpu") { $cmakeArgs += ("-DWHISPERCPP_WITH_CUDA=OFF") $zipFileName = "whispercpp-windows-cpu-$Version.zip" +} elseif ($env:CPU_OR_CUDA -eq "clblast") { + $cmakeArgs += ("-DWHISPERCPP_WITH_CUDA=OFF", "-DWHISPERCPP_WITH_CLBLAST=ON") + $zipFileName = "whispercpp-windows-clblast-$Version.zip" } else { $cmakeArgs += ( "-DWHISPERCPP_WITH_CUDA=ON", @@ -29,4 +32,4 @@ cmake --build build --config Release cmake --install build # compress the release folder -Compress-Archive -Path release -DestinationPath $zipFileName +Compress-Archive -Force -Path release -DestinationPath $zipFileName diff --git a/cmake/FindCLBlast.cmake b/cmake/FindCLBlast.cmake new file mode 100644 index 0000000..eda2cac --- /dev/null +++ b/cmake/FindCLBlast.cmake @@ -0,0 +1,43 @@ +# Assume the library is called libCLBlast.a and the headers are in 'include' +find_path(CLBlast_INCLUDE_DIR NAMES clblast.h + PATHS ${clblast_SOURCE_DIR}/include) + +find_library(CLBlast_LIBRARY NAMES clblast + PATHS ${clblast_SOURCE_DIR}/lib) + +# find opencl sdk includes +find_path(OPENCL_INCLUDE_DIR NAMES CL/opencl.h + PATHS ${opencl_sdk_SOURCE_DIR}/include) + +# find opencl sdk libraries +find_library(OPENCL_LIBRARY NAMES OpenCL + PATHS ${opencl_sdk_SOURCE_DIR}/lib) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(CLBlast DEFAULT_MSG + CLBlast_LIBRARY CLBlast_INCLUDE_DIR) + +if(CLBlast_FOUND AND NOT TARGET clbast) + add_library(clbast::clblast STATIC IMPORTED) + set_target_properties(clbast::clblast PROPERTIES + IMPORTED_LOCATION "${CLBlast_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${CLBlast_INCLUDE_DIR}") + # add opencl library + add_library(opencl STATIC IMPORTED) + set_target_properties(opencl PROPERTIES + IMPORTED_LOCATION "${OPENCL_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${OPENCL_INCLUDE_DIR}") + + # add clblast as an interface for clbast::clblast and opencl both + add_library(clblast INTERFACE) + target_link_libraries(clblast INTERFACE clbast::clblast opencl) + + # find the library dir and store in CLBlast_LIBRARY_DIR + get_filename_component(CLBlast_LIBRARY_DIR ${CLBlast_LIBRARY} DIRECTORY) + get_filename_component(OpenCL_LIBRARY_DIR ${OPENCL_LIBRARY} DIRECTORY) + + # Add to include directories + include_directories(${CLBlast_INCLUDE_DIR} ${OPENCL_INCLUDE_DIR}) + # add the link directories + link_directories(${CLBlast_LIBRARY_DIR} ${OpenCL_LIBRARY_DIR}) +endif() From 7787f688069ab7f43e1df806a60aed76f2b9eafa Mon Sep 17 00:00:00 2001 From: Roy Shilkrot Date: Tue, 16 Apr 2024 19:01:22 -0400 Subject: [PATCH 2/4] Update CUDA Toolkit installation condition in build workflow --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e29c3e3..f67a7af 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -110,14 +110,14 @@ jobs: uses: "actions/checkout@v4" - name: Install CUDA Toolkit - if: ${{ matrix.cublas != 'cpu' }} && ${{ matrix.cublas != 'clblast' }} + if: ${{ matrix.cublas != 'cpu' && matrix.cublas != 'clblast' }} id: cuda-toolkit uses: Jimver/cuda-toolkit@v0.2.11 with: cuda: '${{ matrix.cublas }}' - name: Set CUDA_TOOLKIT_ROOT_DIR if CUDA is installed - if: ${{ matrix.cublas != 'cpu' }} && ${{ matrix.cublas != 'clblast' }} + if: ${{ matrix.cublas != 'cpu' && matrix.cublas != 'clblast' }} run: | "CUDA_TOOLKIT_ROOT_DIR=$env:CUDA_PATH" >> $env:GITHUB_ENV From ec910be39441155175af2d3e81628da1e566a2d5 Mon Sep 17 00:00:00 2001 From: Roy Shilkrot Date: Tue, 16 Apr 2024 19:03:47 -0400 Subject: [PATCH 3/4] Update CMakeLists.txt to include CLBlast library and find_package --- CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ff627b1..772efed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,10 +76,6 @@ if(WIN32) endif() set(clblast_SOURCE_DIR ${clblast_SOURCE_DIR}/CLBlast-1.6.2-windows-x64) - message(STATUS "clblast_SOURCE_DIR: ${clblast_SOURCE_DIR}") - set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) - find_package(CLBlast REQUIRED) - set(OPENCL_SDK_URL "https://github.com/KhronosGroup/OpenCL-SDK/releases/download/v2023.12.14/OpenCL-SDK-v2023.12.14-Win-x64.zip") set(OPENCL_SDK_SHA256 "4C49F37A97B1B6D191B076C1E5D095B180E44BDC72DB32EC8B9748FF6ECFAEB6") FetchContent_Declare( @@ -89,6 +85,10 @@ if(WIN32) URL_HASH SHA256=${OPENCL_SDK_SHA256}) FetchContent_MakeAvailable(OpenCL_SDK) + message(STATUS "clblast_SOURCE_DIR: ${clblast_SOURCE_DIR}") + set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) + find_package(CLBlast REQUIRED) + set(WHISPER_ADDITIONAL_CMAKE_ARGS -DWHISPER_BLAS=OFF -DWHISPER_CUBLAS=OFF -DWHISPER_OPENBLAS=OFF -DWHISPER_CLBLAST=ON -Dclblast_SOURCE_DIR=${clblast_SOURCE_DIR} -Dopencl_sdk_SOURCE_DIR=${opencl_sdk_SOURCE_DIR}) else() From 025fd7705602d002a36a5077f2684c4f943b3280 Mon Sep 17 00:00:00 2001 From: Roy Shilkrot Date: Tue, 16 Apr 2024 19:26:46 -0400 Subject: [PATCH 4/4] Update OpenBLAS version to 0.3.27 in CMakeLists.txt --- CMakeLists.txt | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 772efed..8392695 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,20 +93,19 @@ if(WIN32) -DWHISPER_CLBLAST=ON -Dclblast_SOURCE_DIR=${clblast_SOURCE_DIR} -Dopencl_sdk_SOURCE_DIR=${opencl_sdk_SOURCE_DIR}) else() # Build with OpenBLAS - set(OpenBLAS_URL "https://github.com/xianyi/OpenBLAS/releases/download/v0.3.24/OpenBLAS-0.3.24-x64.zip") - set(OpenBLAS_SHA256 "6335128ee7117ea2dd2f5f96f76dafc17256c85992637189a2d5f6da0c608163") - ExternalProject_Add( + set(OpenBLAS_URL "https://github.com/OpenMathLib/OpenBLAS/releases/download/v0.3.27/OpenBLAS-0.3.27-x64.zip") + set(OpenBLAS_SHA256 "7B4D7504F274F8E26001AAB4E25EC05032D90B8785B0355DC0D09247858D9F1E") + FetchContent_Declare( OpenBLAS URL ${OpenBLAS_URL} URL_HASH SHA256=${OpenBLAS_SHA256} - DOWNLOAD_NO_PROGRESS true - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory ) - ExternalProject_Get_Property(OpenBLAS INSTALL_DIR) - set(OpenBLAS_DIR ${INSTALL_DIR}) - set(WHISPER_ADDITIONAL_ENV "OPENBLAS_PATH=${OpenBLAS_DIR}") - set(WHISPER_ADDITIONAL_CMAKE_ARGS -DWHISPER_BLAS=ON -DWHISPER_CUBLAS=OFF) + DOWNLOAD_EXTRACT_TIMESTAMP true + ) + FetchContent_MakeAvailable(OpenBLAS) + set(OpenBLAS_DIR ${openblas_SOURCE_DIR}) + message(STATUS "OpenBLAS_DIR: ${OpenBLAS_DIR}") + set(WHISPER_ADDITIONAL_ENV "OPENBLAS_PATH=${openblas_SOURCE_DIR}") + set(WHISPER_ADDITIONAL_CMAKE_ARGS -DWHISPER_BLAS=ON -DWHISPER_OPENBLAS=ON -DWHISPER_CUBLAS=OFF) endif() ExternalProject_Add( @@ -180,6 +179,7 @@ if(WIN32) endif() # copy the DLLs to the OBS plugin directory install(FILES ${CLBLAST_DLLS} DESTINATION ${CMAKE_SOURCE_DIR}/release/bin) + install(DIRECTORY ${clblast_SOURCE_DIR}/include ${opencl_sdk_SOURCE_DIR}/include DESTINATION ${CMAKE_SOURCE_DIR}/release) file(TO_CMAKE_PATH ${opencl_sdk_SOURCE_DIR} opencl_sdk_SOURCE_DIR) # find the opencl SDK DLLs in the bin directory of the OpenCL SDK installation