Skip to content

Gradle sync benchmark

Inspired by https://www.youtube.com/watch?v=O51j-RO_GQM, this workflow runs Gradle Profiler to benchmark the time it takes to sync the project every night at 3 AM and feeds it into CodeObserver.

.github/workflows/benchmark-gradle-sync

name: Benchmark Gradle sync

on:
    schedule:
        -   cron: '0 3 * * *'
    workflow_dispatch:

jobs:
    benchmark:
        runs-on: ubuntu-latest
        steps:
            -   name: Checkout
                uses: actions/checkout@v6

            -   name: Build setup
                uses: ./.github/actions/build-setup

            -   name: Install Gradle Profiler using SDKMAN
                run: |
                    curl -s "https://get.sdkman.io" | bash
                    source "$HOME/.sdkman/bin/sdkman-init.sh"
                    sdk install gradleprofiler 0.24.0
                    echo "$HOME/.sdkman/candidates/gradleprofiler/current/bin" >> $GITHUB_PATH

            -   name: Run Gradle Profiler
                run: |
                    mkdir -p profiler-results
                    gradle-profiler \
                      --gradle-user-home "$HOME/.gradle" \
                      --benchmark \
                      --output-dir profiler-results \
                      --scenario-file .github/scenarios/sync.scenarios \
                      --warmups 4 \
                      --iterations 3

            -   name: Upload results
                uses: actions/upload-artifact@v7
                with:
                    name: profiler-results
                    path: profiler-results

            -   name: Compute median build time
                id: median
                run: |
                    median_s=$(kotlin .github/scripts/get_gradle_profiler_median_seconds.main.kts)
                    echo "Median build time: ${median_s} s"
                    echo "median_s=${median_s}" >> "$GITHUB_OUTPUT"
                    echo "## 📊 Gradle Profiler Results" >> "$GITHUB_STEP_SUMMARY"
                    echo "**Median build time:** ${median_s} s" >> "$GITHUB_STEP_SUMMARY"

            -   name: CodeObserver
                uses: jacobras/CodeObserver@v0
                timeout-minutes: 5
                with:
                    command: report-build-time --name gradle-sync --time ${{ steps.median.outputs.median_s }}
                    server: ${{ secrets.CODEOBSERVER_SERVER_URL }}
                    project: your-project-id

.github/scripts/get_gradle_profiler_median_seconds.main.kts

#!/usr/bin/env kotlin

import java.io.File
import kotlin.math.roundToLong
import kotlin.system.exitProcess

val csv = File("profiler-results/benchmark.csv")

if (!csv.isFile) {
    System.err.println("benchmark.csv not found in profiler-results/")
    exitProcess(1)
}

val measuredValues: List<Double> = csv.readLines()
    .map { it.split(",").map(String::trim) }
    .filter { it.firstOrNull()?.startsWith("measured build") == true }
    .mapNotNull { it.getOrNull(1)?.toDoubleOrNull() }

if (measuredValues.isEmpty()) {
    System.err.println("No measured builds found in benchmark.csv")
    exitProcess(1)
}

val sorted = measuredValues.sorted()
val mid = sorted.size / 2
val medianMs = if (sorted.size % 2 == 1) {
    sorted[mid]
} else {
    (sorted[mid - 1] + sorted[mid]) / 2.0
}

val medianSeconds = (medianMs / 1000.0).roundToLong()
println(medianSeconds)

.github/scenarios/sync.scenarios

default - scenarios = ["build_dry_run"]
build_dry_run {
    title = "Build dry run"
    tasks = ["build"]
    gradle - args = ["--dry-run"]
    clear - configuration - cache - state - before = BUILD
}