4
4
5
5
package cpulimit
6
6
7
- // TODO(cw):
8
- // - introduce metrics that report
9
- // - total throttled period count (per QoS)
10
- // - total bandwidth granted (per QoS)
11
- // - something that corresponds to the user experience
12
-
13
7
import (
14
8
"context"
15
9
"sort"
@@ -37,7 +31,7 @@ type WorkspaceHistory struct {
37
31
38
32
func (h * WorkspaceHistory ) Usage () CPUTime {
39
33
if h == nil || h .LastUpdate == nil {
40
- panic ( "usage called before update" )
34
+ return 0
41
35
}
42
36
return h .LastUpdate .Usage - h .UsageT0
43
37
}
@@ -60,26 +54,26 @@ func (h *WorkspaceHistory) Throttled() bool {
60
54
}
61
55
62
56
type DistributorSource func (context.Context ) ([]Workspace , error )
63
- type DistributorSink func (workspaceID string , limit Bandwidth )
57
+ type DistributorSink func (id string , limit Bandwidth , burst bool )
64
58
65
- func NewDistributor (source DistributorSource , sink DistributorSink , limiter ResourceLimiter , breakoutLimiter ResourceLimiter , totalBandwidth Bandwidth ) * Distributor {
59
+ func NewDistributor (source DistributorSource , sink DistributorSink , limiter ResourceLimiter , burstLimiter ResourceLimiter , totalBandwidth Bandwidth ) * Distributor {
66
60
return & Distributor {
67
- Source : source ,
68
- Sink : sink ,
69
- Limiter : limiter ,
70
- BreakoutLimiter : breakoutLimiter ,
71
- TotalBandwidth : totalBandwidth ,
72
- History : make (map [string ]* WorkspaceHistory ),
61
+ Source : source ,
62
+ Sink : sink ,
63
+ Limiter : limiter ,
64
+ BurstLimiter : burstLimiter ,
65
+ TotalBandwidth : totalBandwidth ,
66
+ History : make (map [string ]* WorkspaceHistory ),
73
67
}
74
68
}
75
69
76
70
type Distributor struct {
77
71
Source DistributorSource
78
72
Sink DistributorSink
79
73
80
- History map [string ]* WorkspaceHistory
81
- Limiter ResourceLimiter
82
- BreakoutLimiter ResourceLimiter
74
+ History map [string ]* WorkspaceHistory
75
+ Limiter ResourceLimiter
76
+ BurstLimiter ResourceLimiter
83
77
84
78
// TotalBandwidth is the total CPU time available in nanoseconds per second
85
79
TotalBandwidth Bandwidth
@@ -90,7 +84,7 @@ type Distributor struct {
90
84
}
91
85
92
86
type DistributorDebug struct {
93
- BandwidthAvail , BandwidthUsed , BandwidthBreakout Bandwidth
87
+ BandwidthAvail , BandwidthUsed , BandwidthBurst Bandwidth
94
88
}
95
89
96
90
// Run starts a ticker which repeatedly calls Tick until the context is canceled.
@@ -175,7 +169,7 @@ func (d *Distributor) Tick(dt time.Duration) (DistributorDebug, error) {
175
169
d .LastTickUsage = totalUsage
176
170
177
171
// enforce limits
178
- var breakoutBandwidth Bandwidth
172
+ var burstBandwidth Bandwidth
179
173
for _ , id := range wsOrder {
180
174
ws := d .History [id ]
181
175
limit := d .Limiter .Limit (ws .Usage ())
@@ -184,24 +178,25 @@ func (d *Distributor) Tick(dt time.Duration) (DistributorDebug, error) {
184
178
// and there's still some bandwidth left to give, let's act as if had
185
179
// never spent any CPU time and assume the workspace will spend their
186
180
// entire bandwidth at once.
181
+ var burst bool
187
182
if totalBandwidth < d .TotalBandwidth && ws .Throttled () {
188
- limit = d .BreakoutLimiter .Limit (ws .Usage ())
183
+ limit = d .BurstLimiter .Limit (ws .Usage ())
189
184
190
185
// We assume the workspace is going to use as much as their limit allows.
191
186
// This might not be true, because their process which consumed so much CPU
192
187
// may have ended by now.
193
188
totalBandwidth += limit
194
189
195
- breakoutBandwidth += limit
190
+ burstBandwidth += limit
196
191
}
197
192
198
- d .Sink (id , limit )
193
+ d .Sink (id , limit , burst )
199
194
}
200
195
201
196
return DistributorDebug {
202
- BandwidthAvail : d .TotalBandwidth ,
203
- BandwidthUsed : totalBandwidth ,
204
- BandwidthBreakout : breakoutBandwidth ,
197
+ BandwidthAvail : d .TotalBandwidth ,
198
+ BandwidthUsed : totalBandwidth ,
199
+ BandwidthBurst : burstBandwidth ,
205
200
}, nil
206
201
}
207
202
0 commit comments