Skip to content

probe: measure the GitCode upload path (TEMPORARY — do not merge) #1

probe: measure the GitCode upload path (TEMPORARY — do not merge)

probe: measure the GitCode upload path (TEMPORARY — do not merge) #1

name: probe-gitcode-upload
# TEMPORARY diagnostic workflow — delete with this branch.
#
# WHY. `publish-ecosystem`'s GitCode leg has now blown its 180s per-asset cap
# on four separate releases (0.0.94 / 0.0.97 / 0.0.105 / 2026.7.28.2), each
# time on the two biggest tarballs, each time costing ~5min of manual
# re-upload. Every previous fix was a guess about WHY it is slow (raise the
# cap, skip-don't-retry, batch verify). This workflow measures instead.
#
# Each job isolates ONE hypothesis, and they run in parallel so a single push
# answers all of them:
#
# baseline Is it the network, the direction, or GitCode specifically?
# Down/up control against GitHub from the same runner.
# sizes-urllib Does throughput collapse with size, or is it ~constant?
# (constant MB/s => a pure bandwidth wall, not a stall.)
# sizes-curl Is Python's read-it-all-then-PUT the bottleneck, or the wire?
# concurrency Is bandwidth per-connection or per-host? If per-connection,
# uploading assets in parallel is the whole fix — mirror_res.sh
# currently uploads them SERIALLY within a host leg.
#
# Every job writes NDJSON to the step summary so results are comparable
# without opening logs.
on:
push:
branches: [ 'probe/**' ]
workflow_dispatch:
permissions:
contents: read
concurrency:
group: probe-gitcode-${{ github.ref }}
cancel-in-progress: true
env:
GTC_REPO: xlings-res/mcpp
# A real, already-mirrored asset used as the download reference (34.8MB).
REF_ASSET: mcpp-2026.7.28.2-linux-x86_64.tar.gz
REF_TAG: 2026.7.28.2
jobs:
# ── H0: characterise the pipe itself, both directions, both hosts ────────
baseline:
name: baseline — network + GitHub control
runs-on: ubuntu-latest
timeout-minutes: 25
env:
GITCODE_TOKEN: ${{ secrets.GITCODE_TOKEN }}
GH_TOKEN: ${{ secrets.XLINGS_RES_TOKEN }}
steps:
- uses: actions/checkout@v4
- name: Runner egress identity
run: |
echo "runner public IP / region:"
curl -s --max-time 20 https://ipinfo.io/json || echo "(ipinfo unavailable)"
- name: Connect/TLS timing to each host
run: |
fmt=' dns=%{time_namelookup}s connect=%{time_connect}s tls=%{time_appconnect}s ttfb=%{time_starttransfer}s total=%{time_total}s code=%{http_code}\n'
for h in https://api.gitcode.com https://gitcode.com https://api.github.com https://github.com; do
echo "$h"
curl -sS -o /dev/null --max-time 60 -w "$fmt" "$h" || echo " (failed)"
done
- name: Download throughput — gitcode vs github (same 34.8MB asset)
run: |
fmt=' code=%{http_code} bytes=%{size_download} speed=%{speed_download} B/s total=%{time_total}s\n'
echo "gitcode.com:"
curl -sSL -o /dev/null --max-time 900 -w "$fmt" \
"https://gitcode.com/${GTC_REPO}/releases/download/${REF_TAG}/${REF_ASSET}" || true
echo "github.com:"
curl -sSL -o /dev/null --max-time 900 -w "$fmt" \
"https://github.com/${GTC_REPO}/releases/download/${REF_TAG}/${REF_ASSET}" || true
- name: Upload control — 32MB to GitHub from this same runner
run: |
set -x
head -c 33554432 /dev/urandom > probe-github-32m.bin
gh release view "probe-${{ github.run_id }}" -R "$GTC_REPO" >/dev/null 2>&1 \
|| gh release create "probe-${{ github.run_id }}" -R "$GTC_REPO" \
--title "probe ${{ github.run_id }}" --notes "temporary upload probe; safe to delete"
start=$SECONDS
gh release upload "probe-${{ github.run_id }}" probe-github-32m.bin -R "$GTC_REPO" --clobber
echo "GITHUB_UPLOAD_32MB_SECONDS=$((SECONDS - start))"
# ── H1: is throughput size-dependent (stall) or flat (bandwidth wall)? ───
sizes-urllib:
name: sizes — current urllib transport
runs-on: ubuntu-latest
timeout-minutes: 45
env:
GITCODE_TOKEN: ${{ secrets.GITCODE_TOKEN }}
TAG: probe-${{ github.run_id }}-urllib
steps:
- uses: actions/checkout@v4
- name: Create probe release
run: python3 .github/tools/gtc release create "$GTC_REPO" --tag "$TAG" --name "$TAG"
- name: Upload 1 / 4 / 16 / 32 / 32 MB (serial)
run: |
# 32MB twice: run-to-run variance matters as much as the mean when
# deciding whether a fixed 180s cap can ever be safe.
for spec in 1 4 16 32 32; do
f="probe-urllib-${spec}m-$RANDOM.bin"
head -c $((spec * 1048576)) /dev/urandom > "$f"
python3 .github/tools/probe_gtc_upload.py \
--repo "$GTC_REPO" --tag "$TAG" --file "$f" \
--method urllib --label "urllib-${spec}MB" >> results.ndjson
rm -f "$f"
done
- name: Summary
if: always()
run: |
{ echo '### sizes — urllib'; echo '```json'; cat results.ndjson; echo '```'; } \
>> "$GITHUB_STEP_SUMMARY"
# ── H2: is the Python client the bottleneck, or the wire? ────────────────
sizes-curl:
name: sizes — curl streaming transport
runs-on: ubuntu-latest
timeout-minutes: 45
env:
GITCODE_TOKEN: ${{ secrets.GITCODE_TOKEN }}
TAG: probe-${{ github.run_id }}-curl
steps:
- uses: actions/checkout@v4
- name: Create probe release
run: python3 .github/tools/gtc release create "$GTC_REPO" --tag "$TAG" --name "$TAG"
- name: Upload 1 / 4 / 16 / 32 / 32 MB (serial)
run: |
for spec in 1 4 16 32 32; do
f="probe-curl-${spec}m-$RANDOM.bin"
head -c $((spec * 1048576)) /dev/urandom > "$f"
python3 .github/tools/probe_gtc_upload.py \
--repo "$GTC_REPO" --tag "$TAG" --file "$f" \
--method curl --label "curl-${spec}MB" >> results.ndjson
rm -f "$f"
done
- name: Summary
if: always()
run: |
{ echo '### sizes — curl'; echo '```json'; cat results.ndjson; echo '```'; } \
>> "$GITHUB_STEP_SUMMARY"
# ── H3: per-connection cap or per-host cap? This decides whether simply
# parallelising mirror_res.sh's serial per-asset loop is the fix. ──
concurrency:
name: concurrency — 4x8MB serial vs parallel
runs-on: ubuntu-latest
timeout-minutes: 45
env:
GITCODE_TOKEN: ${{ secrets.GITCODE_TOKEN }}
TAG: probe-${{ github.run_id }}-conc
steps:
- uses: actions/checkout@v4
- name: Create probe release
run: python3 .github/tools/gtc release create "$GTC_REPO" --tag "$TAG" --name "$TAG"
- name: Serial 4x8MB
run: |
for i in 1 2 3 4; do head -c 8388608 /dev/urandom > "ser-$i.bin"; done
start=$SECONDS
for i in 1 2 3 4; do
python3 .github/tools/probe_gtc_upload.py --repo "$GTC_REPO" --tag "$TAG" \
--file "ser-$i.bin" --method curl --label "serial-$i" >> results.ndjson
done
echo "SERIAL_WALL_SECONDS=$((SECONDS - start))" | tee -a wall.txt
- name: Parallel 4x8MB
run: |
for i in 1 2 3 4; do head -c 8388608 /dev/urandom > "par-$i.bin"; done
start=$SECONDS
for i in 1 2 3 4; do
python3 .github/tools/probe_gtc_upload.py --repo "$GTC_REPO" --tag "$TAG" \
--file "par-$i.bin" --method curl --label "parallel-$i" >> "par-$i.json" &
done
wait
echo "PARALLEL_WALL_SECONDS=$((SECONDS - start))" | tee -a wall.txt
cat par-*.json >> results.ndjson
- name: Summary
if: always()
run: |
{ echo '### concurrency'; echo '```'; cat wall.txt; echo '```';
echo '```json'; cat results.ndjson; echo '```'; } >> "$GITHUB_STEP_SUMMARY"
# ── Leave no garbage on the resource repo ───────────────────────────────
cleanup:
name: cleanup probe tags
needs: [baseline, sizes-urllib, sizes-curl, concurrency]
if: always()
runs-on: ubuntu-latest
timeout-minutes: 10
env:
GITCODE_TOKEN: ${{ secrets.GITCODE_TOKEN }}
GH_TOKEN: ${{ secrets.XLINGS_RES_TOKEN }}
steps:
- name: Delete GitCode probe tags (deleting the tag deletes the release)
run: |
for t in "probe-${{ github.run_id }}-urllib" \
"probe-${{ github.run_id }}-curl" \
"probe-${{ github.run_id }}-conc"; do
code=$(curl -sS -o /dev/null -w '%{http_code}' -X DELETE \
-H "PRIVATE-TOKEN: $GITCODE_TOKEN" \
"https://api.gitcode.com/api/v5/repos/${GTC_REPO}/tags/${t}" || echo ERR)
echo "delete $t -> $code"
done
- name: Delete GitHub probe release
run: |
gh release delete "probe-${{ github.run_id }}" -R "$GTC_REPO" --yes --cleanup-tag \
|| echo "(nothing to delete)"