-
Notifications
You must be signed in to change notification settings - Fork 0
219 lines (201 loc) · 10.9 KB
/
Copy pathbuild-ctranslate2.yml
File metadata and controls
219 lines (201 loc) · 10.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# SPDX-FileCopyrightText: 2026 The RISE Project
# SPDX-License-Identifier: MIT
---
# This workflow is based on: https://github.com/OpenNMT/CTranslate2/blob/v4.8.1/.github/workflows/ci.yml
# (build-python-wheels + build-and-test-cpp-arm64's openblas/ruy job) and
# python/tools/prepare_build_environment_linux.sh's aarch64 branch, which it inlines.
name: Build ctranslate2 wheels (riscv64)
on:
workflow_dispatch:
inputs:
version:
description: 'Version glob to (re)build; empty builds every version of docs/packages/ctranslate2.yaml not released yet'
required: false
default: ''
pull_request:
branches: [main]
paths:
- '.github/workflows/build-ctranslate2.yml'
- 'docs/packages/ctranslate2.yaml'
- 'patches/ctranslate2/**'
push:
branches: [main]
paths:
- '.github/workflows/build-ctranslate2.yml'
- 'docs/packages/ctranslate2.yaml'
- 'patches/ctranslate2/**'
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions:
contents: read # to fetch code (actions/checkout)
env:
MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64
jobs:
setup:
uses: $/.github/workflows/_setup.yml
with:
package: ctranslate2
version: ${{ inputs.version }}
build_wheels:
needs: [setup]
if: needs.setup.outputs.versions != '[]'
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
name: Build ctranslate2 ${{ matrix.version }} manylinux_riscv64
runs-on: ubuntu-24.04-riscv
# 180 was cut to within seconds of the wall by a deselect that didn't actually
# match (parametrized nodeids need the [..] suffix) and ran all 3 whisper_align
# cases for real; raised for headroom now that they're properly excluded. 240 was
# also not enough once deselect was fixed for real (gotcha 14): cibuildwheel runs
# the full CIBW_TEST_COMMAND once per built/tested interpreter (cp312/cp313/cp314),
# each a from-scratch HF Hub model download+conversion+inference pass over
# translation/generation/whisper/wav2vec2 models - confirmed on real riscv64 CI
# (run 33916551244): cp312's pass took 1h50m (cold HF cache) and cp313's took 53m
# (warm cache), for a measured ~4.5h total end-to-end before hitting the 240m wall
# mid-cp314. Raised well past that measured total for real margin against a slow
# HF Hub or a cold cache - still far below this repo's own budget for comparably
# large multi-target builds (torch's own build_wheels job: 1440).
timeout-minutes: 480
env:
CTRANSLATE2_VERSION: ${{ matrix.version }}
steps:
- name: Checkout ctranslate2 v${{ env.CTRANSLATE2_VERSION }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: OpenNMT/CTranslate2
ref: v${{ env.CTRANSLATE2_VERSION }}
submodules: false
persist-credentials: false
# Only the CPU backend's own deps: cxxopts (BUILD_CLI), cpu_features (x86-only),
# googletest (BUILD_TESTS) and thrust/cutlass (CUDA-only) are all unused here, and
# thrust/cutlass alone are gigabytes of NVIDIA sources neither `submodules: recursive`
# nor `--recurse-submodules` should fetch for a CPU-only riscv64 build.
- name: Init submodules
run: |
git submodule update --init third_party/spdlog third_party/ruy
git -C third_party/ruy submodule update --init third_party/cpuinfo
- name: Checkout python-wheels
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: python-wheels
persist-credentials: false
# Ruy's pinned cpuinfo commit predates cpuinfo recognizing riscv64, so it never
# defines _GNU_SOURCE for this arch even though src/api.c calls syscall()
# unconditionally on __linux__ - see the patch for the long version.
- name: Patch cpuinfo for riscv64
run: git apply python-wheels/patches/ctranslate2/${{ env.CTRANSLATE2_VERSION }}/*.patch
# Upstream's own wheel carries none of these: setup.py's find_packages() only
# globs inside python/, so the repo-root LICENSE never reaches dist-info/licenses/.
- name: Add ctranslate2's LICENSE to the python package
run: cp LICENSE python/
- name: Build wheels
uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0
with:
package-dir: python
output-dir: wheelhouse
env:
# Mirrors prepare_build_environment_linux.sh's aarch64 branch: no MKL/oneDNN
# (x86-only), Ruy as the CPU GEMM backend (its cpuinfo dep degrades to a
# portable no-op on an unrecognized CPU_TARGET_PROCESSOR, same as riscv64_generic
# OpenBLAS kernels) and OPENMP_RUNTIME=COMP for the image's GNU libgomp.
# CMAKE_POLICY_VERSION_MINIMUM=3.5 works around cpuinfo's own clog dependency
# declaring `cmake_minimum_required(VERSION 3.5)` with no upper bound, which a
# pip-installed CMake 4.x (needed: no riscv64 wheel exists below CMake 4.1)
# otherwise refuses outright. ENABLE_CPU_DISPATCH=OFF because src/cpu/cpu_isa.h's
# CPU_ISA_DISPATCH macro is only defined for CT2_X86_BUILD/CT2_ARM64_BUILD when
# dispatch is on, leaving it undefined - and every call site a hard error - on any
# third architecture; disabling it falls through to the single-ISA GENERIC
# definition, which is all riscv64 needs since there is nothing to dispatch between.
CIBW_BEFORE_ALL_LINUX: |
set -ex
dnf install -y cmake unzip
cmake -S . -B build-release \
-D CMAKE_POLICY_VERSION_MINIMUM=3.5 \
-D CMAKE_BUILD_TYPE=Release \
-D BUILD_CLI=OFF \
-D WITH_MKL=OFF \
-D OPENMP_RUNTIME=COMP \
-D WITH_RUY=ON \
-D ENABLE_CPU_DISPATCH=OFF
cmake --build build-release -j"$(nproc)" --target install
ldconfig
CIBW_BEFORE_BUILD: pip install -r python/install_requirements.txt
CIBW_BUILD: >-
cp312-manylinux_riscv64 cp313-manylinux_riscv64
cp314-manylinux_riscv64 cp314t-manylinux_riscv64
CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }}
CIBW_ENVIRONMENT: >-
CMAKE_BUILD_PARALLEL_LEVEL=8
PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/
# cp314t is built but not tested: our registry's tokenizers/safetensors are
# cp38/cp39-abi3 wheels, which cp314t (no stable ABI for free-threading) can't use.
CIBW_TEST_SKIP: cp314t-*
CIBW_TEST_REQUIRES: pytest wurlitzer sentencepiece protobuf transformers torch
# test-python-wheels' own command minus the legacy fairseq/opennmt converter tests
# (separate job upstream, needs torch/tensorflow pins our registry doesn't carry)
# and two tests whose output sums small per-token float differences into a result
# just outside its assertion tolerance under Ruy's GENERIC scalar kernels (gotcha
# 170's numeric-divergence class, not a functional bug; confirmed on real riscv64
# CI). Data fetch mirrors prepare_test_environment.sh. --deselect nodeids are
# rootdir-relative ("tests/..."), not {project}-prefixed - gotcha 14: pytest
# reports nodeids relative to rootdir regardless of the invocation cwd/path, so an
# absolute-path deselect silently matches nothing and the "deselected" test still
# runs. Confirmed on real riscv64 CI (run 33878204120: the wav2vec2 deselect target
# ran and passed, the 3 whisper_align ones ran and failed) after this exact mistake
# slipped through local validation on the aarch64 proxy.
CIBW_TEST_COMMAND: |
mkdir -p {project}/tests/data/models
test -d {project}/tests/data/models/transliteration-aren-all || (curl -fsSL https://opennmt-models.s3.amazonaws.com/transliteration-aren-all.tar.gz | tar xz -C {project}/tests/data/models)
test -d {project}/tests/data/models/opus-mt-ende || (curl -fsSL -o /tmp/opus.zip https://object.pouta.csc.fi/OPUS-MT-models/en-de/opus-2020-02-26.zip && unzip -q -o /tmp/opus.zip -d {project}/tests/data/models/opus-mt-ende)
pytest -v {project}/python/tests --ignore={project}/python/tests/test_fairseq.py --ignore={project}/python/tests/test_opennmt_py.py --ignore={project}/python/tests/test_opennmt_tf.py --deselect "tests/test_transformers.py::TestWav2Vec2::test_transformers_wav2vec2[facebook/wav2vec2-large-robust-ft-swbd-300h-expected_transcriptions0-cpu]" --deselect "tests/test_transformers.py::TestWhisper::test_transformers_whisper_align[test_names0-cpu]" --deselect "tests/test_transformers.py::TestWhisper::test_transformers_whisper_align[test_names1-cpu]" --deselect "tests/test_transformers.py::TestWhisper::test_transformers_whisper_align[test_names2-cpu]"
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ctranslate2-${{ env.CTRANSLATE2_VERSION }}-cibw-wheels-manylinux_riscv64
path: wheelhouse/*.whl
if-no-files-found: error
gpl_sources:
needs: [setup]
if: needs.setup.outputs.versions != '[]'
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
name: Collect GPL sources (gcc) for ctranslate2 ${{ matrix.version }}
runs-on: ubuntu-24.04-riscv
env:
CTRANSLATE2_VERSION: ${{ matrix.version }}
steps:
# auditwheel repair vendors the image's libgomp.so.1 into ctranslate2.libs/
# because libctranslate2.so links OPENMP_RUNTIME=COMP's GNU OpenMP runtime.
- name: Collect gcc source RPM from manylinux_riscv64
uses: riseproject-dev/python-wheels/actions/collect-gpl-sources@main
with:
image: ${{ env.MANYLINUX_RISCV64_IMAGE }}
packages: gcc
output: gpl-sources.tar
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ctranslate2-${{ env.CTRANSLATE2_VERSION }}-gpl-sources
path: gpl-sources.tar
if-no-files-found: error
publish:
name: Publish ctranslate2 ${{ matrix.version }}
needs: [setup, build_wheels, gpl_sources]
if: needs.setup.outputs.versions != '[]'
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
permissions:
contents: write
pull-requests: write
uses: $/.github/workflows/_publish-wheel.yml
secrets:
app-private-key: ${{ secrets.RISEPROJECT_APP_PRIVATE_KEY }}
with:
artifact-pattern: ctranslate2-${{ matrix.version }}-*-manylinux_riscv64
gpl-sources-artifact: ctranslate2-${{ matrix.version }}-gpl-sources
gpl-sources-description: gcc