Skip to content

Commit 421e388

Browse files
committed
uucore: detect CPU features on Android
Use Rust's supported CPU feature detection on Android instead of disabling every feature. Enable the checksum debug tests and add an x86_64 SSE2 regression. Run Android CI on both API 28 and API 37.0 so the detection tests cover an older Android release and Android 17. Closes #15233
1 parent 198c615 commit 421e388

6 files changed

Lines changed: 59 additions & 52 deletions

File tree

‎.github/workflows/android.yml‎

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
name: Android
22

33
# spell-checker:ignore (people) reactivecircus juliangruber
4-
# spell-checker:ignore (shell/tools) TERMUX nextest udevadm pkill
5-
# spell-checker:ignore (misc) swiftshader playstore DATALOSS noaudio
4+
# spell-checker:ignore (shell/tools) TERMUX nextest udevadm pkill cmdline commandlinetools sdkmanager
5+
# spell-checker:ignore (misc) swiftshader playstore noaudio
66

77
on:
88
pull_request:
@@ -37,7 +37,7 @@ jobs:
3737
os: [ubuntu-latest] # , macos-latest
3838
cores: [4] # , 6
3939
ram: [4096]
40-
api-level: [28]
40+
api-level: [28, "37.0"]
4141
target: [google_apis_playstore]
4242
arch: [x86_64] # ,x86 ,arm64-v8a
4343
runs-on: ${{ matrix.os }}
@@ -64,7 +64,6 @@ jobs:
6464
continue-on-error: true
6565
run: |
6666
ls -lah /mnt/
67-
cat /mnt/DATALOSS_WARNING_README.txt
6867
sudo mkdir /mnt/data
6968
sudo chmod a+rwx /mnt/data
7069
mkdir /mnt/data/.android && ln -s /mnt/data/.android ~/.android
@@ -78,6 +77,14 @@ jobs:
7877
- uses: actions/checkout@v7.0.1
7978
with:
8079
persist-credentials: false
80+
- name: Install Android SDK command-line tools 22.0
81+
run: |
82+
curl --fail --location --retry 3 --output "$RUNNER_TEMP/commandlinetools.zip" \
83+
https://dl.google.com/android/repository/commandlinetools-linux-15859902_latest.zip
84+
unzip -q "$RUNNER_TEMP/commandlinetools.zip" -d "$RUNNER_TEMP/android-tools"
85+
mv "$ANDROID_HOME/cmdline-tools/latest" "$RUNNER_TEMP/android-tools-previous"
86+
mv "$RUNNER_TEMP/android-tools/cmdline-tools" "$ANDROID_HOME/cmdline-tools/latest"
87+
"$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" --version
8188
- name: Collect information about runner
8289
if: always()
8390
continue-on-error: true
@@ -121,6 +128,7 @@ jobs:
121128
disk-size: ${{ env.EMULATOR_DISK_SIZE }}
122129
cores: ${{ env.EMULATOR_CORES }}
123130
force-avd-creation: true
131+
disable-animations: false
124132
emulator-options: ${{ env.COMMON_EMULATOR_OPTIONS }} -no-snapshot-load
125133
emulator-boot-timeout: ${{ env.EMULATOR_BOOT_TIMEOUT }}
126134
script: |
@@ -166,13 +174,14 @@ jobs:
166174
disk-size: ${{ env.EMULATOR_DISK_SIZE }}
167175
cores: ${{ env.EMULATOR_CORES }}
168176
force-avd-creation: false
177+
disable-animations: false
169178
emulator-options: ${{ env.COMMON_EMULATOR_OPTIONS }} -no-snapshot-save -snapshot ${{ env.AVD_CACHE_KEY }}
170179
emulator-boot-timeout: ${{ env.EMULATOR_BOOT_TIMEOUT }}
171180
# This is not a usual script. Every line is executed in a separate shell with `sh -c`. If
172181
# one of the lines returns with error the whole script is failed (like running a script with
173182
# set -e) and in consequences the other lines (shells) are not executed.
174183
script: |
175-
util/android-commands.sh sync_host
184+
timeout --verbose --kill-after=30s 10m util/android-commands.sh sync_host
176185
util/android-commands.sh build
177186
util/android-commands.sh tests
178187
if [ "${{ steps.rust-cache.outputs.cache-hit }}" != 'true' ]; then util/android-commands.sh sync_image; fi; exit 0

