mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Implement gap tracking in the segment set.
This change was derived from a change by: Reapor-Yurnero <reapor.yurnero@gmail.com> And has been modified by: Adin Scannell <ascannell@google.com> (The original change author is preserved for the commit.) This change implements gap tracking in the segment set by adding additional information in each node, and using that information to speed up gap finding from a linear scan to a O(log(n)) walk of the tree. This gap tracking is optional, and will default to off except for segment instances that set gapTracking equal to 1 in their const lists. PiperOrigin-RevId: 312621607
This commit is contained in:
committed by
gVisor bot
parent
8298c5bd4d
commit
059879e143
@@ -21,6 +21,8 @@ go_template(
|
||||
],
|
||||
opt_consts = [
|
||||
"minDegree",
|
||||
# trackGaps must either be 0 or 1.
|
||||
"trackGaps",
|
||||
],
|
||||
types = [
|
||||
"Key",
|
||||
|
||||
+395
-5
File diff suppressed because it is too large
Load Diff
@@ -29,10 +29,28 @@ go_template_instance(
|
||||
},
|
||||
)
|
||||
|
||||
go_template_instance(
|
||||
name = "gap_set",
|
||||
out = "gap_set.go",
|
||||
consts = {
|
||||
"trackGaps": "1",
|
||||
},
|
||||
package = "segment",
|
||||
prefix = "gap",
|
||||
template = "//pkg/segment:generic_set",
|
||||
types = {
|
||||
"Key": "int",
|
||||
"Range": "Range",
|
||||
"Value": "int",
|
||||
"Functions": "gapSetFunctions",
|
||||
},
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "segment",
|
||||
testonly = 1,
|
||||
srcs = [
|
||||
"gap_set.go",
|
||||
"int_range.go",
|
||||
"int_set.go",
|
||||
"set_functions.go",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,21 +14,16 @@
|
||||
|
||||
package segment
|
||||
|
||||
// Basic numeric constants that we define because the math package doesn't.
|
||||
// TODO(nlacasse): These should be Math.MaxInt64/MinInt64?
|
||||
const (
|
||||
maxInt = int(^uint(0) >> 1)
|
||||
minInt = -maxInt - 1
|
||||
)
|
||||
|
||||
type setFunctions struct{}
|
||||
|
||||
func (setFunctions) MinKey() int {
|
||||
return minInt
|
||||
// MinKey returns the minimum key for the set.
|
||||
func (s setFunctions) MinKey() int {
|
||||
return -s.MaxKey() - 1
|
||||
}
|
||||
|
||||
// MaxKey returns the maximum key for the set.
|
||||
func (setFunctions) MaxKey() int {
|
||||
return maxInt
|
||||
return int(^uint(0) >> 1)
|
||||
}
|
||||
|
||||
func (setFunctions) ClearValue(*int) {}
|
||||
@@ -40,3 +35,20 @@ func (setFunctions) Merge(_ Range, val1 int, _ Range, _ int) (int, bool) {
|
||||
func (setFunctions) Split(_ Range, val int, _ int) (int, int) {
|
||||
return val, val
|
||||
}
|
||||
|
||||
type gapSetFunctions struct {
|
||||
setFunctions
|
||||
}
|
||||
|
||||
// MinKey is adjusted to make sure no add overflow would happen in test cases.
|
||||
// e.g. A gap with range {MinInt32, 2} would cause overflow in Range().Length().
|
||||
//
|
||||
// Normally Keys should be unsigned to avoid these issues.
|
||||
func (s gapSetFunctions) MinKey() int {
|
||||
return s.setFunctions.MinKey() / 2
|
||||
}
|
||||
|
||||
// MaxKey returns the maximum key for the set.
|
||||
func (s gapSetFunctions) MaxKey() int {
|
||||
return s.setFunctions.MaxKey() / 2
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ go_template_instance(
|
||||
out = "vma_set.go",
|
||||
consts = {
|
||||
"minDegree": "8",
|
||||
"trackGaps": "1",
|
||||
},
|
||||
imports = {
|
||||
"usermem": "gvisor.dev/gvisor/pkg/usermem",
|
||||
|
||||
@@ -195,7 +195,7 @@ func (mm *MemoryManager) applicationAddrRange() usermem.AddrRange {
|
||||
|
||||
// Preconditions: mm.mappingMu must be locked.
|
||||
func (mm *MemoryManager) findLowestAvailableLocked(length, alignment uint64, bounds usermem.AddrRange) (usermem.Addr, error) {
|
||||
for gap := mm.vmas.LowerBoundGap(bounds.Start); gap.Ok() && gap.Start() < bounds.End; gap = gap.NextGap() {
|
||||
for gap := mm.vmas.LowerBoundGap(bounds.Start); gap.Ok() && gap.Start() < bounds.End; gap = gap.NextLargeEnoughGap(usermem.Addr(length)) {
|
||||
if gr := gap.availableRange().Intersect(bounds); uint64(gr.Length()) >= length {
|
||||
// Can we shift up to match the alignment?
|
||||
if offset := uint64(gr.Start) % alignment; offset != 0 {
|
||||
@@ -214,7 +214,7 @@ func (mm *MemoryManager) findLowestAvailableLocked(length, alignment uint64, bou
|
||||
|
||||
// Preconditions: mm.mappingMu must be locked.
|
||||
func (mm *MemoryManager) findHighestAvailableLocked(length, alignment uint64, bounds usermem.AddrRange) (usermem.Addr, error) {
|
||||
for gap := mm.vmas.UpperBoundGap(bounds.End); gap.Ok() && gap.End() > bounds.Start; gap = gap.PrevGap() {
|
||||
for gap := mm.vmas.UpperBoundGap(bounds.End); gap.Ok() && gap.End() > bounds.Start; gap = gap.PrevLargeEnoughGap(usermem.Addr(length)) {
|
||||
if gr := gap.availableRange().Intersect(bounds); uint64(gr.Length()) >= length {
|
||||
// Can we shift down to match the alignment?
|
||||
start := gr.End - usermem.Addr(length)
|
||||
|
||||
@@ -223,7 +223,9 @@ func main() {
|
||||
} else {
|
||||
switch kind {
|
||||
case globals.KindType, globals.KindVar, globals.KindConst, globals.KindFunction:
|
||||
ident.Name = *prefix + ident.Name + *suffix
|
||||
if ident.Name != "_" {
|
||||
ident.Name = *prefix + ident.Name + *suffix
|
||||
}
|
||||
case globals.KindTag:
|
||||
// Modify the state tag appropriately.
|
||||
if m := stateTagRegexp.FindStringSubmatch(ident.Name); m != nil {
|
||||
|
||||
Reference in New Issue
Block a user