// Copyright (C) 2024 Gradle, Inc.
//
// Licensed under the Creative Commons Attribution-Noncommercial-ShareAlike 4.0 International License.;
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://creativecommons.org/licenses/by-nc-sa/4.0/
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

[[inspecting_build_scans]]
= Inspecting Gradle Builds

++++
<div class="badge-wrapper">
    <a class="badge" href="https://dpeuniversity.gradle.com/app/courses/b5069222-cfd0-4393-b645-7a2c713853d5/" target="_blank">
        <span class="badge-type button--blue">LEARN</span>
        <span class="badge-text">How to Use a Build Scan&nbsp;&nbsp;&nbsp;&gt;</span>
    </a>
</div>
++++

Gradle provides multiple ways to inspect your build:

1. Profile with a Build Scan
2. Local profile reports
3. Low level profiling

== What is a Build Scan?

A https://scans.gradle.com/[Build Scan] is a persistent, shareable record of what happened when running a build.
They provide detailed insights you can use to diagnose performance issues, identify build failures, and share context with your team.

A Build Scan is created locally but published to a secure external server managed by Gradle.
They do not run code on your machine, and they never modify your build.
You can choose whether to publish a scan, and each scan is assigned a unique (private-by-default) URL.

NOTE: For information on what data is collected and how it's handled, see the link:https://gradle.com/privacy[Gradle.com Privacy Policy].

In Gradle 4.3 and above, you can create a Build Scan using the `--scan` command line option:

[source,bash]
----
$ gradle build --scan
----

For older Gradle versions, the
https://docs.gradle.com/develocity/gradle-plugin/current/#getting_set_up[Develocity Plugin User Manual] explains how to generate a Build Scan.

At the end of your build, Gradle displays a URL where you can find your Build Scan:

[source,text]
----
BUILD SUCCESSFUL in 2s
4 actionable tasks: 4 executed

Publishing Build Scan...
https://gradle.com/s/e6ircx2wjbf7e
----

This section explains how to profile your build with a Build Scan.

== 1. Profile with a Build Scan

The performance page can help use a Build Scan to profile a build.
To get there, click _"Performance"_ in the left hand navigation menu or follow the "Explore performance" link on the Build Scan home page:

image::performance/build-scan-home.png[title="Performance page link on Build Scan home page"]

The performance page shows how long it took to complete different stages of a build.
This page shows how long it took to:

- start up
- configure the build's projects
- resolve dependencies
- execute tasks

You also get details about environmental properties, such as whether a daemon was used or not.

[[build-scan-performance]]
image::performance/build-scan-performance-page.png[title="Build Scan performance page"]

In the above Build Scan, configuration takes over 13 seconds.
Click on the _"Configuration"_ tab to break this stage into component parts, exposing the cause of the slowness.

image::performance/build-scan-configuration-breakdown.png[title="Build Scan configuration breakdown"]

Here you can see the scripts and plugins applied to the project in descending order of how long they took to apply.
The slowest plugin and script applications are good candidates for optimization.
For example, the script `script-b.gradle` was applied once but took 3 seconds.
Expand that row to see where the build applied this script.

image::performance/script-b-application.png[title="Showing the application of script-b.gradle to the build"]

You can see that subproject `:app1` applied the script once, from inside of that subproject's `build.gradle` file.

== 2. Profile report

If you prefer not to use a Build Scan, you can generate an HTML report in the
`build/reports/profile` directory of your root project. To generate this report,
use the `--profile` command-line option:

[source,bash]
----
$ gradle --profile <tasks>
----

Each profile report has a timestamp in its name to avoid overwriting existing ones.

The report displays a breakdown of the time taken to run the build.
However, this breakdown is not as detailed as a Build Scan.
The following profile report shows the different categories available:

image::performance/gradle-profile-report.png[title="An example profile report", alt="Sample Gradle profile report"]

== 3. Low level profiling

Sometimes your build can be slow even though your build scripts do everything right.
This often comes down to inefficiencies in plugins and custom tasks or constrained resources.
Use the https://github.com/gradle/gradle-profiler[Gradle Profiler] to find these kinds of bottlenecks.
With the Gradle Profiler, you can define scenarios like "Running 'assemble' after making an ABI-breaking change" and run your build several times to collect profiling data.
Use the Profiler to produce a Build Scan. Or combine it with method profilers like JProfiler and YourKit.
These profilers can help you find inefficient algorithms in custom plugins.
If you find that something in Gradle itself slows down your build, don't hesitate to send a profiler snapshot to performance@gradle.com.

== Performance categories

Both a Build Scan and local profile reports break down build execution into the same categories.
The following sections explain those categories.

=== Startup

This reflects Gradle’s initialization time, which consists mostly of:

- JVM initialization and class loading
- Downloading the Gradle distribution if you’re using the wrapper
- Starting the daemon if a suitable one isn’t already running
- Executing Gradle initialization scripts

Even when a build execution has a long startup time, subsequent runs usually see a dramatic drop off in startup time.
Persistently slow build startup times are usually the result of problems in your init scripts.
Double check that the work you’re doing there is necessary and performant.

=== Settings and _buildSrc_

After startup, Gradle initializes your project. Usually, Gradle only processes your settings file.
If you have custom build logic in a `buildSrc` directory, Gradle also processes that logic.
After building `buildSrc` once, Gradle considers it up to date. The up-to-date checks take significantly less time than logic processing.
If your `buildSrc` phase takes too much time, consider breaking it out into a separate project.
You can then add that project's JAR artifact as a dependency.

The settings file rarely contains code with significant I/O or computation.
If you find that Gradle takes a long time to process it, use more traditional profiling methods, like the https://github.com/gradle/gradle-profiler[Gradle Profiler], to determine the cause.

=== Loading projects

It normally doesn’t take a significant amount of time to load projects, nor do you have any control over it.
The time spent here is basically a function of the number of projects you have in your build.