‎src/uucore/src/lib/features/hardware.rs‎

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -243,12 +243,8 @@ impl HasHardwareFeatures for SimdPolicy {
243243

244244
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
245245
fn detect_avx512() -> bool {
246-
if cfg!(target_os = "android") {
247-
false
248-
} else {
249-
std::arch::is_x86_feature_detected!("avx512f")
250-
&& std::arch::is_x86_feature_detected!("avx512bw")
251-
}
246+
std::arch::is_x86_feature_detected!("avx512f")
247+
&& std::arch::is_x86_feature_detected!("avx512bw")
252248
}
253249

254250
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
@@ -258,11 +254,7 @@ fn detect_avx512() -> bool {
258254

259255
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
260256
fn detect_avx2() -> bool {
261-
if cfg!(target_os = "android") {
262-
false
263-
} else {
264-
std::arch::is_x86_feature_detected!("avx2")
265-
}
257+
std::arch::is_x86_feature_detected!("avx2")
266258
}
267259

268260
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
@@ -272,11 +264,7 @@ fn detect_avx2() -> bool {
272264

273265
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
274266
fn detect_pclmulqdq() -> bool {
275-
if cfg!(target_os = "android") {
276-
false
277-
} else {
278-
std::arch::is_x86_feature_detected!("pclmulqdq")
279-
}
267+
std::arch::is_x86_feature_detected!("pclmulqdq")
280268
}
281269

282270
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
@@ -286,11 +274,7 @@ fn detect_pclmulqdq() -> bool {
286274

287275
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
288276
fn detect_sse2() -> bool {
289-
if cfg!(target_os = "android") {
290-
false
291-
} else {
292-
std::arch::is_x86_feature_detected!("sse2")
293-
}
277+
std::arch::is_x86_feature_detected!("sse2")
294278
}
295279

296280
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
@@ -300,11 +284,7 @@ fn detect_sse2() -> bool {
300284

301285
#[cfg(all(target_arch = "aarch64", target_endian = "little"))]
302286
fn detect_asimd() -> bool {
303-
if cfg!(target_os = "android") {
304-
false
305-
} else {
306-
std::arch::is_aarch64_feature_detected!("asimd")
307-
}
287+
std::arch::is_aarch64_feature_detected!("asimd")
308288
}
309289

310290
#[cfg(not(all(target_arch = "aarch64", target_endian = "little")))]
@@ -315,11 +295,7 @@ fn detect_asimd() -> bool {
315295
#[cfg(target_arch = "aarch64")]
316296
fn detect_pmull() -> bool {
317297
// PMULL is an optional extension. ASIMD alone is not enough.
318-
if cfg!(target_os = "android") {
319-
false
320-
} else {
321-
std::arch::is_aarch64_feature_detected!("pmull")
322-
}
298+
std::arch::is_aarch64_feature_detected!("pmull")
323299
}
324300

325301
#[cfg(not(target_arch = "aarch64"))]

‎tests/by-util/test_cksum.rs‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3320,7 +3320,6 @@ mod format_mix {
33203320
}
33213321
}
33223322

3323-
#[cfg(not(target_os = "android"))]
33243323
mod debug_flag {
33253324
use super::*;
33263325

‎tests/by-util/test_wc.rs‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,20 @@ fn test_invalid_byte_sequence_word_count() {
872872
.stdout_is(" 1 3 6\n");
873873
}
874874

875+
#[test]
876+
#[cfg(all(target_arch = "x86_64", not(wasi_runner)))]
877+
fn test_debug_reports_sse2_on_x86_64() {
878+
// SSE2 is part of the x86_64 baseline
879+
new_ucmd!()
880+
.args(&["-l", "--debug"])
881+
.env("GLIBC_TUNABLES", "")
882+
.pipe_in("line\n")
883+
.succeeds()
884+
.stdout_is("1\n")
885+
.stderr_contains("using hardware support")
886+
.stderr_contains("SSE2");
887+
}
888+
875889
#[cfg(unix)]
876890
#[test]
877891
#[cfg_attr(wasi_runner, ignore = "WASI sandbox: host paths not visible")]

‎util/android-commands.sh‎

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,9 @@ take_screen_shot() {
121121

122122
get_app_user() {
123123
app="$1"
124-
app_user="$(adb shell dumpsys package $app | grep 'userId=' | cut -d= -f2 | sort -u)"
125-
if [[ -z "$app_user" ]]; then
124+
app_user="$(adb shell cmd package list packages -U "$app" | tr -d '\r' |
125+
awk -v app="$app" '$1 == "package:" app { sub(/^uid:/, "", $2); print $2 }')"
126+
if [[ ! "$app_user" =~ ^[0-9]+$ ]]; then
126127
echo "Couldn't find user for app: $app">&2
127128
exit 1
128129
fi
@@ -552,14 +553,18 @@ sync_host() {
552553
cache_home="${HOME}/${cache_dir_name}"
553554
cache_dest="$dev_home_dir/${cache_dir_name}"
554555

555-
reinit_ssh_connection
556+
# Keep Termux in the foreground so Android does not freeze its SSH processes.
557+
adb shell am start -n com.termux/.HomeActivity || return
558+
reinit_ssh_connection || return
556559

557560
echo "Running sync host -> image: ${repo}"
558561

559562
# run_command_via_ssh "mkdir $dev_home_dir/coreutils"
560563

561-
copy_file_or_dir_to_device_via_ssh "$repo" "$dev_home_dir"
562-
[[ -e "$cache_home" ]] && copy_file_or_dir_to_device_via_ssh "$cache_home" "$cache_dest"
564+
copy_file_or_dir_to_device_via_ssh "$repo" "$dev_home_dir" || return
565+
if [[ -e "$cache_home" ]]; then
566+
copy_file_or_dir_to_device_via_ssh "$cache_home" "$cache_dest" || return
567+
fi
563568

564569
echo "Finished sync host -> image: ${repo}"
565570
}

‎util/android-scripts/run-tests.sh‎

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,32 @@ export PATH=$HOME/.cargo/bin:$PATH
88
export RUST_BACKTRACE=full
99
export CARGO_TERM_COLOR=always
1010
export CARGO_INCREMENTAL=0
11+
export CARGO_BUILD_JOBS=2
1112

1213
echo "PATH: $PATH"
1314

1415
run_with_retry() {
15-
tries=$1
16+
local tries=$1
1617
shift 1
18+
local exit_code=0
1719

18-
for i in $(seq 1 $tries); do
20+
for ((i = 1; i <= tries; i++)); do
1921
echo "Try #$i of $tries: run $*"
20-
"$@" && echo "Done in try#$i" && return 0
22+
if "$@"; then
23+
echo "Done in try#$i"
24+
return 0
25+
else
26+
exit_code=$?
27+
fi
2128
done
2229

23-
exit_code=$?
24-
2530
echo "Still failing after $tries. Code: $exit_code"
2631

2732
return $exit_code
2833
}
2934

3035
run_tests_in_subprocess() (
3136

32-
# limit virtual memory to 3GB to avoid that OS kills sshd
33-
ulimit -v $((1024 * 1024 * 3))
34-
3537
watchplus() {
3638
# call: watchplus <interval> <command>
3739
while true; do
@@ -48,7 +50,9 @@ run_tests_in_subprocess() (
4850
watchplus 2 df -h &
4951
watchplus 2 free -hm &
5052

51-
nextest_params=(--profile ci --hide-progress-bar --features feat_os_unix_android)
53+
# Recent Android allocators reserve more virtual memory than a 3 GiB limit
54+
# allows. Limit parallelism to reduce memory pressure without capping addresses.
55+
nextest_params=(--profile ci --hide-progress-bar --test-threads 2 --features feat_os_unix_android)
5256

5357
# run tests
5458
cd ~/coreutils && \
@@ -64,5 +68,5 @@ run_tests_in_subprocess() (
6468
return $result
6569
)
6670

67-
# run sub-shell to be able to use ulimit without affecting the sshd
71+
# Keep the resource monitors and their cleanup in a separate shell.
6872
run_tests_in_subprocess

0 commit comments

Comments
 (0)