Skip to content

Support high build time variation in progress bar #4941

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Nov 17, 2022
Prev Previous commit
Next Next commit
Refactor to use percentiles
  • Loading branch information
ammario committed Nov 17, 2022
commit 6f914a41a8f2f509dbcc2bdd4d8dcf62934d06b4
31 changes: 5 additions & 26 deletions coderd/database/databasefake/databasefake.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package databasefake
import (
"context"
"database/sql"
"math"
"sort"
"strings"
"sync"
Expand Down Expand Up @@ -277,38 +276,18 @@ func (q *fakeQuerier) GetTemplateAverageBuildTime(ctx context.Context, arg datab
}
}

tryMedian := func(fs []float64) float64 {
tryPercentile := func(fs []float64, p float64) float64 {
if len(fs) == 0 {
return -1
}
sort.Float64s(fs)
return fs[len(fs)/2]
}

tryStddev := func(fs []float64) float64 {
if len(fs) == 0 {
return -1
}
var sum float64
for _, f := range fs {
sum += f
}
mean := sum / float64(len(fs))

var sumSqDiff float64
for _, f := range fs {
sumSqDiff += math.Pow(mean-f, 2)
}
return sumSqDiff / float64(len(fs))
return fs[int(float64(len(fs))*p/100)]
}

var row database.GetTemplateAverageBuildTimeRow
row.DeleteMedian = tryMedian(deleteTimes)
row.DeleteStddev = tryStddev(deleteTimes)
row.StopMedian = tryMedian(stopTimes)
row.StopStddev = tryStddev(stopTimes)
row.StartMedian = tryMedian(startTimes)
row.StartStddev = tryStddev(startTimes)
row.Delete50, row.Delete95 = tryPercentile(deleteTimes, 50), tryPercentile(deleteTimes, 95)
row.Stop50, row.Stop95 = tryPercentile(stopTimes, 50), tryPercentile(stopTimes, 95)
row.Start50, row.Start95 = tryPercentile(startTimes, 50), tryPercentile(startTimes, 95)
return row, nil
}

Expand Down
36 changes: 18 additions & 18 deletions coderd/database/queries.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions coderd/database/queries/templates.sql
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,11 @@ ORDER BY
SELECT
-- Postgres offers no clear way to DRY this short of a function or other
-- complexities.
coalesce((PERCENTILE_DISC(0.5) WITHIN GROUP(ORDER BY exec_time_sec) FILTER (WHERE transition = 'start')), -1)::FLOAT AS start_median,
coalesce((PERCENTILE_DISC(0.5) WITHIN GROUP(ORDER BY exec_time_sec) FILTER (WHERE transition = 'stop')), -1)::FLOAT AS stop_median,
coalesce((PERCENTILE_DISC(0.5) WITHIN GROUP(ORDER BY exec_time_sec) FILTER (WHERE transition = 'delete')), -1)::FLOAT AS delete_median,
coalesce((stddev(exec_time_sec) FILTER (WHERE transition = 'start')), -1)::FLOAT AS start_stddev,
coalesce((stddev(exec_time_sec) FILTER (WHERE transition = 'stop')), -1)::FLOAT AS stop_stddev,
coalesce((stddev(exec_time_sec) FILTER (WHERE transition = 'delete')), -1)::FLOAT AS delete_stddev
coalesce((PERCENTILE_DISC(0.5) WITHIN GROUP(ORDER BY exec_time_sec) FILTER (WHERE transition = 'start')), -1)::FLOAT AS start_50,
coalesce((PERCENTILE_DISC(0.5) WITHIN GROUP(ORDER BY exec_time_sec) FILTER (WHERE transition = 'stop')), -1)::FLOAT AS stop_50,
coalesce((PERCENTILE_DISC(0.5) WITHIN GROUP(ORDER BY exec_time_sec) FILTER (WHERE transition = 'delete')), -1)::FLOAT AS delete_50,
coalesce((PERCENTILE_DISC(0.95) WITHIN GROUP(ORDER BY exec_time_sec) FILTER (WHERE transition = 'start')), -1)::FLOAT AS start_95,
coalesce((PERCENTILE_DISC(0.95) WITHIN GROUP(ORDER BY exec_time_sec) FILTER (WHERE transition = 'stop')), -1)::FLOAT AS stop_95,
coalesce((PERCENTILE_DISC(0.95) WITHIN GROUP(ORDER BY exec_time_sec) FILTER (WHERE transition = 'delete')), -1)::FLOAT AS delete_95
FROM build_times
;
12 changes: 6 additions & 6 deletions coderd/metricscache/metricscache.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,16 +270,16 @@ func (c *Cache) TemplateBuildTimeStats(id uuid.UUID) codersdk.TemplateBuildTimeS

return codersdk.TemplateBuildTimeStats{
codersdk.WorkspaceTransitionStart: {
Median: convertMillis(resp.StartMedian),
Stddev: convertMillis(resp.StartStddev),
P50: convertMillis(resp.Start50),
P95: convertMillis(resp.Start95),
},
codersdk.WorkspaceTransitionStop: {
Median: convertMillis(resp.StopMedian),
Stddev: convertMillis(resp.StopStddev),
P50: convertMillis(resp.Stop50),
P95: convertMillis(resp.Stop95),
},
codersdk.WorkspaceTransitionDelete: {
Median: convertMillis(resp.DeleteMedian),
Stddev: convertMillis(resp.DeleteStddev),
P50: convertMillis(resp.Delete50),
P95: convertMillis(resp.Delete95),
},
}
}
11 changes: 7 additions & 4 deletions coderd/metricscache/metricscache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,18 +344,21 @@ func TestCache_BuildTime(t *testing.T) {
gotStats = cache.TemplateBuildTimeStats(template.ID)
for transition, stats := range gotStats {
if transition == wantTransition {
require.Equal(t, tt.want.buildTimeMs, *stats.Median)
require.Equal(t, tt.want.buildTimeMs, *stats.P50)
} else {
require.Empty(t, stats)
require.Empty(
t, stats, "%v", transition,
)
}
}
} else {
var stats codersdk.TemplateBuildTimeStats
require.Never(t, func() bool {
stats := cache.TemplateBuildTimeStats(template.ID)
stats = cache.TemplateBuildTimeStats(template.ID)
requireBuildTimeStatsEmpty(t, stats)
return t.Failed()
}, testutil.WaitShort/2, testutil.IntervalMedium,
"BuildTimeStats populated",
"BuildTimeStats populated", stats,
)
}
})
Expand Down
2 changes: 1 addition & 1 deletion coderd/templates_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,7 @@ func TestTemplateMetrics(t *testing.T) {
require.Eventuallyf(t, func() bool {
template, err = client.Template(ctx, template.ID)
require.NoError(t, err)
startMs := template.BuildTimeStats[codersdk.WorkspaceTransitionStart].Median
startMs := template.BuildTimeStats[codersdk.WorkspaceTransitionStart].P50
return startMs != nil && *startMs > 1
},
testutil.WaitShort, testutil.IntervalFast,
Expand Down
4 changes: 2 additions & 2 deletions codersdk/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ type Template struct {
}

type TransitionStats struct {
Median *int64
Stddev *int64
P50 *int64
P95 *int64
}

type TemplateBuildTimeStats map[WorkspaceTransition]TransitionStats
Expand Down