Skip to content

Commit 6f4cbb0

Browse files
authored
fix(ci): migrate benchmarks to benchmarking-platform trigger (#607)
1 parent c6da90c commit 6f4cbb0

12 files changed

Lines changed: 151 additions & 369 deletions

.github/chainguard/async-profiler-build.ci.sts.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Allow java-profiler GitLab CI to publish reports and manage issues
1+
# Allow java-profiler GitLab CI to post reports
22
issuer: https://gitlab.ddbuild.io
33

44
subject_pattern: "project_path:DataDog/java-profiler:ref_type:branch:ref:.*"

.gitlab-ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ stages:
3131
- integration-test
3232
- reliability
3333
- benchmarks
34+
- post-benchmarks
3435
- fuzz
3536
- notify
3637

.gitlab/benchmarks/.gitlab-ci.yml

Lines changed: 37 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
variables:
2-
PREPARE_IMAGE: registry.ddbuild.io/images/benchmarking-platform-tools-ubuntu:latest
32
DD_OCTO_STS_IMAGE: registry.ddbuild.io/images/dd-octo-sts-ci-base:2025.06-1
43

5-
.benchmark_job:
6-
extends: .deploy-sa
4+
# Bridge job: triggers the BP pipeline and blocks until it completes.
5+
# Bridge jobs cannot appear in other jobs' needs: — downstream jobs use
6+
# stage ordering (post-benchmarks stage runs after benchmarks stage).
7+
benchmarks-trigger:
78
stage: benchmarks
8-
timeout: 6h
9-
variables:
10-
ITERATIONS: "${BENCHMARK_ITERATIONS:-1}"
11-
MODES: "${BENCHMARK_MODES:-cpu,wall,alloc,memleak}"
9+
# Bridge jobs cannot have before_script, so CANCELLED is checked via rules.
10+
# interruptible: false prevents orphaning the BP downstream pipeline on push.
11+
interruptible: false
1212
needs:
1313
- job: get-versions
1414
artifacts: true
1515
- job: deploy-artifact
1616
artifacts: false
1717
rules:
18+
- if: '$CANCELLED == "true"'
19+
when: never
1820
- if: '$JDK_VERSION != null || $DEBUG_LEVEL != null || $HASH != null || $DOWNSTREAM != null'
1921
when: never
2022
- if: '$CI_PIPELINE_SOURCE == "schedule"'
@@ -24,113 +26,51 @@ variables:
2426
- if: '$CI_PIPELINE_SOURCE == "web"'
2527
when: manual
2628
allow_failure: true
27-
# Run automatically and non-blocking on any other source (push/trigger/api/
28-
# etc.) — mirrors the integration-test rules. The before_script CANCELLED
29-
# gate skips branches with no open PR.
29+
# Run automatically and non-blocking on any other source (push/trigger/api/etc.)
3030
- when: on_success
3131
allow_failure: true
32-
script: |
33-
# setup the env
34-
export ARTIFACTS_DIR="$(pwd)/reports" && (mkdir "${ARTIFACTS_DIR}" || :)
35-
export CANDIDATE_VERSION=${CURRENT_VERSION}
36-
export BASELINE_VERSION=${PREVIOUS_VERSION}
37-
export PLATFORM_DIR=".benchmarks/platform"
38-
39-
# check for missing candidate version
40-
if [ -z "${CANDIDATE_VERSION}" ]; then echo "Missing candidate version. Skipping."; exit 0; fi
41-
42-
# fetch the common platform scripts
43-
git -c url."https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.ddbuild.io/DataDog/".insteadOf="https://github.com/DataDog/" \
44-
clone --branch dd-trace-go https://github.com/DataDog/benchmarking-platform ${PLATFORM_DIR}
45-
46-
# apply the specific step scripts
47-
cp -r .gitlab/benchmarks/steps/* ${PLATFORM_DIR}/steps/
48-
chmod a+x ${PLATFORM_DIR}/steps/*
49-
50-
# check for mode validity
51-
${PLATFORM_DIR}/steps/check_modes.sh
52-
if [ "$(cat .job_status)" == "SKIP" ]; then exit 0; fi
53-
54-
# run benchmarks
55-
${PLATFORM_DIR}/steps/capture-hardware-software-info.sh
56-
${PLATFORM_DIR}/steps/run-benchmarks.sh
57-
${PLATFORM_DIR}/steps/analyze-results.sh
58-
${PLATFORM_DIR}/steps/upload-results-to-s3.sh
59-
parallel:
60-
matrix:
61-
- RUN_MODE: ["cpu", "wall", "alloc", "memleak", "cpu,wall", "memleak,alloc", "cpu,wall,alloc,memleak"]
62-
artifacts:
63-
when: always
64-
name: "reports"
65-
paths:
66-
- reports/
67-
expire_in: 3 months
68-
69-
benchmarks-candidate-amd64:
70-
extends: .benchmark_job
71-
tags: ["arch:amd64"]
72-
image: $BENCHMARK_IMAGE_AMD64
73-
74-
benchmarks-candidate-aarch64:
75-
extends: .benchmark_job
76-
tags: ["arch:arm64"]
77-
image: $BENCHMARK_IMAGE_ARM64
7832
variables:
79-
KUBERNETES_MEMORY_REQUEST: 200Gi
80-
KUBERNETES_MEMORY_LIMIT: 200Gi
33+
CANDIDATE_VERSION: "${CURRENT_VERSION}"
34+
BASELINE_VERSION: "${PREVIOUS_VERSION}"
35+
BENCHMARK_ITERATIONS: "${BENCHMARK_ITERATIONS:-5}"
36+
BENCHMARK_MODES: "${BENCHMARK_MODES:-cpu,wall,alloc,memleak}"
37+
DDPROF_COMMIT_SHA: "${CI_COMMIT_SHA}"
38+
DDPROF_COMMIT_BRANCH: "${CI_COMMIT_BRANCH}"
39+
UPSTREAM_PROJECT_NAME: "java-profiler"
40+
UPSTREAM_BRANCH: "${CI_COMMIT_BRANCH}"
41+
UPSTREAM_PIPELINE_ID: "${CI_PIPELINE_ID}"
42+
trigger:
43+
project: DataDog/apm-reliability/benchmarking-platform
44+
branch: java-profiler
45+
strategy: depend
8146

82-
post-benchmarks-pr-comment:
83-
extends: .retry-config
84-
stage: benchmarks
85-
tags: ["arch:arm64"]
86-
image: registry.ddbuild.io/images/dd-octo-sts-ci-base:2025.06-1
87-
id_tokens:
88-
DDOCTOSTS_ID_TOKEN:
89-
aud: dd-octo-sts
90-
needs:
91-
- job: prepare:start
92-
artifacts: true
93-
- job: benchmarks-candidate-amd64
94-
artifacts: true
95-
- job: benchmarks-candidate-aarch64
96-
artifacts: true
97-
rules:
98-
- if: '$JDK_VERSION != null || $DEBUG_LEVEL != null || $HASH != null || $DOWNSTREAM != null'
99-
when: never
100-
- if: '$CI_PIPELINE_SOURCE == "schedule"'
101-
when: never
102-
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
103-
when: never
104-
# Always run when the candidate jobs ran, regardless of source, so results
105-
# are posted back to the PR.
106-
- when: always
107-
timeout: 5m
108-
script:
109-
- .gitlab/benchmarks/post-pr-comment.sh reports
110-
allow_failure: true
11147

11248
publish-benchmark-gh-pages:
113-
stage: benchmarks
49+
stage: post-benchmarks
11450
tags: ["arch:arm64"]
115-
image: registry.ddbuild.io/images/dd-octo-sts-ci-base:2025.06-1
51+
image: $DD_OCTO_STS_IMAGE
11652
id_tokens:
11753
DDOCTOSTS_ID_TOKEN:
11854
aud: dd-octo-sts
119-
needs:
120-
- job: benchmarks-candidate-amd64
121-
artifacts: true
122-
- job: benchmarks-candidate-aarch64
123-
artifacts: true
55+
# Serialize concurrent GH Pages pushes. publish-gh-pages.sh uses
56+
# 'git push --force'; two concurrent pushes race and the slower one
57+
# silently discards the faster one's history update.
58+
resource_group: gh-pages-publish
12459
rules:
12560
- if: '$CI_PIPELINE_SOURCE == "schedule"'
12661
when: never
62+
- if: '$CANCELLED == "true"'
63+
when: never
64+
- if: '$JDK_VERSION != null || $DEBUG_LEVEL != null || $HASH != null || $DOWNSTREAM != null'
65+
when: never
12766
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH == "main"'
12867
when: always
129-
timeout: 10m
68+
timeout: 15m
13069
script:
131-
- ./.gitlab/benchmarks/publish-gh-pages.sh
70+
- mkdir -p reports
71+
- .gitlab/benchmarks/download-bp-reports.sh reports
72+
- ./.gitlab/benchmarks/publish-gh-pages.sh reports
13273
allow_failure: true
13374

13475
include:
13576
- local: .gitlab/common.yml
136-
- local: .gitlab/benchmarks/images.yml
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#!/usr/bin/env bash
2+
# Downloads result JSONs from the BP downstream pipeline via the GitLab CI API.
3+
#
4+
# Requires only curl and python3 (stdlib) — no aws CLI, pip, or boto3 needed.
5+
# BP jobs already store artifacts in GitLab; this fetches them directly from
6+
# the downstream pipeline triggered by benchmarks-trigger.
7+
set -uo pipefail # intentionally no -e: we handle errors explicitly
8+
9+
DEST="${1:-reports}"
10+
mkdir -p "${DEST}"
11+
12+
TMPDIR_LOCAL=$(mktemp -d)
13+
trap 'rm -rf "${TMPDIR_LOCAL}"' EXIT
14+
15+
# ── helper: curl with explicit HTTP status checking ──────────────────────────
16+
# Usage: api_get <url> <output_file>
17+
# Returns 0 on 2xx, prints diagnostics and returns 1 otherwise.
18+
api_get() {
19+
local url="$1" out="$2"
20+
local http_code
21+
http_code=$(curl -s -o "${out}" -w "%{http_code}" \
22+
--header "JOB-TOKEN: ${CI_JOB_TOKEN}" "${url}")
23+
if [[ "${http_code}" != 2* ]]; then
24+
echo " API ${url##*/}: HTTP ${http_code}$(python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('message','?'))" < "${out}" 2>/dev/null || echo 'see above')"
25+
return 1
26+
fi
27+
return 0
28+
}
29+
30+
# ── 1. find the benchmarks-trigger bridge ────────────────────────────────────
31+
BRIDGES_FILE="${TMPDIR_LOCAL}/bridges.json"
32+
echo "Querying bridges for pipeline ${CI_PIPELINE_ID}"
33+
if ! api_get \
34+
"${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/pipelines/${CI_PIPELINE_ID}/bridges" \
35+
"${BRIDGES_FILE}"; then
36+
echo "Cannot read pipeline bridges (job token may lack Reporter access) — skipping download"
37+
exit 0
38+
fi
39+
40+
read -r BP_PROJECT_ID DOWNSTREAM_PIPELINE_ID < <(python3 - "${BRIDGES_FILE}" <<'PYEOF'
41+
import json, sys
42+
with open(sys.argv[1]) as f:
43+
bridges = json.load(f)
44+
for b in bridges:
45+
if b.get("name") == "benchmarks-trigger":
46+
dp = b.get("downstream_pipeline") or {}
47+
if dp.get("id") and dp.get("project_id") and dp.get("status") == "success":
48+
print(dp["project_id"], dp["id"])
49+
sys.exit(0)
50+
print("", "")
51+
PYEOF
52+
)
53+
54+
if [ -z "${DOWNSTREAM_PIPELINE_ID:-}" ]; then
55+
echo "benchmarks-trigger bridge not found or did not run — skipping download"
56+
exit 0
57+
fi
58+
echo "BP downstream pipeline: project=${BP_PROJECT_ID} pipeline=${DOWNSTREAM_PIPELINE_ID}"
59+
60+
# ── 2. list jobs in the downstream pipeline (paginated) ──────────────────────
61+
echo "Listing BP pipeline jobs…"
62+
JOB_IDS=""
63+
PAGE=1
64+
while true; do
65+
JOBS_FILE="${TMPDIR_LOCAL}/jobs_page${PAGE}.json"
66+
if ! api_get \
67+
"${CI_API_V4_URL}/projects/${BP_PROJECT_ID}/pipelines/${DOWNSTREAM_PIPELINE_ID}/jobs?per_page=100&page=${PAGE}" \
68+
"${JOBS_FILE}"; then
69+
echo "Cannot list BP pipeline jobs — skipping download"
70+
exit 0
71+
fi
72+
PAGE_IDS=$(python3 -c "
73+
import json, sys
74+
jobs = json.load(open(sys.argv[1]))
75+
print(' '.join(str(j['id']) for j in jobs))
76+
print(len(jobs), file=sys.stderr)
77+
" "${JOBS_FILE}" 2>"${TMPDIR_LOCAL}/page_count.txt")
78+
JOB_IDS="${JOB_IDS} ${PAGE_IDS}"
79+
PAGE_COUNT=$(cat "${TMPDIR_LOCAL}/page_count.txt")
80+
if [ "${PAGE_COUNT}" -lt 100 ]; then
81+
break
82+
fi
83+
PAGE=$((PAGE + 1))
84+
done
85+
86+
# ── 3. download result_*.json from each job's artifact zip ───────────────────
87+
DOWNLOADED=0
88+
for JOB_ID in ${JOB_IDS}; do
89+
ART_ZIP="${TMPDIR_LOCAL}/art_${JOB_ID}.zip"
90+
ART_STATUS=$(curl -s -o "${ART_ZIP}" -w "%{http_code}" \
91+
--header "JOB-TOKEN: ${CI_JOB_TOKEN}" \
92+
"${CI_API_V4_URL}/projects/${BP_PROJECT_ID}/jobs/${JOB_ID}/artifacts" 2>/dev/null)
93+
if [[ "${ART_STATUS}" == 2* ]]; then
94+
# Contract with BP (DataDog/apm-reliability/benchmarking-platform#190):
95+
# artifacts are stored under the "artifacts/" prefix with names matching
96+
# "result_*.json". If BP renames either, this silently extracts nothing.
97+
# -j: junk paths (strip artifacts/ prefix), -q: quiet, -o: overwrite
98+
if unzip -q -j "${ART_ZIP}" "artifacts/result_*.json" -d "${DEST}/" 2>/dev/null; then
99+
DOWNLOADED=$((DOWNLOADED + 1))
100+
fi
101+
fi
102+
done
103+
104+
RESULT_COUNT=$(find "${DEST}" -name "result_*.json" | wc -l)
105+
echo "result_*.json files: ${RESULT_COUNT} (from ${DOWNLOADED} BP job(s))"
106+
107+
if [ "${RESULT_COUNT}" -eq 0 ]; then
108+
echo "WARNING: no result JSONs found — BP jobs may not have run or produced artifacts yet"
109+
exit 1
110+
fi

.gitlab/benchmarks/post-pr-comment.sh

Lines changed: 0 additions & 47 deletions
This file was deleted.

.gitlab/benchmarks/publish-gh-pages.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# Usage: publish-gh-pages.sh [reports-dir]
66
#
77
# Updates benchmark history and regenerates GitHub Pages site.
8-
# Reports are available at: https://datadog.github.io/async-profiler-build/benchmarks/
8+
# Reports are available at: https://datadog.github.io/java-profiler/benchmarks/
99
#
1010
# In CI: Uses Octo-STS for secure, short-lived GitHub tokens (no secrets needed)
1111
# Locally: Use 'devflow gitlab auth' for Octo-STS, or set GITHUB_TOKEN env var

.gitlab/benchmarks/steps/analyze-results.sh

Lines changed: 0 additions & 37 deletions
This file was deleted.

0 commit comments

Comments
 (0)