<p>I checked out the Jenkins source code, and I believe Jenkins uses the last 3 <em>successful</em> or <em>unstable</em> builds for its estimation. If it out of the last 6 builds it can't find 3 <em>successful</em> or <em>unstable</em> builds, it uses 1 or more of the last <em>completed</em> (not aborted) builds. It then takes the total duration time of the "candidates" and simply divides it by the number of candidates (i.e. mean of the durations). Here is the code I based this off of that can be found in the Job.java file in the <a href="https://github.com/jenkinsci/jenkins" rel="nofollow noreferrer">Jenkins repo</a>:</p>

<pre><code>    /**
     * Returns candidate build for calculating the estimated duration of the current run.
     * 
     * Returns the 3 last successful (stable or unstable) builds, if there are any.
     * Failing to find 3 of those, it will return up to 3 last unsuccessful builds.
     * 
     * In any case it will not go more than 6 builds into the past to avoid costly build loading.
     */
    @SuppressWarnings("unchecked")
    protected List&lt;RunT&gt; getEstimatedDurationCandidates() {
        List&lt;RunT&gt; candidates = new ArrayList&lt;RunT&gt;(3);
        RunT lastSuccessful = getLastSuccessfulBuild();
        int lastSuccessfulNumber = -1;
        if (lastSuccessful != null) {
            candidates.add(lastSuccessful);
            lastSuccessfulNumber = lastSuccessful.getNumber();
        }

        int i = 0;
        RunT r = getLastBuild();
        List&lt;RunT&gt; fallbackCandidates = new ArrayList&lt;RunT&gt;(3);
        while (r != null &amp;&amp; candidates.size() &lt; 3 &amp;&amp; i &lt; 6) {
            if (!r.isBuilding() &amp;&amp; r.getResult() != null &amp;&amp; r.getNumber() != lastSuccessfulNumber) {
                Result result = r.getResult();
                if (result.isBetterOrEqualTo(Result.UNSTABLE)) {
                    candidates.add(r);
                } else if (result.isCompleteBuild()) {
                    fallbackCandidates.add(r);
                }
            }
            i++;
            r = r.getPreviousBuild();
        }

        while (candidates.size() &lt; 3) {
            if (fallbackCandidates.isEmpty())
                break;
            RunT run = fallbackCandidates.remove(0);
            candidates.add(run);
        }

        return candidates;
    }

    public long getEstimatedDuration() {
        List&lt;RunT&gt; builds = getEstimatedDurationCandidates();

        if(builds.isEmpty())     return -1;

        long totalDuration = 0;
        for (RunT b : builds) {
            totalDuration += b.getDuration();
        }
        if(totalDuration==0) return -1;

        return Math.round((double)totalDuration / builds.size());
    }
</code></pre>

CC BY-SA 3.0
2018-03-29T15:17:01.403Z
That clears things up nicely, thank you! Still odd that the bars aren't resolving when they've already run 2-3+ times on the new Jenkins, but at least I know how the behavior is expected to work. Something to keep an eye on I guess
Alex
CC BY-SA 3.0
2018-03-29T15:26:59.553Z
Glad I could help! I have always wondered how Jenkins derives these estimates. Your question gave me an excuse to look into it :) As for why you are seeing the wrong estimation, I always check plugin compatibility whenever I update Jenkins. Seemingly unrelated plugins can sometimes cause compatibility issues with other Jenkins components.
Preston Martin
CC BY-SA 3.0
2018-03-29T15:32:17.003Z
Very true. 030 had a good point about Blue Ocean, it seems like they're always to blame when we get weird gui errors. I'll have to do some testing and find out!
Alex
CC BY-SA 3.0
2018-03-29T15:12:42.347Z
2018-04-02T13:27:51.740Z
2018-04-02T13:27:51.740Z
Preston Martin
<p>We just updated our Jenkins to v2.207.1 and our build estimation times on pipeline jobs have stopped showing up. Rather than a blue bar that when hovered over shows an estimate, we are now seeing the blue-and-white striped barber pole and an estimation of N/A. </p>

<p>I believe this behavior might be only on pipeline jobs - we have so few freestyle jobs that I haven't seen them run yet.</p>

<p>What logic does Jenkins use to calculate those estimations? How many builds will we need before those times fill back in?</p>

