How would you set up a lightweight, account-free build-timing measurement step in CI using these flags, and what would you capture from it?
answer
- --profile HTML archived as artifact
- tasks.stats -> tee log, cache-outcome KPI
- --dry-run vs golden file = graph-drift gate
- keep heavy diagnostic off every PR (nightly/label)
- escalate to scans for correlation
basics
~10 sAdd a diagnostic build invocation with --profile to archive the HTML report as a CI artifact, and optionally -Dorg.gradle.internal.tasks.stats=true to log aggregated task-type/outcome stats. Capture the report and the log for trend review.
solid answer
~40 sA pragmatic, no-account setup: in a CI job (or a periodic diagnostic job) run the build with `--profile` and publish `build/reports/profile/*.html` as a build artifact so anyone can open per-phase, per-task timings after the fact. Layer `-Dorg.gradle.internal.tasks.stats=true` and `tee` the console so the log carries an aggregate by task type and by outcome (EXECUTED / UP-TO-DATE / FROM-CACHE) — the single best signal for cache effectiveness across runs. Use `--dry-run` separately as a fast sanity gate that the expected task graph hasn't drifted (e.g. an unintended `finalizedBy`). Keep the heavy diagnostic invocation off the hot path of every PR (it adds noise/time); run it on a schedule or label. For richer cross-build correlation you'd graduate to build scans, but this gets you 80% locally and free.
code
bash · 5 lines./gradlew build \
--profile \
-Dorg.gradle.internal.tasks.stats=true \
2>&1 | tee build-diagnostic.log
# CI archives: build/reports/profile/*.html and build-diagnostic.loggo deeper
Know --profile produces an archivable HTML report you can attach in CI.
Combine --profile (artifact) with tasks.stats (log) and explain what each captures.
Design where the diagnostic runs (nightly/label vs every PR), pick the cache-effectiveness KPI, and know when to escalate to scans.
Own a measurement strategy: free local tier vs Develocity, trend ownership, guardrails against misleading snapshots, and graph-drift gating policy.
## Goal Get actionable timing signal in CI without a Develocity/scan account, cheaply, and in a form people will actually read. ## The three flags, mapped to CI roles - **`--profile`** → produces `build/reports/profile/profile-<ts>.html`. Archive it as a CI artifact. It's self-contained, so reviewers just download and open — phase breakdown (configuration / dependency resolution / execution) plus sortable per-task durations. - **`-Dorg.gradle.internal.tasks.stats=true`** → console aggregate by task **type** and **outcome**. `tee` it into a log artifact. The outcome distribution (how many tasks were FROM-CACHE / UP-TO-DATE vs EXECUTED) is your cache-effectiveness KPI; track it run over run. - **`--dry-run`** → fast graph-shape gate. Compare the printed task list against a checked-in golden file to catch accidental wiring drift, without executing anything. ## What to capture 1. The `--profile` HTML (artifact) — for ad-hoc human drill-down. 2. The `tasks.stats` console block (log artifact) — for the cache/up-to-date outcome ratios. 3. Total wall-clock build time (from CI itself) — the headline trend. ## Where to run it Don't bolt the heavy diagnostic onto every PR build — it lengthens feedback and adds noise. Patterns: - A **nightly/scheduled** diagnostic job on the main branch. - A **`perf` label** that opt-in enables the diagnostic invocation on a PR. ## Example CI step ```bash # Diagnostic build: profile report + aggregated task stats ./gradlew build \ --profile \ -Dorg.gradle.internal.tasks.stats=true \ 2>&1 | tee build-diagnostic.log # Then have CI archive these as artifacts: # build/reports/profile/*.html # build-diagnostic.log ``` ## Caveats and escalation - `tasks.stats` is **internal/unstable** — don't parse it programmatically as a hard gate; use it as a human/trend signal. - `--profile` is a single-invocation snapshot; for cross-build correlation, cache-miss root-causing, and sharing, build scans are the next rung. - Make sure the diagnostic run reflects realistic conditions (warm vs cold cache) or you'll draw the wrong conclusions. ## The mental model Local flags give you a cheap, free first tier of observability: `--dry-run` guards graph shape, `--profile` shows where time went, `tasks.stats` shows reuse health. Escalate to scans only when you need correlation or sharing.
- Why not run the full diagnostic on every PR?It lengthens feedback time and adds console noise, and the snapshot value is low per-PR. A scheduled/main-branch run or an opt-in label gives the trend signal without taxing every contributor.
- Which captured signal best tracks cache effectiveness over time?The outcome distribution from tasks.stats — the ratio of FROM-CACHE / UP-TO-DATE to EXECUTED tasks. A drift toward EXECUTED flags degrading reuse.
- When would you move beyond these flags?When you need to correlate across many builds, root-cause individual cache misses, or share results with a team — that's when build scans / Develocity earn their keep.
saying these in an interview costs you the question
- Hard-gating CI on parsed tasks.stats output (internal/unstable format).
- Running the heavy diagnostic on every PR and slowing everyone's feedback loop.
- Comparing profile timings across runs with inconsistent cache warmth and drawing false conclusions.