Skip to content

Commit 812a0c1

Browse files
authored
rcmgr: make scaling changes more intuitive (#1685)
1 parent e0aff12 commit 812a0c1

File tree

3 files changed

+96
-33
lines changed

3 files changed

+96
-33
lines changed

p2p/host/resource-manager/limit.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,16 +126,18 @@ func (l *BaseLimit) Apply(l2 BaseLimit) {
126126
}
127127
}
128128

129-
// BaseLimitIncrease is the increase per GB of system memory.
129+
// BaseLimitIncrease is the increase per GiB of allowed memory.
130130
type BaseLimitIncrease struct {
131131
Streams int
132132
StreamsInbound int
133133
StreamsOutbound int
134134
Conns int
135135
ConnsInbound int
136136
ConnsOutbound int
137-
Memory int64
138-
FDFraction float64
137+
// Memory is in bytes. Values over 1>>30 (1GiB) don't make sense.
138+
Memory int64
139+
// FDFraction is expected to be >= 0 and <= 1.
140+
FDFraction float64
139141
}
140142

141143
// Apply overwrites all zero-valued limits with the values of l2

p2p/host/resource-manager/limit_defaults.go

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -255,54 +255,50 @@ func (cfg *LimitConfig) Apply(c LimitConfig) {
255255

256256
// Scale scales up a limit configuration.
257257
// memory is the amount of memory that the stack is allowed to consume,
258-
// for a full it's recommended to use 1/8 of the installed system memory.
258+
// for a dedicated node it's recommended to use 1/8 of the installed system memory.
259259
// If memory is smaller than 128 MB, the base configuration will be used.
260260
func (cfg *ScalingLimitConfig) Scale(memory int64, numFD int) LimitConfig {
261-
var scaleFactor int
262-
if memory > 128<<20 {
263-
scaleFactor = int((memory - 128<<20) >> 20)
264-
}
265261
lc := LimitConfig{
266-
System: scale(cfg.SystemBaseLimit, cfg.SystemLimitIncrease, scaleFactor, numFD),
267-
Transient: scale(cfg.TransientBaseLimit, cfg.TransientLimitIncrease, scaleFactor, numFD),
268-
AllowlistedSystem: scale(cfg.AllowlistedSystemBaseLimit, cfg.AllowlistedSystemLimitIncrease, scaleFactor, numFD),
269-
AllowlistedTransient: scale(cfg.AllowlistedTransientBaseLimit, cfg.AllowlistedTransientLimitIncrease, scaleFactor, numFD),
270-
ServiceDefault: scale(cfg.ServiceBaseLimit, cfg.ServiceLimitIncrease, scaleFactor, numFD),
271-
ServicePeerDefault: scale(cfg.ServicePeerBaseLimit, cfg.ServicePeerLimitIncrease, scaleFactor, numFD),
272-
ProtocolDefault: scale(cfg.ProtocolBaseLimit, cfg.ProtocolLimitIncrease, scaleFactor, numFD),
273-
ProtocolPeerDefault: scale(cfg.ProtocolPeerBaseLimit, cfg.ProtocolPeerLimitIncrease, scaleFactor, numFD),
274-
PeerDefault: scale(cfg.PeerBaseLimit, cfg.PeerLimitIncrease, scaleFactor, numFD),
275-
Conn: scale(cfg.ConnBaseLimit, cfg.ConnLimitIncrease, scaleFactor, numFD),
276-
Stream: scale(cfg.StreamBaseLimit, cfg.ConnLimitIncrease, scaleFactor, numFD),
262+
System: scale(cfg.SystemBaseLimit, cfg.SystemLimitIncrease, memory, numFD),
263+
Transient: scale(cfg.TransientBaseLimit, cfg.TransientLimitIncrease, memory, numFD),
264+
AllowlistedSystem: scale(cfg.AllowlistedSystemBaseLimit, cfg.AllowlistedSystemLimitIncrease, memory, numFD),
265+
AllowlistedTransient: scale(cfg.AllowlistedTransientBaseLimit, cfg.AllowlistedTransientLimitIncrease, memory, numFD),
266+
ServiceDefault: scale(cfg.ServiceBaseLimit, cfg.ServiceLimitIncrease, memory, numFD),
267+
ServicePeerDefault: scale(cfg.ServicePeerBaseLimit, cfg.ServicePeerLimitIncrease, memory, numFD),
268+
ProtocolDefault: scale(cfg.ProtocolBaseLimit, cfg.ProtocolLimitIncrease, memory, numFD),
269+
ProtocolPeerDefault: scale(cfg.ProtocolPeerBaseLimit, cfg.ProtocolPeerLimitIncrease, memory, numFD),
270+
PeerDefault: scale(cfg.PeerBaseLimit, cfg.PeerLimitIncrease, memory, numFD),
271+
Conn: scale(cfg.ConnBaseLimit, cfg.ConnLimitIncrease, memory, numFD),
272+
Stream: scale(cfg.StreamBaseLimit, cfg.ConnLimitIncrease, memory, numFD),
277273
}
278274
if cfg.ServiceLimits != nil {
279275
lc.Service = make(map[string]BaseLimit)
280276
for svc, l := range cfg.ServiceLimits {
281-
lc.Service[svc] = scale(l.BaseLimit, l.BaseLimitIncrease, scaleFactor, numFD)
277+
lc.Service[svc] = scale(l.BaseLimit, l.BaseLimitIncrease, memory, numFD)
282278
}
283279
}
284280
if cfg.ProtocolLimits != nil {
285281
lc.Protocol = make(map[protocol.ID]BaseLimit)
286282
for proto, l := range cfg.ProtocolLimits {
287-
lc.Protocol[proto] = scale(l.BaseLimit, l.BaseLimitIncrease, scaleFactor, numFD)
283+
lc.Protocol[proto] = scale(l.BaseLimit, l.BaseLimitIncrease, memory, numFD)
288284
}
289285
}
290286
if cfg.PeerLimits != nil {
291287
lc.Peer = make(map[peer.ID]BaseLimit)
292288
for p, l := range cfg.PeerLimits {
293-
lc.Peer[p] = scale(l.BaseLimit, l.BaseLimitIncrease, scaleFactor, numFD)
289+
lc.Peer[p] = scale(l.BaseLimit, l.BaseLimitIncrease, memory, numFD)
294290
}
295291
}
296292
if cfg.ServicePeerLimits != nil {
297293
lc.ServicePeer = make(map[string]BaseLimit)
298294
for svc, l := range cfg.ServicePeerLimits {
299-
lc.ServicePeer[svc] = scale(l.BaseLimit, l.BaseLimitIncrease, scaleFactor, numFD)
295+
lc.ServicePeer[svc] = scale(l.BaseLimit, l.BaseLimitIncrease, memory, numFD)
300296
}
301297
}
302298
if cfg.ProtocolPeerLimits != nil {
303299
lc.ProtocolPeer = make(map[protocol.ID]BaseLimit)
304300
for p, l := range cfg.ProtocolPeerLimits {
305-
lc.ProtocolPeer[p] = scale(l.BaseLimit, l.BaseLimitIncrease, scaleFactor, numFD)
301+
lc.ProtocolPeer[p] = scale(l.BaseLimit, l.BaseLimitIncrease, memory, numFD)
306302
}
307303
}
308304
return lc
@@ -315,20 +311,30 @@ func (cfg *ScalingLimitConfig) AutoScale() LimitConfig {
315311
)
316312
}
317313

318-
// factor is the number of MBs above the minimum (128 MB)
319-
func scale(base BaseLimit, inc BaseLimitIncrease, factor int, numFD int) BaseLimit {
314+
func scale(base BaseLimit, inc BaseLimitIncrease, memory int64, numFD int) BaseLimit {
315+
// mebibytesAvailable represents how many MiBs we're allowed to use. Used to
316+
// scale the limits. If this is below 128MiB we set it to 0 to just use the
317+
// base amounts.
318+
var mebibytesAvailable int
319+
if memory > 128<<20 {
320+
mebibytesAvailable = int((memory) >> 20)
321+
}
320322
l := BaseLimit{
321-
StreamsInbound: base.StreamsInbound + (inc.StreamsInbound*factor)>>10,
322-
StreamsOutbound: base.StreamsOutbound + (inc.StreamsOutbound*factor)>>10,
323-
Streams: base.Streams + (inc.Streams*factor)>>10,
324-
ConnsInbound: base.ConnsInbound + (inc.ConnsInbound*factor)>>10,
325-
ConnsOutbound: base.ConnsOutbound + (inc.ConnsOutbound*factor)>>10,
326-
Conns: base.Conns + (inc.Conns*factor)>>10,
327-
Memory: base.Memory + (inc.Memory*int64(factor))>>10,
323+
StreamsInbound: base.StreamsInbound + (inc.StreamsInbound*mebibytesAvailable)>>10,
324+
StreamsOutbound: base.StreamsOutbound + (inc.StreamsOutbound*mebibytesAvailable)>>10,
325+
Streams: base.Streams + (inc.Streams*mebibytesAvailable)>>10,
326+
ConnsInbound: base.ConnsInbound + (inc.ConnsInbound*mebibytesAvailable)>>10,
327+
ConnsOutbound: base.ConnsOutbound + (inc.ConnsOutbound*mebibytesAvailable)>>10,
328+
Conns: base.Conns + (inc.Conns*mebibytesAvailable)>>10,
329+
Memory: base.Memory + (inc.Memory*int64(mebibytesAvailable))>>10,
328330
FD: base.FD,
329331
}
330332
if inc.FDFraction > 0 && numFD > 0 {
331333
l.FD = int(inc.FDFraction * float64(numFD))
334+
if l.FD < base.FD {
335+
// Use at least the base amount
336+
l.FD = base.FD
337+
}
332338
}
333339
return l
334340
}

p2p/host/resource-manager/limit_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,31 @@ func TestScaling(t *testing.T) {
5959
require.Equal(t, base.Memory+4*7, scaled.Transient.Memory)
6060
})
6161

62+
t.Run("scaling and using the base amounts", func(t *testing.T) {
63+
cfg := ScalingLimitConfig{
64+
TransientBaseLimit: base,
65+
TransientLimitIncrease: BaseLimitIncrease{
66+
Streams: 1,
67+
StreamsInbound: 2,
68+
StreamsOutbound: 3,
69+
Conns: 4,
70+
ConnsInbound: 5,
71+
ConnsOutbound: 6,
72+
Memory: 7,
73+
FDFraction: 0.01,
74+
},
75+
}
76+
scaled := cfg.Scale(1, 10)
77+
require.Equal(t, 1, scaled.Transient.FD)
78+
require.Equal(t, base.Streams, scaled.Transient.Streams)
79+
require.Equal(t, base.StreamsInbound, scaled.Transient.StreamsInbound)
80+
require.Equal(t, base.StreamsOutbound, scaled.Transient.StreamsOutbound)
81+
require.Equal(t, base.Conns, scaled.Transient.Conns)
82+
require.Equal(t, base.ConnsInbound, scaled.Transient.ConnsInbound)
83+
require.Equal(t, base.ConnsOutbound, scaled.Transient.ConnsOutbound)
84+
require.Equal(t, base.Memory, scaled.Transient.Memory)
85+
})
86+
6287
t.Run("scaling limits in maps", func(t *testing.T) {
6388
cfg := ScalingLimitConfig{
6489
ServiceLimits: map[string]baseLimitConfig{
@@ -86,3 +111,33 @@ func TestScaling(t *testing.T) {
86111

87112
})
88113
}
114+
115+
func TestReadmeExample(t *testing.T) {
116+
scalingLimits := ScalingLimitConfig{
117+
SystemBaseLimit: BaseLimit{
118+
ConnsInbound: 64,
119+
ConnsOutbound: 128,
120+
Conns: 128,
121+
StreamsInbound: 512,
122+
StreamsOutbound: 1024,
123+
Streams: 1024,
124+
Memory: 128 << 20,
125+
FD: 256,
126+
},
127+
SystemLimitIncrease: BaseLimitIncrease{
128+
ConnsInbound: 32,
129+
ConnsOutbound: 64,
130+
Conns: 64,
131+
StreamsInbound: 256,
132+
StreamsOutbound: 512,
133+
Streams: 512,
134+
Memory: 256 << 20,
135+
FDFraction: 1,
136+
},
137+
}
138+
139+
limitConf := scalingLimits.Scale(4<<30, 1000)
140+
141+
require.Equal(t, 384, limitConf.System.Conns)
142+
require.Equal(t, 1000, limitConf.System.FD)
143+
}

0 commit comments

Comments
 (0)