CC BY-SA 3.0
2018-03-29T14:35:32.217Z
For freestyle or pipelines? Do you use bleuocean?
030
CC BY-SA 3.0
2018-03-29T14:39:56.327Z
@030 Pipelines, as said. And yes we do use blueocean but this is not in the BO interface, but in regular jenkins.
Alex
<jenkins>
How many builds does jenkins need to run before it has estimated times?
Alex
# How many builds does jenkins need to run before it has estimated times?

(Asked by: username_0 on 2018-03-29)

We just updated our Jenkins to v2.207.1 and our build estimation times on pipeline jobs have stopped showing up. Rather than a blue bar that when hovered over shows an estimate, we are now seeing the blue-and-white striped barber pole and an estimation of N/A.

I believe this behavior might be only on pipeline jobs - we have so few freestyle jobs that I haven't seen them run yet.

What logic does Jenkins use to calculate those estimations? How many builds will we need before those times fill back in?

**Tags:** jenkins

> **Comments:**
> **username_1**: For freestyle or pipelines? Do you use bleuocean?  
> **username_0**: @username_1 Pipelines, as said. And yes we do use blueocean but this is not in the BO interface, but in regular jenkins.  

---

## 1 answers

### Answer by username_2 on 2018-03-29. Score: 5 | Accepted answer

I checked out the Jenkins source code, and I believe Jenkins uses the last 3 successful or unstable builds for its estimation. If it out of the last 6 builds it can't find 3 successful or unstable builds, it uses 1 or more of the last completed (not aborted) builds. It then takes the total duration time of the "candidates" and simply divides it by the number of candidates (i.e. mean of the durations). Here is the code I based this off of that can be found in the Job.java file in the Jenkins repo:
    /**
     * Returns candidate build for calculating the estimated duration of the current run.
     * 
     * Returns the 3 last successful (stable or unstable) builds, if there are any.
     * Failing to find 3 of those, it will return up to 3 last unsuccessful builds.
     * 
     * In any case it will not go more than 6 builds into the past to avoid costly build loading.
     */
    @SuppressWarnings("unchecked")
    protected List getEstimatedDurationCandidates() {
        List candidates = new ArrayList(3);
        RunT lastSuccessful = getLastSuccessfulBuild();
        int lastSuccessfulNumber = -1;
        if (lastSuccessful != null) {
            candidates.add(lastSuccessful);
            lastSuccessfulNumber = lastSuccessful.getNumber();
        }

        int i = 0;
        RunT r = getLastBuild();
        List fallbackCandidates = new ArrayList(3);
        while (r != null && candidates.size() < 3 && i < 6) {
            if (!r.isBuilding() && r.getResult() != null && r.getNumber() != lastSuccessfulNumber) {
                Result result = r.getResult();
                if (result.isBetterOrEqualTo(Result.UNSTABLE)) {
                    candidates.add(r);
                } else if (result.isCompleteBuild()) {
                    fallbackCandidates.add(r);
                }
            }
            i++;
            r = r.getPreviousBuild();
        }

        while (candidates.size() < 3) {
            if (fallbackCandidates.isEmpty())
                break;
            RunT run = fallbackCandidates.remove(0);
            candidates.add(run);
        }

        return candidates;
    }

    public long getEstimatedDuration() {
        List builds = getEstimatedDurationCandidates();

        if(builds.isEmpty())     return -1;

        long totalDuration = 0;
        for (RunT b : builds) {
            totalDuration += b.getDuration();
        }
        if(totalDuration==0) return -1;

        return Math.round((double)totalDuration / builds.size());
    }

> **Comments:**
> **username_0**: That clears things up nicely, thank you! Still odd that the bars aren't resolving when they've already run 2-3+ times on the new Jenkins, but at least I know how the behavior is expected to work. Something to keep an eye on I guess  
> **username_2**: Glad I could help! I have always wondered how Jenkins derives these estimates. Your question gave me an excuse to look into it :) As for why you are seeing the wrong estimation, I always check plugin compatibility whenever I update Jenkins. Seemingly unrelated plugins can sometimes cause compatibility issues with other Jenkins components.  
> **username_0**: Very true. username_1 had a good point about Blue Ocean, it seems like they're always to blame when we get weird gui errors. I'll have to do some testing and find out!  

---

