14 Commits

Author SHA1 Message Date
vpshostreview
14cf7fe435 Add VPS Host Review to the result submission sites (#133)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 23:33:42 -04:00
Mason Rowe
316260707a fix formatting issue 2026-09-20 00:27:26 -04:00
Mason Rowe
ad1af039ce pull fio/iperf3 binaries from github releases instead of repo 2026-09-20 00:26:00 -04:00
Mason Rowe
7d27d65cb3 update binary workflows to poll virustotal for scan completion 2026-09-19 21:42:37 -04:00
Mason Rowe
e29813716c update binary workflows to grab github-hosted toolchain assets 2026-09-19 21:25:18 -04:00
Mason Rowe
c0aa5b8870 update fio/iperf3 binary generation workflows 2026-09-19 20:31:32 -04:00
Mason Rowe
bf41ddf401 add geekbench score parsing logic for upcoming GB release 2026-09-17 23:44:09 -04:00
LTSlw
f8c6a48cd6 Add Geekbench 7 support (#129)
* Add Geekbench 7 support

* Add Geekbench 7 documentation to README
2026-07-28 19:52:04 -04:00
Mason Rowe
1d20bd9b05 Update README 2026-07-04 15:58:15 -04:00
Mason Rowe
3474d82f83 shellcheck fix on line 804 (SC2086) 2026-07-03 22:05:37 -04:00
Michael Hohl
6ea1d66e0f Fix: iperf_test latency measurement ignores IPv4/IPv6 (#126)
`iperf_test` only calls `ping -c1 $URL` right now, not passing IPv4 or IPv6 parameters to ping. It thus doesn't differentiate between IPv4 and IPv6 latency at all.
2026-07-03 21:15:30 -04:00
Mason Rowe
3125fedff1 correction for fio's kilobyte vs kibibyte for disk speeds (#120) 2026-07-03 21:02:43 -04:00
Mason Rowe
97b5ec226f fix for bad uptime calculation (#92) 2026-05-19 21:55:39 -04:00
Mason Rowe
d79e781ca3 fix for zfs fs disk calculation (#118) 2026-05-19 21:50:33 -04:00
16 changed files with 395 additions and 370 deletions

View File

@@ -2,32 +2,40 @@ name: Build fio Static Binaries
on: on:
workflow_dispatch: workflow_dispatch:
schedule:
# check upstream for a new fio release once a day
- cron: '23 5 * * *'
permissions:
contents: write
jobs: jobs:
check-release: check-release:
runs-on: self-hosted runs-on: ubuntu-latest
outputs: outputs:
latest-version: ${{ steps.get-version.outputs.version }} latest-version: ${{ steps.get-version.outputs.version }}
should-build: ${{ steps.check-version.outputs.should-build }} should-build: ${{ steps.check-version.outputs.should-build }}
steps: steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Get latest fio release - name: Get latest fio release
id: get-version id: get-version
run: | run: |
# Get the latest release tag from GitHub API # Get the latest release tag from GitHub API (e.g. "fio-3.41")
LATEST_VERSION=$(curl -4 --retry 5 --retry-delay 2 --connect-timeout 15 -s https://api.github.com/repos/axboe/fio/releases/latest | jq -r '.tag_name') LATEST_VERSION=$(curl -4 --retry 5 --retry-delay 2 --connect-timeout 15 -s https://api.github.com/repos/axboe/fio/releases/latest | jq -r '.tag_name')
echo "Latest fio version: $LATEST_VERSION" echo "Latest fio version: $LATEST_VERSION"
if [ -z "$LATEST_VERSION" ] || [ "$LATEST_VERSION" = "null" ]; then
echo "Failed to determine latest fio version"
exit 1
fi
echo "version=$LATEST_VERSION" >> $GITHUB_OUTPUT echo "version=$LATEST_VERSION" >> $GITHUB_OUTPUT
- name: Check if version exists in releases - name: Check if version exists in releases
id: check-version id: check-version
run: | run: |
VERSION="${{ steps.get-version.outputs.version }}" VERSION="${{ steps.get-version.outputs.version }}"
# Check if this version already exists in our releases # Check if this version already exists in our releases (upstream tag is
if gh release view "fio-$VERSION" --repo ${{ github.repository }} >/dev/null 2>&1; then # already prefixed, e.g. "fio-3.41", so it can be used as-is)
if gh release view "$VERSION" --repo ${{ github.repository }} >/dev/null 2>&1; then
echo "Version $VERSION already exists in releases" echo "Version $VERSION already exists in releases"
echo "should-build=false" >> $GITHUB_OUTPUT echo "should-build=false" >> $GITHUB_OUTPUT
else else
@@ -40,8 +48,9 @@ jobs:
build: build:
needs: check-release needs: check-release
if: needs.check-release.outputs.should-build == 'true' if: needs.check-release.outputs.should-build == 'true'
runs-on: self-hosted runs-on: ubuntu-latest
strategy: strategy:
fail-fast: false
matrix: matrix:
include: include:
- arch: x64 - arch: x64
@@ -58,81 +67,72 @@ jobs:
host: arm-linux-gnueabihf host: arm-linux-gnueabihf
steps: steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Create compilation script - name: Create compilation script
run: | run: |
VERSION="${{ needs.check-release.outputs.latest-version }}"
ARCH="${{ matrix.arch }}"
CROSS="${{ matrix.cross }}"
HOST="${{ matrix.host }}"
# Single script for all architectures using musl cross-compilation # Single script for all architectures using musl cross-compilation
cat > compile-fio.sh << EOF cat > compile-fio.sh << 'EOF'
#!/bin/bash #!/bin/bash
set -e set -e
# Activate Holy Build Box lib compilation environment # Activate Holy Build Box lib compilation environment
source /hbb/activate source /hbb/activate
set -x set -x
# remove obsolete CentOS repos # remove obsolete CentOS repos
cd /etc/yum.repos.d/ cd /etc/yum.repos.d/
rm -f CentOS-Base.repo CentOS-SCLo-scl-rh.repo CentOS-SCLo-scl.repo CentOS-fasttrack.repo CentOS-x86_64-kernel.repo rm -f CentOS-Base.repo CentOS-SCLo-scl-rh.repo CentOS-SCLo-scl.repo CentOS-fasttrack.repo CentOS-x86_64-kernel.repo
yum install -y yum-plugin-ovl # fix for docker overlay fs yum install -y yum-plugin-ovl # fix for docker overlay fs
yum install -y xz yum install -y xz
# download musl cross compilation toolchain # download musl cross compilation toolchain - mirrored as a release asset on
# this repo since musl.cc blocks GitHub Actions IP ranges (musl.cc fallback
# kept for local runs)
cd ~ cd ~
curl -L -4 --retry 5 --retry-delay 2 --connect-timeout 15 "https://musl.cc/\$CROSS-cross.tgz" -o "\$CROSS-cross.tgz" curl -fL -4 --retry 5 --retry-delay 2 --connect-timeout 15 "https://github.com/masonr/yet-another-bench-script/releases/download/toolchains/$CROSS-cross.tgz" -o "$CROSS-cross.tgz" \
tar xf "\$CROSS-cross.tgz" || curl -fL -4 --retry 5 --retry-delay 2 --connect-timeout 15 "https://musl.cc/$CROSS-cross.tgz" -o "$CROSS-cross.tgz"
tar xf "$CROSS-cross.tgz"
# download, compile, and install libaio as static library # download, compile, and install libaio as static library
cd ~ cd ~
curl -L -4 --retry 5 --retry-delay 2 --connect-timeout 15 http://ftp.de.debian.org/debian/pool/main/liba/libaio/libaio_0.3.113.orig.tar.gz -o "libaio.tar.gz" curl -L -4 --retry 5 --retry-delay 2 --connect-timeout 15 http://ftp.de.debian.org/debian/pool/main/liba/libaio/libaio_0.3.113.orig.tar.gz -o "libaio.tar.gz"
tar xf libaio.tar.gz tar xf libaio.tar.gz
cd libaio-*/src cd libaio-*/src
CC=/root/\$CROSS-cross/bin/\$CROSS-gcc ENABLE_SHARED=0 make prefix=/hbb_exe install CC=/root/$CROSS-cross/bin/$CROSS-gcc ENABLE_SHARED=0 make prefix=/hbb_exe install
# Activate Holy Build Box exe compilation environment # Activate Holy Build Box exe compilation environment
source /hbb_exe/activate source /hbb_exe/activate
# download and compile fio # download and compile fio
cd ~ cd ~
curl -L -4 --retry 5 --retry-delay 2 --connect-timeout 15 "https://github.com/axboe/fio/archive/\$VERSION.tar.gz" -o "fio.tar.gz" curl -L -4 --retry 5 --retry-delay 2 --connect-timeout 15 "https://github.com/axboe/fio/archive/$VERSION.tar.gz" -o "fio.tar.gz"
tar xf fio.tar.gz tar xf fio.tar.gz
cd fio-\${VERSION#fio-}* cd fio-fio-*
CC=/root/\$CROSS-cross/bin/\$CROSS-gcc ./configure --disable-native --build-static # fio >= 3.42 includes both linux/prctl.h and sys/prctl.h in backend.c, which
make # redefines struct prctl_mm_map under musl; sys/prctl.h alone is sufficient
sed -i '/#include <linux\/prctl.h>/d' backend.c
CC=/root/$CROSS-cross/bin/$CROSS-gcc ./configure --disable-native --build-static
# link against libatomic for 32-bit/ARM targets that lack native 64-bit atomics
make EXTLIBS+=' -latomic'
# verify no external shared library links # verify no external shared library links
libcheck fio libcheck fio
# copy fio binary to mounted dir # copy fio binary to mounted dir
cp fio "/io/fio_\$ARCH" cp fio "/io/fio_$ARCH"
EOF EOF
chmod +x compile-fio.sh chmod +x compile-fio.sh
- name: Compile fio binary - name: Compile fio binary
run: | run: |
ARCH="${{ matrix.arch }}"
CROSS="${{ matrix.cross }}"
HOST="${{ matrix.host }}"
# Use musl cross-compilation for all architectures # Use musl cross-compilation for all architectures
docker run --rm -v $(pwd):/io --env ARCH=$ARCH --env CROSS=$CROSS --env HOST=$HOST --env VERSION="${{ needs.check-release.outputs.latest-version }}" phusion/holy-build-box-64:latest bash /io/compile-fio.sh docker run --rm -v $(pwd):/io --env ARCH=${{ matrix.arch }} --env CROSS=${{ matrix.cross }} --env HOST=${{ matrix.host }} --env VERSION="${{ needs.check-release.outputs.latest-version }}" phusion/holy-build-box-64:latest bash /io/compile-fio.sh
- name: Verify binary - name: Verify binary
run: | run: |
ARCH="${{ matrix.arch }}" ls -la fio_${{ matrix.arch }}
ls -la fio_$ARCH file fio_${{ matrix.arch }}
file fio_$ARCH
- name: Upload binary as artifact - name: Upload binary as artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
@@ -144,7 +144,7 @@ jobs:
virustotal-scan: virustotal-scan:
needs: [check-release, build] needs: [check-release, build]
if: needs.check-release.outputs.should-build == 'true' if: needs.check-release.outputs.should-build == 'true'
runs-on: self-hosted runs-on: ubuntu-latest
outputs: outputs:
scan-results: ${{ steps.scan-summary.outputs.results }} scan-results: ${{ steps.scan-summary.outputs.results }}
all-clean: ${{ steps.scan-summary.outputs.all-clean }} all-clean: ${{ steps.scan-summary.outputs.all-clean }}
@@ -166,14 +166,13 @@ jobs:
echo "## VirusTotal Scan Results" > scan_results.md echo "## VirusTotal Scan Results" > scan_results.md
echo "| Binary | Status | Malicious | Suspicious | Undetected | VirusTotal URL |" >> scan_results.md echo "| Binary | Status | Malicious | Suspicious | Undetected | VirusTotal URL |" >> scan_results.md
echo "|--------|--------|-----------|------------|------------|----------------|" >> scan_results.md echo "|--------|--------|-----------|------------|------------|----------------|" >> scan_results.md
ALL_CLEAN=true ALL_CLEAN=true
SCAN_DATA=""
for binary in scan-binaries/fio_*; do for binary in scan-binaries/fio_*; do
filename=$(basename "$binary") filename=$(basename "$binary")
echo "Uploading $filename to VirusTotal..." echo "Uploading $filename to VirusTotal..."
# Upload to VirusTotal # Upload to VirusTotal
upload_response=$(curl -4 --retry 5 --retry-delay 2 --connect-timeout 15 -s --request POST \ upload_response=$(curl -4 --retry 5 --retry-delay 2 --connect-timeout 15 -s --request POST \
--url https://www.virustotal.com/api/v3/files \ --url https://www.virustotal.com/api/v3/files \
@@ -181,85 +180,90 @@ jobs:
--header 'content-type: multipart/form-data' \ --header 'content-type: multipart/form-data' \
--header "x-apikey: ${{ secrets.VIRUSTOTAL_API_KEY }}" \ --header "x-apikey: ${{ secrets.VIRUSTOTAL_API_KEY }}" \
--form "file=@$binary") --form "file=@$binary")
analysis_id=$(echo "$upload_response" | jq -r '.data.id') analysis_id=$(echo "$upload_response" | jq -r '.data.id')
echo "Analysis ID for $filename: $analysis_id" echo "Analysis ID for $filename: $analysis_id"
if [ "$analysis_id" = "null" ] || [ -z "$analysis_id" ]; then if [ "$analysis_id" = "null" ] || [ -z "$analysis_id" ]; then
echo "Failed to upload $filename to VirusTotal" echo "Failed to upload $filename to VirusTotal"
echo "| $filename | Upload Failed | N/A | N/A | N/A | N/A |" >> scan_results.md echo "| $filename | Upload Failed | N/A | N/A | N/A | N/A |" >> scan_results.md
ALL_CLEAN=false ALL_CLEAN=false
continue continue
fi fi
# Store analysis ID for later retrieval # Store analysis ID for later retrieval
echo "${filename}:${analysis_id}" >> analysis_ids.txt echo "${filename}:${analysis_id}" >> analysis_ids.txt
done done
echo "all_clean_upload=$ALL_CLEAN" >> $GITHUB_OUTPUT
# Wait 2 minutes for scans to complete
echo "Waiting 2 minutes for VirusTotal scans to complete..."
sleep 120
- name: Retrieve VirusTotal scan results - name: Retrieve VirusTotal scan results
id: get-results id: get-results
run: | run: |
ALL_CLEAN=true ALL_CLEAN=true
SCAN_SUMMARY=""
# Poll each analysis until it completes; VirusTotal scans can take a few
# minutes after upload, so allow up to ~5 minutes per binary (10 polls,
# 30s apart) before giving up. Files are processed sequentially, so by
# the time the first completes the rest are usually already done.
while IFS=':' read -r filename analysis_id; do while IFS=':' read -r filename analysis_id; do
echo "Retrieving results for $filename (ID: $analysis_id)..." echo "Retrieving results for $filename (ID: $analysis_id)..."
# Get scan results status="queued"
result_response=$(curl -4 --retry 5 --retry-delay 2 --connect-timeout 15 -s --request GET \ for ((attempts=1; attempts<=10; attempts++)); do
--url "https://www.virustotal.com/api/v3/analyses/$analysis_id" \ # Get scan results
--header 'accept: application/json' \ result_response=$(curl -4 --retry 5 --retry-delay 2 --connect-timeout 15 -s --request GET \
--header "x-apikey: ${{ secrets.VIRUSTOTAL_API_KEY }}") --url "https://www.virustotal.com/api/v3/analyses/$analysis_id" \
--header 'accept: application/json' \
status=$(echo "$result_response" | jq -r '.data.attributes.status // "unknown"') --header "x-apikey: ${{ secrets.VIRUSTOTAL_API_KEY }}")
status=$(echo "$result_response" | jq -r '.data.attributes.status // "unknown"')
[ "$status" = "completed" ] && break
echo "$filename still scanning (attempt $attempts of 10), waiting 30s..."
sleep 30
done
if [ "$status" = "completed" ]; then if [ "$status" = "completed" ]; then
malicious=$(echo "$result_response" | jq -r '.data.attributes.stats.malicious // 0') malicious=$(echo "$result_response" | jq -r '.data.attributes.stats.malicious // 0')
suspicious=$(echo "$result_response" | jq -r '.data.attributes.stats.suspicious // 0') suspicious=$(echo "$result_response" | jq -r '.data.attributes.stats.suspicious // 0')
undetected=$(echo "$result_response" | jq -r '.data.attributes.stats.undetected // 0') undetected=$(echo "$result_response" | jq -r '.data.attributes.stats.undetected // 0')
# Get file hash from the item link # Get file hash from the item link
item_link=$(echo "$result_response" | jq -r '.data.links.item // ""') item_link=$(echo "$result_response" | jq -r '.data.links.item // ""')
file_hash=$(echo "$item_link" | sed 's/.*files\///') file_hash=$(echo "$item_link" | sed 's/.*files\///')
vt_url="https://www.virustotal.com/gui/file/$file_hash" vt_url="https://www.virustotal.com/gui/file/$file_hash"
if [ "$malicious" -gt 0 ] || [ "$suspicious" -gt 0 ]; then if [ "$malicious" -gt 0 ] || [ "$suspicious" -gt 0 ]; then
status_text="⚠️ FLAGGED" status_text="⚠️ FLAGGED"
ALL_CLEAN=false ALL_CLEAN=false
else else
status_text="✅ Clean" status_text="✅ Clean"
fi fi
echo "| $filename | $status_text | $malicious | $suspicious | $undetected | [$file_hash]($vt_url) |" >> scan_results.md echo "| $filename | $status_text | $malicious | $suspicious | $undetected | [$file_hash]($vt_url) |" >> scan_results.md
else else
echo "| $filename | ⏳ Pending | N/A | N/A | N/A | Scan not completed |" >> scan_results.md echo "| $filename | ⏳ Timed out | N/A | N/A | N/A | Scan did not complete in ~5 min |" >> scan_results.md
ALL_CLEAN=false ALL_CLEAN=false
fi fi
done < analysis_ids.txt done < analysis_ids.txt
echo "all_clean=$ALL_CLEAN" >> $GITHUB_OUTPUT echo "all_clean=$ALL_CLEAN" >> $GITHUB_OUTPUT
# Add summary to GitHub step summary # Add summary to GitHub step summary
cat scan_results.md >> $GITHUB_STEP_SUMMARY cat scan_results.md >> $GITHUB_STEP_SUMMARY
- name: Create scan summary - name: Create scan summary
id: scan-summary id: scan-summary
run: | run: |
RESULTS=$(cat scan_results.md)
ALL_CLEAN="${{ steps.get-results.outputs.all_clean }}" ALL_CLEAN="${{ steps.get-results.outputs.all_clean }}"
# Escape newlines for GitHub output # Pass the scan results through as a multi-line output (heredoc delimiter
RESULTS_ESCAPED=$(echo "$RESULTS" | sed ':a;N;$!ba;s/\n/\\n/g') # syntax) so the markdown table renders correctly in the release body
{
echo "results=$RESULTS_ESCAPED" >> $GITHUB_OUTPUT echo "results<<RESULTS_EOF"
cat scan_results.md
echo "RESULTS_EOF"
} >> $GITHUB_OUTPUT
echo "all-clean=$ALL_CLEAN" >> $GITHUB_OUTPUT echo "all-clean=$ALL_CLEAN" >> $GITHUB_OUTPUT
- name: Upload scan results as artifact - name: Upload scan results as artifact
@@ -274,11 +278,8 @@ jobs:
create-release: create-release:
needs: [check-release, build, virustotal-scan] needs: [check-release, build, virustotal-scan]
if: needs.check-release.outputs.should-build == 'true' && needs.virustotal-scan.outputs.all-clean == 'true' if: needs.check-release.outputs.should-build == 'true' && needs.virustotal-scan.outputs.all-clean == 'true'
runs-on: self-hosted runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download all artifacts - name: Download all artifacts
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
@@ -291,6 +292,13 @@ jobs:
find artifacts -name "fio_*" -type f -exec cp {} release-assets/ \; find artifacts -name "fio_*" -type f -exec cp {} release-assets/ \;
ls -la release-assets/ ls -la release-assets/
- name: Download upstream source tarball
run: |
# Attach the exact upstream source these binaries were built from
# (fio is GPL-2.0; distributing binaries requires offering the source)
curl -L --retry 5 --retry-delay 2 --connect-timeout 15 "https://github.com/axboe/fio/archive/${{ needs.check-release.outputs.latest-version }}.tar.gz" -o "release-assets/${{ needs.check-release.outputs.latest-version }}.tar.gz"
ls -la release-assets/
- name: Generate SHA256 checksums - name: Generate SHA256 checksums
run: | run: |
cd release-assets cd release-assets
@@ -304,36 +312,40 @@ jobs:
path: vt-results path: vt-results
- name: Create Release - name: Create Release
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v2
with: with:
tag_name: fio-${{ needs.check-release.outputs.latest-version }} tag_name: ${{ needs.check-release.outputs.latest-version }}
name: fio ${{ needs.check-release.outputs.latest-version }} Static Binaries name: ${{ needs.check-release.outputs.latest-version }} Static Binaries
body: | body: |
Static binaries for fio ${{ needs.check-release.outputs.latest-version }} Static binaries for ${{ needs.check-release.outputs.latest-version }}
Built using musl toolchains for maximum compatibility. Built using musl toolchains for maximum compatibility.
**Architectures:** **Architectures:**
- `fio_x64` - x86_64 (64-bit) - `fio_x64` - x86_64 (64-bit)
- `fio_x86` - i686 (32-bit) - `fio_x86` - i686 (32-bit)
- `fio_aarch64` - ARM 64-bit - `fio_aarch64` - ARM 64-bit
- `fio_arm` - ARM 32-bit - `fio_arm` - ARM 32-bit
**Security Verification:** **Security Verification:**
All binaries have been scanned by VirusTotal and verified clean. All binaries have been scanned by VirusTotal and verified clean.
${{ needs.virustotal-scan.outputs.scan-results }} ${{ needs.virustotal-scan.outputs.scan-results }}
**Checksum Verification:** **Checksum Verification:**
```bash ```bash
# Verify checksums # Verify checksums
sha256sum -c fio-checksums.sha256 sha256sum -c fio-checksums.sha256
``` ```
For usage in YABS script, place these binaries in the `bin/fio/` directory. **License & Source:**
fio is licensed under [GPL-2.0](https://github.com/axboe/fio/blob/master/COPYING) (© Jens Axboe).
These are unofficial static builds produced by CI for use by [YABS](https://github.com/masonr/yet-another-bench-script);
the exact upstream source is attached as `${{ needs.check-release.outputs.latest-version }}.tar.gz`.
files: | files: |
release-assets/fio_* release-assets/fio_*
release-assets/fio-checksums.sha256 release-assets/fio-checksums.sha256
release-assets/*.tar.gz
draft: false draft: false
prerelease: false prerelease: false
env: env:
@@ -342,13 +354,13 @@ jobs:
notify-failure: notify-failure:
needs: [check-release, build, virustotal-scan] needs: [check-release, build, virustotal-scan]
if: always() && needs.check-release.outputs.should-build == 'true' && (failure() || needs.virustotal-scan.outputs.all-clean == 'false') if: always() && needs.check-release.outputs.should-build == 'true' && (failure() || needs.virustotal-scan.outputs.all-clean == 'false')
runs-on: self-hosted runs-on: ubuntu-latest
steps: steps:
- name: Send failure notification - name: Send failure notification
run: | run: |
echo "## ⚠️ fio Build Failed" >> $GITHUB_STEP_SUMMARY echo "## ⚠️ fio Build Failed" >> $GITHUB_STEP_SUMMARY
echo "Version: ${{ needs.check-release.outputs.latest-version }}" >> $GITHUB_STEP_SUMMARY echo "Version: ${{ needs.check-release.outputs.latest-version }}" >> $GITHUB_STEP_SUMMARY
if [ "${{ needs.virustotal-scan.outputs.all-clean }}" == "false" ]; then if [ "${{ needs.virustotal-scan.outputs.all-clean }}" == "false" ]; then
echo "**Reason:** VirusTotal scan detected issues with one or more binaries" >> $GITHUB_STEP_SUMMARY echo "**Reason:** VirusTotal scan detected issues with one or more binaries" >> $GITHUB_STEP_SUMMARY
echo "**Scan Results:**" >> $GITHUB_STEP_SUMMARY echo "**Scan Results:**" >> $GITHUB_STEP_SUMMARY
@@ -356,5 +368,5 @@ jobs:
else else
echo "**Reason:** Build compilation failed" >> $GITHUB_STEP_SUMMARY echo "**Reason:** Build compilation failed" >> $GITHUB_STEP_SUMMARY
fi fi
echo "Check the workflow logs for details: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> $GITHUB_STEP_SUMMARY echo "Check the workflow logs for details: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> $GITHUB_STEP_SUMMARY

View File

@@ -2,6 +2,12 @@ name: Build iperf3 Static Binaries
on: on:
workflow_dispatch: workflow_dispatch:
schedule:
# check upstream for a new iperf3 release once a day
- cron: '47 5 * * *'
permissions:
contents: write
jobs: jobs:
check-release: check-release:
@@ -10,22 +16,23 @@ jobs:
latest-version: ${{ steps.get-version.outputs.version }} latest-version: ${{ steps.get-version.outputs.version }}
should-build: ${{ steps.check-version.outputs.should-build }} should-build: ${{ steps.check-version.outputs.should-build }}
steps: steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Get latest iperf3 release - name: Get latest iperf3 release
id: get-version id: get-version
run: | run: |
# Get the latest release tag from GitHub API # Get the latest release tag from GitHub API (e.g. "3.19")
LATEST_VERSION=$(curl -s https://api.github.com/repos/esnet/iperf/releases/latest | jq -r '.tag_name') LATEST_VERSION=$(curl -4 --retry 5 --retry-delay 2 --connect-timeout 15 -s https://api.github.com/repos/esnet/iperf/releases/latest | jq -r '.tag_name')
echo "Latest iperf3 version: $LATEST_VERSION" echo "Latest iperf3 version: $LATEST_VERSION"
if [ -z "$LATEST_VERSION" ] || [ "$LATEST_VERSION" = "null" ]; then
echo "Failed to determine latest iperf3 version"
exit 1
fi
echo "version=$LATEST_VERSION" >> $GITHUB_OUTPUT echo "version=$LATEST_VERSION" >> $GITHUB_OUTPUT
- name: Check if version exists in releases - name: Check if version exists in releases
id: check-version id: check-version
run: | run: |
VERSION="${{ steps.get-version.outputs.version }}" VERSION="${{ steps.get-version.outputs.version }}"
# Check if this version already exists in our releases # Check if this version already exists in our releases
if gh release view "iperf3-$VERSION" --repo ${{ github.repository }} >/dev/null 2>&1; then if gh release view "iperf3-$VERSION" --repo ${{ github.repository }} >/dev/null 2>&1; then
echo "Version $VERSION already exists in releases" echo "Version $VERSION already exists in releases"
@@ -41,7 +48,11 @@ jobs:
needs: check-release needs: check-release
if: needs.check-release.outputs.should-build == 'true' if: needs.check-release.outputs.should-build == 'true'
runs-on: ubuntu-latest runs-on: ubuntu-latest
# allow the ARM 32-bit leg to fail without failing the workflow (iperf3 arm32
# builds are historically flaky; kept as a safety net for future versions)
continue-on-error: ${{ matrix.arch == 'arm' }}
strategy: strategy:
fail-fast: false
matrix: matrix:
include: include:
- arch: x64 - arch: x64
@@ -53,81 +64,69 @@ jobs:
- arch: aarch64 - arch: aarch64
cross: aarch64-linux-musl cross: aarch64-linux-musl
host: aarch64-linux-gnu host: aarch64-linux-gnu
# Note: ARM 32-bit compilation of iperf3 >3.15 has known issues
# We'll still attempt it but expect potential failures
- arch: arm - arch: arm
cross: arm-linux-musleabihf cross: arm-linux-musleabihf
host: arm-linux-gnueabihf host: arm-linux-gnueabihf
steps: steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Create compilation script - name: Create compilation script
run: | run: |
VERSION="${{ needs.check-release.outputs.latest-version }}"
ARCH="${{ matrix.arch }}"
CROSS="${{ matrix.cross }}"
HOST="${{ matrix.host }}"
# Single script for all architectures using musl cross-compilation # Single script for all architectures using musl cross-compilation
cat > compile-iperf3.sh << EOF cat > compile-iperf3.sh << 'EOF'
#!/bin/bash #!/bin/bash
set -e set -e
# Activate Holy Build Box lib compilation environment # Activate Holy Build Box lib compilation environment
source /hbb/activate source /hbb/activate
set -x set -x
# remove obsolete CentOS repos # remove obsolete CentOS repos
cd /etc/yum.repos.d/ cd /etc/yum.repos.d/
rm -f CentOS-Base.repo CentOS-SCLo-scl-rh.repo CentOS-SCLo-scl.repo CentOS-fasttrack.repo CentOS-x86_64-kernel.repo rm -f CentOS-Base.repo CentOS-SCLo-scl-rh.repo CentOS-SCLo-scl.repo CentOS-fasttrack.repo CentOS-x86_64-kernel.repo
yum install -y yum-plugin-ovl # fix for docker overlay fs yum install -y yum-plugin-ovl # fix for docker overlay fs
yum install -y xz yum install -y xz
# download musl cross compilation toolchain # download musl cross compilation toolchain - mirrored as a release asset on
# this repo since musl.cc blocks GitHub Actions IP ranges (musl.cc fallback
# kept for local runs)
cd ~ cd ~
curl -L "https://musl.cc/\$CROSS-cross.tgz" -o "\$CROSS-cross.tgz" curl -fL -4 --retry 5 --retry-delay 2 --connect-timeout 15 "https://github.com/masonr/yet-another-bench-script/releases/download/toolchains/$CROSS-cross.tgz" -o "$CROSS-cross.tgz" \
tar xf "\$CROSS-cross.tgz" || curl -fL -4 --retry 5 --retry-delay 2 --connect-timeout 15 "https://musl.cc/$CROSS-cross.tgz" -o "$CROSS-cross.tgz"
tar xf "$CROSS-cross.tgz"
# Activate Holy Build Box exe compilation environment # Activate Holy Build Box exe compilation environment
source /hbb_exe/activate source /hbb_exe/activate
# download and compile iperf3 # download and compile iperf3
cd ~ cd ~
curl -L "https://github.com/esnet/iperf/archive/\$VERSION.tar.gz" -o "iperf.tar.gz" curl -L -4 --retry 5 --retry-delay 2 --connect-timeout 15 "https://github.com/esnet/iperf/archive/$VERSION.tar.gz" -o "iperf.tar.gz"
tar xf iperf.tar.gz tar xf iperf.tar.gz
cd iperf-* cd iperf-*
CC=/root/\$CROSS-cross/bin/\$CROSS-gcc ./configure --disable-shared --disable-profiling --build x86_64-pc-linux-gnu --host "\$HOST" --with-openssl=no --enable-static-bin CC=/root/$CROSS-cross/bin/$CROSS-gcc ./configure --disable-shared --disable-profiling --build x86_64-pc-linux-gnu --host "$HOST" --with-openssl=no --enable-static-bin
# remove libatomic.la so libtool links the static libatomic.a rather than
# attempting to link libatomic.so into the static binary (breaks arm32 builds)
rm -f /root/$CROSS-cross/$CROSS/lib/libatomic.la
make make
# verify no external shared library links # verify no external shared library links
libcheck src/iperf3 libcheck src/iperf3
# copy iperf3 binary to mounted dir # copy iperf3 binary to mounted dir
cp src/iperf3 "/io/iperf3_\$ARCH" cp src/iperf3 "/io/iperf3_$ARCH"
EOF EOF
chmod +x compile-iperf3.sh chmod +x compile-iperf3.sh
- name: Compile iperf3 binary - name: Compile iperf3 binary
run: | run: |
ARCH="${{ matrix.arch }}"
CROSS="${{ matrix.cross }}"
HOST="${{ matrix.host }}"
# Use musl cross-compilation for all architectures # Use musl cross-compilation for all architectures
docker run --rm -v $(pwd):/io --env ARCH=$ARCH --env CROSS=$CROSS --env HOST=$HOST --env VERSION="${{ needs.check-release.outputs.latest-version }}" phusion/holy-build-box-64:latest bash /io/compile-iperf3.sh docker run --rm -v $(pwd):/io --env ARCH=${{ matrix.arch }} --env CROSS=${{ matrix.cross }} --env HOST=${{ matrix.host }} --env VERSION="${{ needs.check-release.outputs.latest-version }}" phusion/holy-build-box-64:latest bash /io/compile-iperf3.sh
- name: Verify binary - name: Verify binary
run: | run: |
ARCH="${{ matrix.arch }}" ls -la iperf3_${{ matrix.arch }}
ls -la iperf3_$ARCH file iperf3_${{ matrix.arch }}
file iperf3_$ARCH
- name: Upload binary as artifact - name: Upload binary as artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
@@ -135,8 +134,6 @@ jobs:
name: iperf3_${{ matrix.arch }} name: iperf3_${{ matrix.arch }}
path: iperf3_${{ matrix.arch }} path: iperf3_${{ matrix.arch }}
retention-days: 1 retention-days: 1
# Allow arm builds to fail as ARM 32-bit has known compilation issues with newer versions
continue-on-error: ${{ matrix.arch == 'arm' }}
virustotal-scan: virustotal-scan:
needs: [check-release, build] needs: [check-release, build]
@@ -157,7 +154,7 @@ jobs:
mkdir -p scan-binaries mkdir -p scan-binaries
find artifacts -name "iperf3_*" -type f -exec cp {} scan-binaries/ \; || true find artifacts -name "iperf3_*" -type f -exec cp {} scan-binaries/ \; || true
ls -la scan-binaries/ ls -la scan-binaries/
# Check if we have at least the x64 binary # Check if we have at least the x64 binary
if [ ! -f "scan-binaries/iperf3_x64" ]; then if [ ! -f "scan-binaries/iperf3_x64" ]; then
echo "Error: No iperf3_x64 binary found" echo "Error: No iperf3_x64 binary found"
@@ -170,100 +167,104 @@ jobs:
echo "## VirusTotal Scan Results" > scan_results.md echo "## VirusTotal Scan Results" > scan_results.md
echo "| Binary | Status | Malicious | Suspicious | Undetected | VirusTotal URL |" >> scan_results.md echo "| Binary | Status | Malicious | Suspicious | Undetected | VirusTotal URL |" >> scan_results.md
echo "|--------|--------|-----------|------------|------------|----------------|" >> scan_results.md echo "|--------|--------|-----------|------------|------------|----------------|" >> scan_results.md
ALL_CLEAN=true ALL_CLEAN=true
SCAN_DATA=""
for binary in scan-binaries/iperf3_*; do for binary in scan-binaries/iperf3_*; do
filename=$(basename "$binary") filename=$(basename "$binary")
echo "Uploading $filename to VirusTotal..." echo "Uploading $filename to VirusTotal..."
# Upload to VirusTotal # Upload to VirusTotal
upload_response=$(curl -s --request POST \ upload_response=$(curl -4 --retry 5 --retry-delay 2 --connect-timeout 15 -s --request POST \
--url https://www.virustotal.com/api/v3/files \ --url https://www.virustotal.com/api/v3/files \
--header 'accept: application/json' \ --header 'accept: application/json' \
--header 'content-type: multipart/form-data' \ --header 'content-type: multipart/form-data' \
--header "x-apikey: ${{ secrets.VIRUSTOTAL_API_KEY }}" \ --header "x-apikey: ${{ secrets.VIRUSTOTAL_API_KEY }}" \
--form "file=@$binary") --form "file=@$binary")
analysis_id=$(echo "$upload_response" | jq -r '.data.id') analysis_id=$(echo "$upload_response" | jq -r '.data.id')
echo "Analysis ID for $filename: $analysis_id" echo "Analysis ID for $filename: $analysis_id"
if [ "$analysis_id" = "null" ] || [ -z "$analysis_id" ]; then if [ "$analysis_id" = "null" ] || [ -z "$analysis_id" ]; then
echo "Failed to upload $filename to VirusTotal" echo "Failed to upload $filename to VirusTotal"
echo "| $filename | Upload Failed | N/A | N/A | N/A | N/A |" >> scan_results.md echo "| $filename | Upload Failed | N/A | N/A | N/A | N/A |" >> scan_results.md
ALL_CLEAN=false ALL_CLEAN=false
continue continue
fi fi
# Store analysis ID for later retrieval # Store analysis ID for later retrieval
echo "${filename}:${analysis_id}" >> analysis_ids.txt echo "${filename}:${analysis_id}" >> analysis_ids.txt
done done
echo "all_clean_upload=$ALL_CLEAN" >> $GITHUB_OUTPUT
# Wait 2 minutes for scans to complete
echo "Waiting 2 minutes for VirusTotal scans to complete..."
sleep 120
- name: Retrieve VirusTotal scan results - name: Retrieve VirusTotal scan results
id: get-results id: get-results
run: | run: |
ALL_CLEAN=true ALL_CLEAN=true
SCAN_SUMMARY=""
# Poll each analysis until it completes; VirusTotal scans can take a few
# minutes after upload, so allow up to ~5 minutes per binary (10 polls,
# 30s apart) before giving up. Files are processed sequentially, so by
# the time the first completes the rest are usually already done.
while IFS=':' read -r filename analysis_id; do while IFS=':' read -r filename analysis_id; do
echo "Retrieving results for $filename (ID: $analysis_id)..." echo "Retrieving results for $filename (ID: $analysis_id)..."
# Get scan results status="queued"
result_response=$(curl -s --request GET \ for ((attempts=1; attempts<=10; attempts++)); do
--url "https://www.virustotal.com/api/v3/analyses/$analysis_id" \ # Get scan results
--header 'accept: application/json' \ result_response=$(curl -4 --retry 5 --retry-delay 2 --connect-timeout 15 -s --request GET \
--header "x-apikey: ${{ secrets.VIRUSTOTAL_API_KEY }}") --url "https://www.virustotal.com/api/v3/analyses/$analysis_id" \
--header 'accept: application/json' \
status=$(echo "$result_response" | jq -r '.data.attributes.status // "unknown"') --header "x-apikey: ${{ secrets.VIRUSTOTAL_API_KEY }}")
status=$(echo "$result_response" | jq -r '.data.attributes.status // "unknown"')
[ "$status" = "completed" ] && break
echo "$filename still scanning (attempt $attempts of 10), waiting 30s..."
sleep 30
done
if [ "$status" = "completed" ]; then if [ "$status" = "completed" ]; then
malicious=$(echo "$result_response" | jq -r '.data.attributes.stats.malicious // 0') malicious=$(echo "$result_response" | jq -r '.data.attributes.stats.malicious // 0')
suspicious=$(echo "$result_response" | jq -r '.data.attributes.stats.suspicious // 0') suspicious=$(echo "$result_response" | jq -r '.data.attributes.stats.suspicious // 0')
undetected=$(echo "$result_response" | jq -r '.data.attributes.stats.undetected // 0') undetected=$(echo "$result_response" | jq -r '.data.attributes.stats.undetected // 0')
# Get file hash from the item link # Get file hash from the item link
item_link=$(echo "$result_response" | jq -r '.data.links.item // ""') item_link=$(echo "$result_response" | jq -r '.data.links.item // ""')
file_hash=$(echo "$item_link" | sed 's/.*files\///') file_hash=$(echo "$item_link" | sed 's/.*files\///')
vt_url="https://www.virustotal.com/gui/file/$file_hash" vt_url="https://www.virustotal.com/gui/file/$file_hash"
if [ "$malicious" -gt 0 ] || [ "$suspicious" -gt 0 ]; then if [ "$malicious" -gt 0 ] || [ "$suspicious" -gt 0 ]; then
status_text="⚠️ FLAGGED" status_text="⚠️ FLAGGED"
ALL_CLEAN=false ALL_CLEAN=false
else else
status_text="✅ Clean" status_text="✅ Clean"
fi fi
echo "| $filename | $status_text | $malicious | $suspicious | $undetected | [$file_hash]($vt_url) |" >> scan_results.md echo "| $filename | $status_text | $malicious | $suspicious | $undetected | [$file_hash]($vt_url) |" >> scan_results.md
else else
echo "| $filename | ⏳ Pending | N/A | N/A | N/A | Scan not completed |" >> scan_results.md echo "| $filename | ⏳ Timed out | N/A | N/A | N/A | Scan did not complete in ~5 min |" >> scan_results.md
ALL_CLEAN=false ALL_CLEAN=false
fi fi
done < analysis_ids.txt done < analysis_ids.txt
echo "all_clean=$ALL_CLEAN" >> $GITHUB_OUTPUT echo "all_clean=$ALL_CLEAN" >> $GITHUB_OUTPUT
# Add summary to GitHub step summary # Add summary to GitHub step summary
cat scan_results.md >> $GITHUB_STEP_SUMMARY cat scan_results.md >> $GITHUB_STEP_SUMMARY
- name: Create scan summary - name: Create scan summary
id: scan-summary id: scan-summary
run: | run: |
RESULTS=$(cat scan_results.md)
ALL_CLEAN="${{ steps.get-results.outputs.all_clean }}" ALL_CLEAN="${{ steps.get-results.outputs.all_clean }}"
# Escape newlines for GitHub output # Pass the scan results through as a multi-line output (heredoc delimiter
RESULTS_ESCAPED=$(echo "$RESULTS" | sed ':a;N;$!ba;s/\n/\\n/g') # syntax) so the markdown table renders correctly in the release body
{
echo "results=$RESULTS_ESCAPED" >> $GITHUB_OUTPUT echo "results<<RESULTS_EOF"
cat scan_results.md
echo "RESULTS_EOF"
} >> $GITHUB_OUTPUT
echo "all-clean=$ALL_CLEAN" >> $GITHUB_OUTPUT echo "all-clean=$ALL_CLEAN" >> $GITHUB_OUTPUT
- name: Upload scan results as artifact - name: Upload scan results as artifact
@@ -280,9 +281,6 @@ jobs:
if: needs.check-release.outputs.should-build == 'true' && needs.virustotal-scan.outputs.all-clean == 'true' if: needs.check-release.outputs.should-build == 'true' && needs.virustotal-scan.outputs.all-clean == 'true'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download all artifacts - name: Download all artifacts
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
@@ -296,13 +294,20 @@ jobs:
# Move all binaries to release-assets directory # Move all binaries to release-assets directory
find artifacts -name "iperf3_*" -type f -exec cp {} release-assets/ \; || true find artifacts -name "iperf3_*" -type f -exec cp {} release-assets/ \; || true
ls -la release-assets/ ls -la release-assets/
# Check if we have at least the x64 binary # Check if we have at least the x64 binary
if [ ! -f "release-assets/iperf3_x64" ]; then if [ ! -f "release-assets/iperf3_x64" ]; then
echo "Error: No iperf3_x64 binary found" echo "Error: No iperf3_x64 binary found"
exit 1 exit 1
fi fi
- name: Download upstream source tarball
run: |
# Attach the exact upstream source these binaries were built from
# (iperf3 is BSD-3-Clause; retain the copyright notice with distribution)
curl -L --retry 5 --retry-delay 2 --connect-timeout 15 "https://github.com/esnet/iperf/archive/${{ needs.check-release.outputs.latest-version }}.tar.gz" -o "release-assets/iperf-${{ needs.check-release.outputs.latest-version }}.tar.gz"
ls -la release-assets/
- name: Generate SHA256 checksums - name: Generate SHA256 checksums
run: | run: |
cd release-assets cd release-assets
@@ -330,38 +335,42 @@ jobs:
path: vt-results path: vt-results
- name: Create Release - name: Create Release
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v2
with: with:
tag_name: iperf3-${{ needs.check-release.outputs.latest-version }} tag_name: iperf3-${{ needs.check-release.outputs.latest-version }}
name: iperf3 ${{ needs.check-release.outputs.latest-version }} Static Binaries name: iperf3 ${{ needs.check-release.outputs.latest-version }} Static Binaries
body: | body: |
Static binaries for iperf3 ${{ needs.check-release.outputs.latest-version }} Static binaries for iperf3 ${{ needs.check-release.outputs.latest-version }}
Built using musl toolchains for maximum compatibility. Built using musl toolchains for maximum compatibility.
**Architectures:** **Architectures:**
- `iperf3_x64` - x86_64 (64-bit) - `iperf3_x64` - x86_64 (64-bit)
- `iperf3_x86` - i686 (32-bit) - `iperf3_x86` - i686 (32-bit)
- `iperf3_aarch64` - ARM 64-bit - `iperf3_aarch64` - ARM 64-bit
- `iperf3_arm` - ARM 32-bit (if available) - `iperf3_arm` - ARM 32-bit (if available)
${{ steps.check-arm.outputs.arm-note }} ${{ steps.check-arm.outputs.arm-note }}
**Security Verification:** **Security Verification:**
All binaries have been scanned by VirusTotal and verified clean. All binaries have been scanned by VirusTotal and verified clean.
${{ needs.virustotal-scan.outputs.scan-results }} ${{ needs.virustotal-scan.outputs.scan-results }}
**Checksum Verification:** **Checksum Verification:**
```bash ```bash
# Verify checksums # Verify checksums
sha256sum -c iperf3-checksums.sha256 sha256sum -c iperf3-checksums.sha256
``` ```
For usage in YABS script, place these binaries in the `bin/iperf/` directory. **License & Source:**
iperf3 is licensed under [BSD-3-Clause](https://github.com/esnet/iperf/blob/master/LICENSE) (© ESnet / LBL).
These are unofficial static builds produced by CI for use by [YABS](https://github.com/masonr/yet-another-bench-script);
the exact upstream source is attached as `iperf-${{ needs.check-release.outputs.latest-version }}.tar.gz`.
files: | files: |
release-assets/iperf3_* release-assets/iperf3_*
release-assets/iperf3-checksums.sha256 release-assets/iperf3-checksums.sha256
release-assets/*.tar.gz
draft: false draft: false
prerelease: false prerelease: false
env: env:
@@ -376,7 +385,7 @@ jobs:
run: | run: |
echo "## ⚠️ iperf3 Build Failed" >> $GITHUB_STEP_SUMMARY echo "## ⚠️ iperf3 Build Failed" >> $GITHUB_STEP_SUMMARY
echo "Version: ${{ needs.check-release.outputs.latest-version }}" >> $GITHUB_STEP_SUMMARY echo "Version: ${{ needs.check-release.outputs.latest-version }}" >> $GITHUB_STEP_SUMMARY
if [ "${{ needs.virustotal-scan.outputs.all-clean }}" == "false" ]; then if [ "${{ needs.virustotal-scan.outputs.all-clean }}" == "false" ]; then
echo "**Reason:** VirusTotal scan detected issues with one or more binaries" >> $GITHUB_STEP_SUMMARY echo "**Reason:** VirusTotal scan detected issues with one or more binaries" >> $GITHUB_STEP_SUMMARY
echo "**Scan Results:**" >> $GITHUB_STEP_SUMMARY echo "**Scan Results:**" >> $GITHUB_STEP_SUMMARY
@@ -384,5 +393,5 @@ jobs:
else else
echo "**Reason:** Build compilation failed" >> $GITHUB_STEP_SUMMARY echo "**Reason:** Build compilation failed" >> $GITHUB_STEP_SUMMARY
fi fi
echo "Check the workflow logs for details: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> $GITHUB_STEP_SUMMARY echo "Check the workflow logs for details: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> $GITHUB_STEP_SUMMARY

View File

@@ -1,74 +0,0 @@
name: Monitor External Releases for Updates
on:
schedule:
# Check every hour for new releases
- cron: '0 * * * *'
workflow_dispatch:
jobs:
monitor-releases:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Check fio releases
id: check-fio
run: |
# Get latest fio release
LATEST_FIO=$(curl -s https://api.github.com/repos/axboe/fio/releases/latest | jq -r '.tag_name')
echo "Latest fio: $LATEST_FIO"
# Check if we already have this version
if ! gh release view "fio-$LATEST_FIO" --repo ${{ github.repository }} >/dev/null 2>&1; then
echo "New fio version found: $LATEST_FIO"
echo "trigger-fio=true" >> $GITHUB_OUTPUT
echo "fio-version=$LATEST_FIO" >> $GITHUB_OUTPUT
else
echo "fio $LATEST_FIO already exists"
echo "trigger-fio=false" >> $GITHUB_OUTPUT
fi
env:
GH_TOKEN: ${{ github.token }}
- name: Check iperf3 releases
id: check-iperf3
run: |
# Get latest iperf3 release
LATEST_IPERF3=$(curl -s https://api.github.com/repos/esnet/iperf/releases/latest | jq -r '.tag_name')
echo "Latest iperf3: $LATEST_IPERF3"
# Check if we already have this version
if ! gh release view "iperf3-$LATEST_IPERF3" --repo ${{ github.repository }} >/dev/null 2>&1; then
echo "New iperf3 version found: $LATEST_IPERF3"
echo "trigger-iperf3=true" >> $GITHUB_OUTPUT
echo "iperf3-version=$LATEST_IPERF3" >> $GITHUB_OUTPUT
else
echo "iperf3 $LATEST_IPERF3 already exists"
echo "trigger-iperf3=false" >> $GITHUB_OUTPUT
fi
env:
GH_TOKEN: ${{ github.token }}
- name: Trigger fio build workflow
if: steps.check-fio.outputs.trigger-fio == 'true'
run: |
echo "Triggering fio build for version ${{ steps.check-fio.outputs.fio-version }}"
gh workflow run build-fio.yml --repo ${{ github.repository }}
env:
GH_TOKEN: ${{ github.token }}
- name: Trigger iperf3 build workflow
if: steps.check-iperf3.outputs.trigger-iperf3 == 'true'
run: |
echo "Triggering iperf3 build for version ${{ steps.check-iperf3.outputs.iperf3-version }}"
gh workflow run build-iperf3.yml --repo ${{ github.repository }}
env:
GH_TOKEN: ${{ github.token }}
- name: Summary
run: |
echo "## Release Monitoring Summary" >> $GITHUB_STEP_SUMMARY
echo "- fio: ${{ steps.check-fio.outputs.trigger-fio == 'true' && 'New version triggered build' || 'No new version' }}" >> $GITHUB_STEP_SUMMARY
echo "- iperf3: ${{ steps.check-iperf3.outputs.trigger-iperf3 == 'true' && 'New version triggered build' || 'No new version' }}" >> $GITHUB_STEP_SUMMARY

View File

@@ -7,15 +7,17 @@ Logo design by [Dian Pratama](https://github.com/dianp)
This script automates the execution of the best benchmarking tools in the industry. Included are several tests to check the performance of critical areas of a server: disk performance with [fio](https://github.com/axboe/fio), network performance with [iperf3](https://github.com/esnet/iperf), and CPU/memory performance with [Geekbench](https://www.geekbench.com/). The script is designed to not require any external dependencies to be installed nor elevated privileges to run. If there are any features that you would like to see added, feel free to submit an issue describing your feature request or fork the project and submit a PR! This script automates the execution of the best benchmarking tools in the industry. Included are several tests to check the performance of critical areas of a server: disk performance with [fio](https://github.com/axboe/fio), network performance with [iperf3](https://github.com/esnet/iperf), and CPU/memory performance with [Geekbench](https://www.geekbench.com/). The script is designed to not require any external dependencies to be installed nor elevated privileges to run. If there are any features that you would like to see added, feel free to submit an issue describing your feature request or fork the project and submit a PR!
View Daily and Historical 📊 **[YABS Usage Stats Here](https://stats.yabs.sh/)** 📈 ([source](https://github.com/masonr/yabs-stats)).
### **What's New With YABS?** ### **What's New With YABS?**
* [27 Feb 2023](https://github.com/masonr/yet-another-bench-script/commit/06eaa2ab3b32355bec8278c51c4be93b3662a96d) - Newly released [Geekbench 6](https://www.geekbench.com/) is added as the default Geekbench test. * [19 Sep 2026](https://github.com/masonr/yet-another-bench-script/actions) - fio/iperf3 portable binary builds now automated via GitHub workflows.
* [26 Feb 2023](https://github.com/masonr/yet-another-bench-script/commit/f075baf59c3057983fff0a30ea0c746b5ea88d91) - Network information added to YABS output using [ip-api](https://ip-api.com/). * [24 Jul 2026](https://github.com/masonr/yet-another-bench-script) - [Geekbench 7](https://www.geekbench.com/) is now available via the `-7` flag (Geekbench 6 remains the default).
* [15 Aug 2022](https://github.com/masonr/yet-another-bench-script/commit/ae24e70fbf7a4848e81a70cf829ec44e060e63d5) - Added JSON output/upload support to export or auto-upload of YABS results for sharing. * [04 Jul 2026](https://stats.yabs.sh/) - Check out YABS usage stats here -> https://stats.yabs.sh/
## How to Run ## How to Run
``` ```
curl -sL https://yabs.sh | bash curl -sL yabs.sh | bash
``` ```
or or
@@ -32,10 +34,10 @@ wget -qO- yabs.sh | bash
**Windows Users**: This script can be run on Windows systems by using [Windows Subsystem for Linux v2 (WSL 2)](https://learn.microsoft.com/en-us/windows/wsl/about). WSLv1 will not run the script and binaries correctly. **Windows Users**: This script can be run on Windows systems by using [Windows Subsystem for Linux v2 (WSL 2)](https://learn.microsoft.com/en-us/windows/wsl/about). WSLv1 will not run the script and binaries correctly.
### Flags (Skipping Tests, Reducing iperf Locations, Geekbench 4/5/6, etc.) ### Flags (Skipping Tests, Reducing iperf Locations, Geekbench 4/5/6/7, etc.)
``` ```
curl -sL https://yabs.sh | bash -s -- -flags curl -sL yabs.sh | bash -s -- -flags
``` ```
| Flag | Description | | Flag | Description |
@@ -49,8 +51,9 @@ curl -sL https://yabs.sh | bash -s -- -flags
| -r | Reduces the number of iperf locations (Scaleway/Clouvider LON+NYC) to lessen bandwidth usage | | -r | Reduces the number of iperf locations (Scaleway/Clouvider LON+NYC) to lessen bandwidth usage |
| -4 | Runs a Geekbench 4 test and disables the Geekbench 6 test | | -4 | Runs a Geekbench 4 test and disables the Geekbench 6 test |
| -5 | Runs a Geekbench 5 test and disables the Geekbench 6 test | | -5 | Runs a Geekbench 5 test and disables the Geekbench 6 test |
| -7 | Runs a Geekbench 7 test and disables the Geekbench 6 test |
| -9 | Runs both the Geekbench 4 and 5 tests instead of the Geekbench 6 test | | -9 | Runs both the Geekbench 4 and 5 tests instead of the Geekbench 6 test |
| -6 | Re-enables the Geekbench 6 test if any of the following were used: -4, -5, or -9 (-6 flag must be last to not be overridden) | | -6 | Re-enables the Geekbench 6 test if any of the following were used: -4, -5, -7, or -9 (-6 flag must be last to not be overridden) |
| -j | Prints a JSON representation of the results to the screen | | -j | Prints a JSON representation of the results to the screen |
| -w \<filename\> | Writes the JSON results to a file using the file name provided | | -w \<filename\> | Writes the JSON results to a file using the file name provided |
| -s \<url\> | Sends a JSON representation of the results to the designated URL(s) (see section below) | | -s \<url\> | Sends a JSON representation of the results to the designated URL(s) (see section below) |
@@ -73,8 +76,11 @@ Sites supporting submission of YABS JSON results:
| Website | Example Command | | Website | Example Command |
| --- | --- | | --- | --- |
| [YABSdb](https://yabsdb.com/) | `curl -sL https://yabs.sh \| bash -s -- -s "https://yabsdb.com/add"` | | [YABSdb](https://yabsdb.com/) | `curl -sL yabs.sh \| bash -s -- -s "https://yabsdb.com/add"` |
| [VPSBenchmarks](https://www.vpsbenchmarks.com/yabs/get_started) | `curl -sL https://yabs.sh \| bash -s -- -s https://www.vpsbenchmarks.com/yabs/upload` | | [VPSBenchmarks](https://www.vpsbenchmarks.com/yabs/get_started) | `curl -sL yabs.sh \| bash -s -- -s https://www.vpsbenchmarks.com/yabs/upload` |
| [serverlist.dev](https://serverlist.dev/) | `curl -sL yabs.sh \| bash -s -- -s "https://serverlist.dev/api/v1/yabs/submit"` |
| [ServerVerify](https://serververify.com/benchmarks) | (sign up for account) |
| [VPS Host Review](https://vpshostreview.com/yabs) | `curl -sL yabs.sh \| bash -s -- -s "https://vpshostreview.com/yabs"` |
Example JSON output: [example.json](bin/example.json). Example JSON output: [example.json](bin/example.json).
@@ -82,11 +88,11 @@ Example JSON output: [example.json](bin/example.json).
* **[fio](https://github.com/axboe/fio)** - the most comprehensive I/O testing software available, fio grants the ability to evaluate disk performance in a variety of methods with a variety of options. Four random read and write fio disk tests are conducted as part of this script with 4k, 64k, 512k, and 1m block sizes. The tests are designed to evaluate disk throughput in near-real world (using random) scenarios with a 50/50 split (50% reads and 50% writes per test). * **[fio](https://github.com/axboe/fio)** - the most comprehensive I/O testing software available, fio grants the ability to evaluate disk performance in a variety of methods with a variety of options. Four random read and write fio disk tests are conducted as part of this script with 4k, 64k, 512k, and 1m block sizes. The tests are designed to evaluate disk throughput in near-real world (using random) scenarios with a 50/50 split (50% reads and 50% writes per test).
* **[iperf3](https://github.com/esnet/iperf)** - the industry standard for testing download and upload speeds to various locations. This script utilizes iperf3 with 8 parallel threads and tests both download and upload speeds. If an iperf server is busy after 5 tries, the speed test for that location/direction is skipped. * **[iperf3](https://github.com/esnet/iperf)** - the industry standard for testing download and upload speeds to various locations. This script utilizes iperf3 with 8 parallel threads and tests both download and upload speeds. If an iperf server is busy after 5 tries, the speed test for that location/direction is skipped.
* **[Geekbench](https://www.geekbench.com/)** - Geekbench is a benchmarking program that measures system performance, which is widely used in the tech community. The web URL is displayed to be able to see complete test and individual benchmark results and allow comparison to other geekbench'd systems. The claim URL to add the Geekbench result to your Geekbench profile is written to a file in the directory that this script is executed from. By default, Geekbench 6 is the only Geekbench test performed, however, Geekbench 4 and/or 5 can also be toggled on by passing the appropriate flag. * **[Geekbench](https://www.geekbench.com/)** - Geekbench is a benchmarking program that measures system performance, which is widely used in the tech community. The web URL is displayed to be able to see complete test and individual benchmark results and allow comparison to other geekbench'd systems. The claim URL to add the Geekbench result to your Geekbench profile is written to a file in the directory that this script is executed from. By default, Geekbench 6 is the only Geekbench test performed, however, Geekbench 4, 5, and/or 7 can also be toggled on by passing the appropriate flag.
### Security Notice ### Security Notice
This script relies on external binaries in order to complete the performance tests. The network (iperf3) and disk (fio) tests use binaries that are compiled by myself utilizing a [Holy Build Box](https://github.com/phusion/holy-build-box) compilation environment to ensure binary portability. The reasons for doing this include ensuring standardized (parsable) output, allowing support of both 32-bit and 64-bit architectures, bypassing the need for prerequisites to be compiled and/or installed, among other reasons. For the system test, a Geekbench tarball is downloaded, extracted, and the resulting binary is run. Use this script at your own risk as you would with any script publicly available on the net. Additional information regarding the binaries, including compilation notes and steps, can be found in the bin directory's [README page](bin/README.md). This script relies on external binaries in order to complete the performance tests. The network (iperf3) and disk (fio) tests use binaries that are built by GitHub Actions workflows in a [Holy Build Box](https://github.com/phusion/holy-build-box) compilation environment to ensure binary portability, and are published as release assets on this repository (scanned via VirusTotal with SHA-256 checksums included). The reasons for using pre-compiled binaries include ensuring standardized (parsable) output, allowing support of both 32-bit and 64-bit architectures, bypassing the need for prerequisites to be compiled and/or installed, among other reasons. For the system test, a Geekbench tarball is downloaded, extracted, and the resulting binary is run. Use this script at your own risk as you would with any script publicly available on the net. Additional information regarding the binaries, including compilation notes and steps, can be found in the bin directory's [README page](bin/README.md).
## Example Output ## Example Output

View File

@@ -1,28 +1,49 @@
## YABS Pre-Compiled Binaries ## YABS Pre-Compiled Binaries
This directory contains all of the binaries required to run the benchmarking tests. Naturally, there is a security risk to your machine and its contents by running this script since, after all, this is just a script on the internet. You'll simply have to have confidence that I don't have malicious intent and am semi-competent at writing a bash script. The script is made public so you can look at the code yourself. The binaries were compiled using a [Holy Build Box](https://github.com/phusion/holy-build-box) compilation environment in order to ensure the most portability. The compiled binary version numbers and compilations steps are noted below. Please open an issue if the compiled version is out of date and lacking any security-related and/or performance updates. This directory contains the compilation scripts used to build the fio and iperf3
binaries that YABS uses. **The binaries themselves are no longer committed to the
repository** - they are built automatically by GitHub Actions workflows
([build-fio.yml](../.github/workflows/build-fio.yml) and
[build-iperf3.yml](../.github/workflows/build-iperf3.yml)) on GitHub-hosted
runners and published as release assets on this repository:
### Binaries * `fio-*` releases (e.g. `fio-3.42`) - contain `fio_x64`, `fio_x86`, `fio_aarch64`, `fio_arm`
* `iperf3-*` releases (e.g. `iperf3-3.21`) - contain `iperf3_x64`, `iperf3_x86`, `iperf3_aarch64`, `iperf3_arm`
* `toolchains` release - musl cross-compilation toolchains mirrored from
[musl.cc](https://musl.cc/) (which blocks GitHub Actions IP ranges); see the
NOTICE.txt asset for licensing/source info
| Binary Name | Version | Compile Date | Architecture | OS | SHA-256 Hash<br>(VirusTotal Scan) | Each binary release includes SHA-256 checksums (`*-checksums.sha256`), a
|:-:|:-:|:-:|:-:|:-:|:-:| VirusTotal scan summary in the release notes, and the exact upstream source
| fio_x64 | 3.39 | 20-APR-2025 | x86_64 | 64-bit | [b511bda](https://www.virustotal.com/gui/file/b511bda3b26b6d840698f543d63e956d7466b8512c10ff0ada8292d556c33fb1) | tarball the binaries were built from. Binaries are cross-compiled with musl
| fio_x86 | 3.39 | 20-APR-2025 | i686 | 32-bit | [42e2e0b](https://www.virustotal.com/gui/file/42e2e0b0370faeb8e53dcf48dfff15daa9baaadfd196d9bdda57af196bedf0b3) | toolchains for maximum portability.
| fio_aarch64 | 3.39 | 20-APR-2025 | ARM (aarch64) | 64-bit | [e2942a2](https://www.virustotal.com/gui/file/e2942a26d4b249076486677c9c12cd7f1a572854a5e136597d1391e8ad75ffb0) |
| fio_arm | 3.39 | 20-APR-2025 | ARM | 32-bit | [3a96b1c](https://www.virustotal.com/gui/file/3a96b1cadfb51501b7fd54dc47a4dad666dc4382d4fe152116c62ae6a07485ea) |
| iperf3_x64 | 3.18 | 14-DEC-2024 | x86_64 | 64-bit | [ef787ab](https://www.virustotal.com/gui/file/ef787abbe4b09c7958ed592df52dfe3a2848cbdee5b76738c757d7c51c348053) |
| iperf3_x86 | 3.18 | 14-DEC-2024 | i686 | 32-bit | [655eb51](https://www.virustotal.com/gui/file/655eb51abc36ddaa624c1d0e98c6930e8b1e9d91c85e5a3443624355656be9b9) |
| iperf3_aarch64 | 3.18 | 14-DEC-2024 | ARM (aarch64) | 64-bit | [92e5821](https://www.virustotal.com/gui/file/92e5821cfbaa1f8faf123b4d6773dc0f6efef221b9308668a21ddabc04a1de20) |
| iperf3_arm | 3.15* | 20-OCT-2023 | ARM | 32-bit | [310e80f](https://www.virustotal.com/gui/file/310e80f442dda47fa0fe41225af85e8b91e75116dce5187f123380fd3c3c85a8) |
Note: ARM compatibility is considered experimental. Static binaries for 32-bit and ARM-based machines are cross-compiled within a Holy Build Box container using the [musl toolchain](https://musl.cc/). At runtime, yabs.sh auto-detects the latest `fio-*`/`iperf3-*` release via the
repository's releases feed and downloads the appropriate binary for the host
architecture. If the lookup fails, it falls back to a pinned release tag.
### Compile Notes Naturally, there is a security risk to your machine and its contents by running
this script since, after all, this is just a script on the internet. You'll
simply have to have confidence that I don't have malicious intent and am
semi-competent at writing a bash script. The script and the workflows that build
the binaries are public so you can look at the code yourself. The binaries are
compiled using a [Holy Build Box](https://github.com/phusion/holy-build-box)
compilation environment in order to ensure the most portability. Please open an
issue if the binaries are out of date and lacking any security-related and/or
performance updates - the daily scheduled workflows should pick up new upstream
releases automatically.
Note: ARM compatibility is considered experimental.
### Compile Notes (manual builds)
The workflows above are the canonical build path. To build manually, the same
scripts can be run inside a Holy Build Box container:
**Pre-reqs**: **Pre-reqs**:
* Docker - https://www.docker.com/ * Docker - https://www.docker.com/
**Compiling 64-bit binaries**: **Compiling 64-bit (x86_64) binaries**:
```sh ```sh
docker run -t -i --rm -v `pwd`:/io phusion/holy-build-box-64:latest bash /io/compile.sh docker run -t -i --rm -v `pwd`:/io phusion/holy-build-box-64:latest bash /io/compile.sh
@@ -32,9 +53,11 @@ docker run -t -i --rm -v `pwd`:/io phusion/holy-build-box-64:latest bash /io/com
### Cross-compiling Notes ### Cross-compiling Notes
Compilation of ARM-compatible binaries requires additional environment variables to identify the proper musl toolchain and architecture to target for cross-compilation. Compilation of 32-bit and ARM-compatible binaries requires additional
environment variables to identify the proper musl toolchain and architecture to
target for cross-compilation.
**Compiling 32-bit binaries**: **Compiling 32-bit x86 binaries**:
```sh ```sh
docker run -t -i --rm -v `pwd`:/io --env ARCH=x86 --env CROSS=i686-linux-musl --env HOST=i686-linux-musl phusion/holy-build-box-64:latest bash /io/cross-compile.sh docker run -t -i --rm -v `pwd`:/io --env ARCH=x86 --env CROSS=i686-linux-musl --env HOST=i686-linux-musl phusion/holy-build-box-64:latest bash /io/cross-compile.sh
@@ -46,12 +69,8 @@ docker run -t -i --rm -v `pwd`:/io --env ARCH=x86 --env CROSS=i686-linux-musl --
docker run -t -i --rm -v `pwd`:/io --env ARCH=aarch64 --env CROSS=aarch64-linux-musl --env HOST=aarch64-linux-gnu phusion/holy-build-box-64:latest bash /io/cross-compile.sh docker run -t -i --rm -v `pwd`:/io --env ARCH=aarch64 --env CROSS=aarch64-linux-musl --env HOST=aarch64-linux-gnu phusion/holy-build-box-64:latest bash /io/cross-compile.sh
``` ```
**Compiling ARM 32-bit binaries\***: **Compiling ARM 32-bit binaries**:
```sh ```sh
docker run -t -i --rm -v `pwd`:/io --env ARCH=arm --env CROSS=arm-linux-musleabihf --env HOST=arm-linux-gnueabihf phusion/holy-build-box-64:latest bash /io/cross-compile.sh docker run -t -i --rm -v `pwd`:/io --env ARCH=arm --env CROSS=arm-linux-musleabihf --env HOST=arm-linux-gnueabihf phusion/holy-build-box-64:latest bash /io/cross-compile.sh
``` ```
64-bit (aarch64) and 32-bit (x86, arm) binaries will be placed in the current directory.
\* ARM 32-bit: Last sucessful compiliation of ARM 32-bit binary for iperf3 is v3.15. All later versions fail to compile.

View File

@@ -36,9 +36,12 @@ source /hbb_exe/activate
# download and compile fio # download and compile fio
cd ~ cd ~
curl -L https://github.com/axboe/fio/archive/fio-3.39.tar.gz -o "fio.tar.gz" curl -L https://github.com/axboe/fio/archive/fio-3.42.tar.gz -o "fio.tar.gz"
tar xf fio.tar.gz tar xf fio.tar.gz
cd fio-fio* cd fio-fio-*
# fio >= 3.42 includes both linux/prctl.h and sys/prctl.h in backend.c, which
# conflicts under musl; sys/prctl.h alone is sufficient (harmless on glibc too)
sed -i '/#include <linux\/prctl.h>/d' backend.c
./configure --disable-native ./configure --disable-native
make make
@@ -49,9 +52,9 @@ cp fio "/io/fio_$ARCH"
# download and compile iperf # download and compile iperf
cd ~ cd ~
curl -L https://github.com/esnet/iperf/archive/3.18.tar.gz -o "iperf.tar.gz" curl -L https://github.com/esnet/iperf/archive/3.21.tar.gz -o "iperf.tar.gz"
tar xf iperf.tar.gz tar xf iperf.tar.gz
cd iperf* cd iperf-*
./configure --disable-shared --disable-profiling ./configure --disable-shared --disable-profiling
make make

View File

@@ -8,14 +8,16 @@ set -x
# remove obsolete CentOS repos # remove obsolete CentOS repos
cd /etc/yum.repos.d/ cd /etc/yum.repos.d/
rm CentOS-Base.repo CentOS-SCLo-scl-rh.repo CentOS-SCLo-scl.repo CentOS-fasttrack.repo CentOS-x86_64-kernel.repo rm -f CentOS-Base.repo CentOS-SCLo-scl-rh.repo CentOS-SCLo-scl.repo CentOS-fasttrack.repo CentOS-x86_64-kernel.repo
yum install -y yum-plugin-ovl # fix for docker overlay fs yum install -y yum-plugin-ovl # fix for docker overlay fs
yum install -y xz yum install -y xz
# download musl cross compilation toolchain # download musl cross compilation toolchain - mirrored as a release asset on the
# repo since musl.cc blocks GitHub Actions IP ranges (musl.cc fallback kept)
cd ~ cd ~
curl -L "https://musl.cc/${CROSS}-cross.tgz" -o "${CROSS}-cross.tgz" curl -fL -4 --retry 5 --retry-delay 2 --connect-timeout 15 "https://github.com/masonr/yet-another-bench-script/releases/download/toolchains/${CROSS}-cross.tgz" -o "${CROSS}-cross.tgz" \
|| curl -fL -4 --retry 5 --retry-delay 2 --connect-timeout 15 "https://musl.cc/${CROSS}-cross.tgz" -o "${CROSS}-cross.tgz"
tar xf "${CROSS}-cross.tgz" tar xf "${CROSS}-cross.tgz"
# download, compile, and install libaio as static library # download, compile, and install libaio as static library
@@ -30,11 +32,15 @@ source /hbb_exe/activate
# download and compile fio # download and compile fio
cd ~ cd ~
curl -L https://github.com/axboe/fio/archive/fio-3.39.tar.gz -o "fio.tar.gz" curl -L https://github.com/axboe/fio/archive/fio-3.42.tar.gz -o "fio.tar.gz"
tar xf fio.tar.gz tar xf fio.tar.gz
cd fio-fio* cd fio-fio-*
# fio >= 3.42 includes both linux/prctl.h and sys/prctl.h in backend.c, which
# conflicts under musl; sys/prctl.h alone is sufficient
sed -i '/#include <linux\/prctl.h>/d' backend.c
CC=/root/${CROSS}-cross/bin/${CROSS}-gcc ./configure --disable-native --build-static CC=/root/${CROSS}-cross/bin/${CROSS}-gcc ./configure --disable-native --build-static
make # link against libatomic for 32-bit/ARM targets that lack native 64-bit atomics
make EXTLIBS+=' -latomic'
# verify no external shared library links # verify no external shared library links
libcheck fio libcheck fio
@@ -43,10 +49,13 @@ cp fio "/io/fio_$ARCH"
# download and compile iperf # download and compile iperf
cd ~ cd ~
curl -L https://github.com/esnet/iperf/archive/3.18.tar.gz -o "iperf.tar.gz" curl -L https://github.com/esnet/iperf/archive/3.21.tar.gz -o "iperf.tar.gz"
tar xf iperf.tar.gz tar xf iperf.tar.gz
cd iperf* cd iperf-*
CC=/root/${CROSS}-cross/bin/${CROSS}-gcc ./configure --disable-shared --disable-profiling --build x86_64-pc-linux-gnu --host "${HOST}" --with-openssl=no --enable-static-bin CC=/root/${CROSS}-cross/bin/${CROSS}-gcc ./configure --disable-shared --disable-profiling --build x86_64-pc-linux-gnu --host "${HOST}" --with-openssl=no --enable-static-bin
# remove libatomic.la so libtool links the static libatomic.a rather than
# attempting to link libatomic.so into the static binary (breaks arm32 builds)
rm -f "/root/${CROSS}-cross/${CROSS}/lib/libatomic.la"
make make
# verify no external shared library links # verify no external shared library links

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

129
yabs.sh
View File

@@ -1,18 +1,18 @@
#!/bin/bash #!/bin/bash
# Yet Another Bench Script by Mason Rowe # Yet Another Bench Script by Mason Rowe
# Initial Oct 2019; Last update May 2026 # Initial Oct 2019; Last update Sep 2026
# Disclaimer: This project is a work in progress. Any errors or suggestions should be # Disclaimer: This project is a work in progress. Any errors or suggestions should be
# relayed to me via the GitHub project page linked below. # relayed to me via the GitHub project page linked below.
# #
# Purpose: The purpose of this script is to quickly gauge the performance of a Linux- # Purpose: The purpose of this script is to quickly gauge the performance of a Linux-
# based server by benchmarking network performance via iperf3, CPU and # based server by benchmarking network performance via iperf3, CPU and
# overall system performance via Geekbench 4/5/6, and random disk # overall system performance via Geekbench 4/5/6/7, and random disk
# performance via fio. The script is designed to not require any dependencies # performance via fio. The script is designed to not require any dependencies
# - either compiled or installed - nor admin privileges to run. # - either compiled or installed - nor admin privileges to run.
YABS_VERSION="v2026-05-11" YABS_VERSION="v2026-09-20"
echo -e '# ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## #' echo -e '# ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## #'
echo -e '# Yet-Another-Bench-Script #' echo -e '# Yet-Another-Bench-Script #'
@@ -59,11 +59,11 @@ else
fi fi
# flags to skip certain performance tests # flags to skip certain performance tests
unset PREFER_BIN SKIP_FIO SKIP_IPERF SKIP_GEEKBENCH SKIP_NET PRINT_HELP REDUCE_NET GEEKBENCH_4 GEEKBENCH_5 GEEKBENCH_6 DD_FALLBACK IPERF_DL_FAIL JSON JSON_SEND JSON_RESULT JSON_FILE IPERF_SERVERS unset PREFER_BIN SKIP_FIO SKIP_IPERF SKIP_GEEKBENCH SKIP_NET PRINT_HELP REDUCE_NET GEEKBENCH_4 GEEKBENCH_5 GEEKBENCH_6 GEEKBENCH_7 DD_FALLBACK IPERF_DL_FAIL JSON JSON_SEND JSON_RESULT JSON_FILE IPERF_SERVERS
GEEKBENCH_6="True" # gb6 test enabled by default GEEKBENCH_6="True" # gb6 test enabled by default
# get any arguments that were passed to the script and set the associated skip flags (if applicable) # get any arguments that were passed to the script and set the associated skip flags (if applicable)
while getopts 'bfdignhr4596jw:s:p:' flag; do while getopts 'bfdignhr45796jw:s:p:' flag; do
case "${flag}" in case "${flag}" in
b) PREFER_BIN="True" ;; b) PREFER_BIN="True" ;;
f) SKIP_FIO="True" ;; f) SKIP_FIO="True" ;;
@@ -75,6 +75,7 @@ while getopts 'bfdignhr4596jw:s:p:' flag; do
r) REDUCE_NET="True" ;; r) REDUCE_NET="True" ;;
4) GEEKBENCH_4="True" && unset GEEKBENCH_6 ;; 4) GEEKBENCH_4="True" && unset GEEKBENCH_6 ;;
5) GEEKBENCH_5="True" && unset GEEKBENCH_6 ;; 5) GEEKBENCH_5="True" && unset GEEKBENCH_6 ;;
7) GEEKBENCH_7="True" && unset GEEKBENCH_6 ;;
9) GEEKBENCH_4="True" && GEEKBENCH_5="True" && unset GEEKBENCH_6 ;; 9) GEEKBENCH_4="True" && GEEKBENCH_5="True" && unset GEEKBENCH_6 ;;
6) GEEKBENCH_6="True" ;; 6) GEEKBENCH_6="True" ;;
j) JSON+="j" ;; j) JSON+="j" ;;
@@ -144,8 +145,9 @@ if [ -n "$PRINT_HELP" ]; then
echo -e " to lessen bandwidth usage" echo -e " to lessen bandwidth usage"
echo -e " -4 : use geekbench 4 instead of geekbench 6" echo -e " -4 : use geekbench 4 instead of geekbench 6"
echo -e " -5 : use geekbench 5 instead of geekbench 6" echo -e " -5 : use geekbench 5 instead of geekbench 6"
echo -e " -7 : use geekbench 7 instead of geekbench 6"
echo -e " -9 : use both geekbench 4 AND geekbench 5 instead of geekbench 6" echo -e " -9 : use both geekbench 4 AND geekbench 5 instead of geekbench 6"
echo -e " -6 : use geekbench 6 in addition to 4 and/or 5 (only needed if -4, -5, or -9 are set; -6 must come last)" echo -e " -6 : use geekbench 6 in addition to 4, 5, and/or 7 (only needed if -4, -5, -7, or -9 are set; -6 must come last)"
echo -e " -j : print jsonified YABS results at conclusion of test" echo -e " -j : print jsonified YABS results at conclusion of test"
echo -e " -w <filename> : write jsonified YABS results to disk using file name provided" echo -e " -w <filename> : write jsonified YABS results to disk using file name provided"
echo -e " -s <url> : send jsonified YABS results to URL" echo -e " -s <url> : send jsonified YABS results to URL"
@@ -165,6 +167,7 @@ if [ -n "$PRINT_HELP" ]; then
[[ -n $GEEKBENCH_4 ]] && echo -e " running geekbench 4" [[ -n $GEEKBENCH_4 ]] && echo -e " running geekbench 4"
[[ -n $GEEKBENCH_5 ]] && echo -e " running geekbench 5" [[ -n $GEEKBENCH_5 ]] && echo -e " running geekbench 5"
[[ -n $GEEKBENCH_6 ]] && echo -e " running geekbench 6" [[ -n $GEEKBENCH_6 ]] && echo -e " running geekbench 6"
[[ -n $GEEKBENCH_7 ]] && echo -e " running geekbench 7"
[[ -n $IPERF_SERVERS ]] && echo -e " -p, using custom iperf servers: $IPERF_SERVERS" [[ -n $IPERF_SERVERS ]] && echo -e " -p, using custom iperf servers: $IPERF_SERVERS"
echo -e echo -e
echo -e "Local Binary Check:" echo -e "Local Binary Check:"
@@ -192,6 +195,20 @@ if [ -n "$PRINT_HELP" ]; then
exit 0 exit 0
fi fi
# determine which repo release tags to pull the precompiled fio/iperf3 binaries from:
# auto-detect the latest matching releases from the repo's releases feed and fall
# back to the pinned tags below if the lookup fails
FIO_BIN_TAG="fio-3.42" # pinned fallback fio release
IPERF_BIN_TAG="iperf3-3.21" # pinned fallback iperf3 release
if [[ -z $SKIP_FIO || -z $SKIP_IPERF ]]; then
BIN_RELEASES_FEED=$($IP_CHECK_CMD https://github.com/masonr/yet-another-bench-script/releases.atom 2>/dev/null)
FIO_BIN_TAG_LATEST=$(echo "$BIN_RELEASES_FEED" | grep -oE 'fio-[0-9]+\.[0-9]+' | head -n 1)
IPERF_BIN_TAG_LATEST=$(echo "$BIN_RELEASES_FEED" | grep -oE 'iperf3-[0-9]+\.[0-9]+' | head -n 1)
[[ -n $FIO_BIN_TAG_LATEST ]] && FIO_BIN_TAG=$FIO_BIN_TAG_LATEST
[[ -n $IPERF_BIN_TAG_LATEST ]] && IPERF_BIN_TAG=$IPERF_BIN_TAG_LATEST
unset FIO_BIN_TAG_LATEST IPERF_BIN_TAG_LATEST BIN_RELEASES_FEED
fi
# format_size # format_size
# Purpose: Formats raw disk and memory sizes from kibibytes (KiB) to largest unit # Purpose: Formats raw disk and memory sizes from kibibytes (KiB) to largest unit
# Parameters: # Parameters:
@@ -235,7 +252,7 @@ function format_size {
echo -e echo -e
echo -e "Basic System Information:" echo -e "Basic System Information:"
echo -e "---------------------------------" echo -e "---------------------------------"
UPTIME=$(uptime | awk -F'( |,|:)+' '{d=h=m=0; if ($7=="min") m=$6; else {if ($7~/^day/) {d=$6;h=$8;m=$9} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes"}') UPTIME=$(uptime | awk -F'( |,|:)+' '{d=h=m=0; if ($7=="min") m=$6; else {if ($7~/^day/) {d=$6; if ($9~/^min/) m=$8; else {h=$8;m=$9}} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes"}')
echo -e "Uptime : $UPTIME" echo -e "Uptime : $UPTIME"
# check for local lscpu installs # check for local lscpu installs
if command -v lscpu >/dev/null 2>&1; then if command -v lscpu >/dev/null 2>&1; then
@@ -383,16 +400,18 @@ function catch_abort() {
# format_speed # format_speed
# Purpose: This method is a convenience function to format the output of the fio disk tests which # Purpose: This method is a convenience function to format the output of the fio disk tests which
# always returns a result in KB/s. If result is >= 1 GB/s, use GB/s. If result is < 1 GB/s # always returns a result in KiB/s (fio terse v3 bandwidth fields are always KiB/s regardless
# and >= 1 MB/s, then use MB/s. Otherwise, use KB/s. # of --kb_base setting). Converts KiB/s to decimal units (KB/s, MB/s, GB/s) for display.
# Conversion: multiply KiB/s by 1024 to get bytes/s, then divide by 1000, 1000000, or
# 1000000000 to get KB/s, MB/s, or GB/s respectively.
# Thresholds (in KiB/s): >= 976563 -> GB/s, >= 977 -> MB/s, otherwise -> KB/s
# Parameters: # Parameters:
# 1. RAW - the raw disk speed result (in KB/s) # 1. RAW - the raw disk speed result (in KiB/s)
# Returns: # Returns:
# Formatted disk speed in GB/s, MB/s, or KB/s # Formatted disk speed in GB/s, MB/s, or KB/s
function format_speed { function format_speed {
RAW=$1 # disk speed in KB/s RAW=$1 # disk speed in KiB/s
RESULT=$RAW RESULT=$RAW
local DENOM=1
local UNIT="KB/s" local UNIT="KB/s"
# ensure raw value is not null, if it is, return blank # ensure raw value is not null, if it is, return blank
@@ -401,18 +420,19 @@ function format_speed {
return 0 return 0
fi fi
# check if disk speed >= 1 GB/s # check if disk speed >= 1 GB/s (976563 KiB/s = 1,000,000,000 bytes/s)
if [ "$RAW" -ge 1000000 ]; then if [ "$RAW" -ge 976563 ]; then
DENOM=1000000
UNIT="GB/s" UNIT="GB/s"
# check if disk speed < 1 GB/s && >= 1 MB/s RESULT=$(awk -v a="$RAW" 'BEGIN { print a * 1024 / 1000000000 }')
elif [ "$RAW" -ge 1000 ]; then # check if disk speed >= 1 MB/s (977 KiB/s ~ 1,000,000 bytes/s)
DENOM=1000 elif [ "$RAW" -ge 977 ]; then
UNIT="MB/s" UNIT="MB/s"
RESULT=$(awk -v a="$RAW" 'BEGIN { print a * 1024 / 1000000 }')
else
# convert KiB/s to KB/s (multiply by 1.024)
RESULT=$(awk -v a="$RAW" 'BEGIN { print a * 1024 / 1000 }')
fi fi
# divide the raw result to get the corresponding formatted result (based on determined unit)
RESULT=$(awk -v a="$RESULT" -v b="$DENOM" 'BEGIN { print a / b }')
# shorten the formatted result to two decimal places (i.e. x.xx) # shorten the formatted result to two decimal places (i.e. x.xx)
RESULT=$(echo "$RESULT" | awk -F. '{ printf "%0.2f",$1"."substr($2,1,2) }') RESULT=$(echo "$RESULT" | awk -F. '{ printf "%0.2f",$1"."substr($2,1,2) }')
# concat formatted result value with units and return result # concat formatted result value with units and return result
@@ -569,9 +589,9 @@ elif [ -z "$SKIP_FIO" ]; then
# Proceed only if a relevant ZFS path was found # Proceed only if a relevant ZFS path was found
if [[ -n "$long" ]]; then if [[ -n "$long" ]]; then
# Get the 'Avail' space directly for the detected path and explicitly for ZFS type # Get the 'Avail' space directly for the detected path and explicitly for ZFS type
# The 'Avail' column is the 4th field in `df -Th` output # The 'Avail' column is the 5th field in `df -Th` output (-T adds a Type column, shifting fields right)
# Example: '7.3T', '104G', '17G' # Example: '7.3T', '104G', '17G'
avail_space_with_unit=$(df -Th | grep -w "$long" | awk '$2 == "zfs" {print $4; exit}') avail_space_with_unit=$(df -Th | grep -w "$long" | awk '$2 == "zfs" {print $5; exit}')
# If a valid free space value was extracted # If a valid free space value was extracted
if [[ -n "$avail_space_with_unit" ]]; then if [[ -n "$avail_space_with_unit" ]]; then
@@ -640,14 +660,14 @@ fi
if [[ -z "$PREFER_BIN" && -n "$LOCAL_FIO" ]]; then # local fio has been detected, use instead of pre-compiled binary if [[ -z "$PREFER_BIN" && -n "$LOCAL_FIO" ]]; then # local fio has been detected, use instead of pre-compiled binary
FIO_CMD=fio FIO_CMD=fio
else else
# download fio binary # download fio binary from the binary release on the repo
if [[ -n $LOCAL_CURL ]]; then if [[ -n $LOCAL_CURL ]]; then
curl -s --connect-timeout 5 --retry 5 --retry-delay 0 https://raw.githubusercontent.com/masonr/yet-another-bench-script/master/bin/fio/fio_$ARCH -o "$DISK_PATH/fio" curl -sfL --connect-timeout 5 --retry 5 --retry-delay 0 "https://github.com/masonr/yet-another-bench-script/releases/download/$FIO_BIN_TAG/fio_$ARCH" -o "$DISK_PATH/fio"
else else
wget -q -T 5 -t 5 -w 0 https://raw.githubusercontent.com/masonr/yet-another-bench-script/master/bin/fio/fio_$ARCH -O "$DISK_PATH/fio" wget -q -T 5 -t 5 -w 0 "https://github.com/masonr/yet-another-bench-script/releases/download/$FIO_BIN_TAG/fio_$ARCH" -O "$DISK_PATH/fio"
fi fi
if [ ! -f "$DISK_PATH/fio" ]; then # ensure fio binary download successfully if [ ! -s "$DISK_PATH/fio" ]; then # ensure fio binary download successfully
echo -en "\r\033[0K" echo -en "\r\033[0K"
echo -e "Fio binary download failed. Running dd test as fallback...." echo -e "Fio binary download failed. Running dd test as fallback...."
DD_FALLBACK=True DD_FALLBACK=True
@@ -798,7 +818,7 @@ function iperf_test {
done done
# Run a latency test via ping -c1 command -> will return "xx.x ms" # Run a latency test via ping -c1 command -> will return "xx.x ms"
[[ -n $LOCAL_PING ]] && LATENCY_RUN="$(ping -c1 "$URL" 2>/dev/null | grep -o 'time=.*' | sed s/'time='//)" [[ -n $LOCAL_PING ]] && LATENCY_RUN="$(ping "$FLAGS" -c1 "$URL" 2>/dev/null | grep -o 'time=.*' | sed 's/time=//')"
[[ -z $LATENCY_RUN ]] && LATENCY_RUN="--" [[ -z $LATENCY_RUN ]] && LATENCY_RUN="--"
# parse the resulting send and receive speed results # parse the resulting send and receive speed results
@@ -858,14 +878,14 @@ if [ -z "$SKIP_IPERF" ]; then
IPERF_PATH=$YABS_PATH/iperf IPERF_PATH=$YABS_PATH/iperf
mkdir -p "$IPERF_PATH" mkdir -p "$IPERF_PATH"
# download iperf3 binary # download iperf3 binary from the binary release on the repo
if [[ -n $LOCAL_CURL ]]; then if [[ -n $LOCAL_CURL ]]; then
curl -s --connect-timeout 5 --retry 5 --retry-delay 0 https://raw.githubusercontent.com/masonr/yet-another-bench-script/master/bin/iperf/iperf3_$ARCH -o "$IPERF_PATH/iperf3" curl -sfL --connect-timeout 5 --retry 5 --retry-delay 0 "https://github.com/masonr/yet-another-bench-script/releases/download/$IPERF_BIN_TAG/iperf3_$ARCH" -o "$IPERF_PATH/iperf3"
else else
wget -q -T 5 -t 5 -w 0 https://raw.githubusercontent.com/masonr/yet-another-bench-script/master/bin/iperf/iperf3_$ARCH -O "$IPERF_PATH/iperf3" wget -q -T 5 -t 5 -w 0 "https://github.com/masonr/yet-another-bench-script/releases/download/$IPERF_BIN_TAG/iperf3_$ARCH" -O "$IPERF_PATH/iperf3"
fi fi
if [ ! -f "$IPERF_PATH/iperf3" ]; then # ensure iperf3 binary downloaded successfully if [ ! -s "$IPERF_PATH/iperf3" ]; then # ensure iperf3 binary downloaded successfully
IPERF_DL_FAIL=True IPERF_DL_FAIL=True
else else
chmod +x "$IPERF_PATH/iperf3" chmod +x "$IPERF_PATH/iperf3"
@@ -937,7 +957,7 @@ if [ -z "$SKIP_IPERF" ]; then
fi fi
# launch_geekbench # launch_geekbench
# Purpose: This method is designed to run the Primate Labs' Geekbench 4/5/6 Cross-Platform Benchmark utility # Purpose: This method is designed to run the Primate Labs' Geekbench 4/5/6/7 Cross-Platform Benchmark utility
# Parameters: # Parameters:
# 1. VERSION - indicates which Geekbench version to run # 1. VERSION - indicates which Geekbench version to run
function launch_geekbench { function launch_geekbench {
@@ -960,8 +980,8 @@ function launch_geekbench {
GB_URL="https://cdn.geekbench.com/Geekbench-4.4.4-Linux.tar.gz" GB_URL="https://cdn.geekbench.com/Geekbench-4.4.4-Linux.tar.gz"
[[ "$ARCH" == *"x86"* ]] && GB_CMD="geekbench_x86_32" || GB_CMD="geekbench4" [[ "$ARCH" == *"x86"* ]] && GB_CMD="geekbench_x86_32" || GB_CMD="geekbench4"
GB_RUN="True" GB_RUN="True"
elif [[ $VERSION == *5* || $VERSION == *6* ]]; then # Geekbench v5/6 elif [[ $VERSION == *5* || $VERSION == *6* || $VERSION == *7* ]]; then # Geekbench v5/6/7
if [[ $ARCH = *x86* && $GEEKBENCH_4 == *False* ]]; then # don't run Geekbench 5 if on 32-bit arch if [[ $ARCH = *x86* && $GEEKBENCH_4 == *False* ]]; then # don't run Geekbench 5/6/7 if on 32-bit arch
echo -e "\nGeekbench $VERSION cannot run on 32-bit architectures. Re-run with -4 flag to use" echo -e "\nGeekbench $VERSION cannot run on 32-bit architectures. Re-run with -4 flag to use"
echo -e "Geekbench 4, which can support 32-bit architectures. Skipping Geekbench $VERSION." echo -e "Geekbench 4, which can support 32-bit architectures. Skipping Geekbench $VERSION."
elif [[ $ARCH = *x86* && $GEEKBENCH_4 == *True* ]]; then elif [[ $ARCH = *x86* && $GEEKBENCH_4 == *True* ]]; then
@@ -971,10 +991,14 @@ function launch_geekbench {
[[ $ARCH = *aarch64* || $ARCH = *arm* ]] && GB_URL="https://cdn.geekbench.com/Geekbench-5.5.1-LinuxARMPreview.tar.gz" \ [[ $ARCH = *aarch64* || $ARCH = *arm* ]] && GB_URL="https://cdn.geekbench.com/Geekbench-5.5.1-LinuxARMPreview.tar.gz" \
|| GB_URL="https://cdn.geekbench.com/Geekbench-5.5.1-Linux.tar.gz" || GB_URL="https://cdn.geekbench.com/Geekbench-5.5.1-Linux.tar.gz"
GB_CMD="geekbench5" GB_CMD="geekbench5"
else # Geekbench v6 elif [[ $VERSION == *6* ]]; then # Geekbench v6
[[ $ARCH = *aarch64* || $ARCH = *arm* ]] && GB_URL="https://cdn.geekbench.com/Geekbench-6.7.1-LinuxARMPreview.tar.gz" \ [[ $ARCH = *aarch64* || $ARCH = *arm* ]] && GB_URL="https://cdn.geekbench.com/Geekbench-6.7.1-LinuxARMPreview.tar.gz" \
|| GB_URL="https://cdn.geekbench.com/Geekbench-6.7.1-Linux.tar.gz" || GB_URL="https://cdn.geekbench.com/Geekbench-6.7.1-Linux.tar.gz"
GB_CMD="geekbench6" GB_CMD="geekbench6"
else # Geekbench v7
[[ $ARCH = *aarch64* || $ARCH = *arm* ]] && GB_URL="https://cdn.geekbench.com/Geekbench-7.0.0-LinuxARMPreview.tar.gz" \
|| GB_URL="https://cdn.geekbench.com/Geekbench-7.0.0-Linux.tar.gz"
GB_CMD="geekbench7"
fi fi
GB_RUN="True" GB_RUN="True"
fi fi
@@ -995,7 +1019,8 @@ function launch_geekbench {
test -f "geekbench.license" && "$GEEKBENCH_PATH/$GB_CMD" --unlock "$(cat geekbench.license)" > /dev/null 2>&1 test -f "geekbench.license" && "$GEEKBENCH_PATH/$GB_CMD" --unlock "$(cat geekbench.license)" > /dev/null 2>&1
# run the Geekbench test and grep the test results URL given at the end of the test # run the Geekbench test and grep the test results URL given at the end of the test
GEEKBENCH_TEST=$("$GEEKBENCH_PATH/$GB_CMD" --upload 2>/dev/null | grep "https://browser") GEEKBENCH_OUTPUT=$("$GEEKBENCH_PATH/$GB_CMD" --upload 2>/dev/null)
GEEKBENCH_TEST=$(echo "$GEEKBENCH_OUTPUT" | grep "https://browser")
# ensure the test ran successfully # ensure the test ran successfully
if [ -z "$GEEKBENCH_TEST" ]; then if [ -z "$GEEKBENCH_TEST" ]; then
@@ -1007,7 +1032,7 @@ function launch_geekbench {
# Geekbench test failed to download because host lacks IPv4 (cdn.geekbench.com = IPv4 only) # Geekbench test failed to download because host lacks IPv4 (cdn.geekbench.com = IPv4 only)
echo -e "\r\033[0KGeekbench releases can only be downloaded over IPv4. FTP the Geekbench files and run manually." echo -e "\r\033[0KGeekbench releases can only be downloaded over IPv4. FTP the Geekbench files and run manually."
elif [[ $VERSION != *4* && $TOTAL_RAM_RAW -le 1048576 ]]; then elif [[ $VERSION != *4* && $TOTAL_RAM_RAW -le 1048576 ]]; then
# Geekbench 5/6 test failed with low memory (<=1GB) # Geekbench 5/6/7 test failed with low memory (<=1GB)
echo -e "\r\033[0KGeekbench test failed and low memory was detected. Add at least 1GB of SWAP or use GB4 instead (higher compatibility with low memory systems)." echo -e "\r\033[0KGeekbench test failed and low memory was detected. Add at least 1GB of SWAP or use GB4 instead (higher compatibility with low memory systems)."
elif [[ $ARCH != *x86* ]]; then elif [[ $ARCH != *x86* ]]; then
# if the Geekbench test failed for any other reason, exit cleanly and print error message # if the Geekbench test failed for any other reason, exit cleanly and print error message
@@ -1017,14 +1042,26 @@ function launch_geekbench {
# if the Geekbench test succeeded, parse the test results URL # if the Geekbench test succeeded, parse the test results URL
GEEKBENCH_URL=$(echo -e "$GEEKBENCH_TEST" | head -1 | awk '{ print $1 }') GEEKBENCH_URL=$(echo -e "$GEEKBENCH_TEST" | head -1 | awk '{ print $1 }')
GEEKBENCH_URL_CLAIM=$(echo -e "$GEEKBENCH_TEST" | tail -1 | awk '{ print $1 }') GEEKBENCH_URL_CLAIM=$(echo -e "$GEEKBENCH_TEST" | tail -1 | awk '{ print $1 }')
# sleep a bit to wait for results to be made available on the geekbench website
sleep 10
# parse the public results page for the single and multi core geekbench scores
[[ $VERSION == *4* ]] && GEEKBENCH_SCORES=$($DL_CMD "$GEEKBENCH_URL" | grep "span class='score'") || \
GEEKBENCH_SCORES=$($DL_CMD "$GEEKBENCH_URL" | grep "div class='score'")
GEEKBENCH_SCORES_SINGLE=$(echo "$GEEKBENCH_SCORES" | awk -v FS="(>|<)" '{ print $3 }' | head -n 1) # newer Geekbench 6/7 releases print the single and multi-core scores to stdout
GEEKBENCH_SCORES_MULTI=$(echo "$GEEKBENCH_SCORES" | awk -v FS="(>|<)" '{ print $3 }' | tail -n 1) # in the "Benchmark Summary" section; parse them directly from the test output
if [[ $VERSION == *6* || $VERSION == *7* ]]; then
GEEKBENCH_SCORES_SINGLE=$(echo "$GEEKBENCH_OUTPUT" | grep "Single-Core Score" | awk '{ print $NF }')
GEEKBENCH_SCORES_MULTI=$(echo "$GEEKBENCH_OUTPUT" | grep "Multi-Core Score" | awk '{ print $NF }')
fi
# if the scores were not found in the test output (i.e. Geekbench 4/5 or older
# 6/7 releases), fetch and parse the public results page for them instead
if [[ -z "$GEEKBENCH_SCORES_SINGLE" || -z "$GEEKBENCH_SCORES_MULTI" ]]; then
# sleep a bit to wait for results to be made available on the geekbench website
sleep 10
# parse the public results page for the single and multi core geekbench scores
[[ $VERSION == *4* ]] && GEEKBENCH_SCORES=$($DL_CMD "$GEEKBENCH_URL" | grep "span class='score'") || \
GEEKBENCH_SCORES=$($DL_CMD "$GEEKBENCH_URL" | grep "div class='score'")
GEEKBENCH_SCORES_SINGLE=$(echo "$GEEKBENCH_SCORES" | awk -v FS="(>|<)" '{ print $3 }' | head -n 1)
GEEKBENCH_SCORES_MULTI=$(echo "$GEEKBENCH_SCORES" | awk -v FS="(>|<)" '{ print $3 }' | tail -n 1)
fi
# print the Geekbench results # print the Geekbench results
echo -en "\r\033[0K" echo -en "\r\033[0K"
@@ -1061,6 +1098,10 @@ if [ -z "$SKIP_GEEKBENCH" ]; then
if [[ $GEEKBENCH_6 == *True* ]]; then if [[ $GEEKBENCH_6 == *True* ]]; then
launch_geekbench 6 launch_geekbench 6
fi fi
if [[ $GEEKBENCH_7 == *True* ]]; then
launch_geekbench 7
fi
[[ -n $JSON ]] && [[ "${JSON_RESULT: -1}" == ',' ]] && JSON_RESULT="${JSON_RESULT%,}" [[ -n $JSON ]] && [[ "${JSON_RESULT: -1}" == ',' ]] && JSON_RESULT="${JSON_RESULT%,}"
[[ -n $JSON ]] && JSON_RESULT+="]" [[ -n $JSON ]] && JSON_RESULT+="]"
fi fi