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:
Reapor-Yurnero
2020-05-20 22:50:07 -07:00
committed by gVisor bot
parent 8298c5bd4d
commit 059879e143
8 changed files with 792 additions and 66 deletions
+2
View File
@@ -21,6 +21,8 @@ go_template(
],
opt_consts = [
"minDegree",
# trackGaps must either be 0 or 1.
"trackGaps",
],
types = [
"Key",
+395 -5
View File
File diff suppressed because it is too large Load Diff
+18
View File
@@ -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
+22 -10
View File
@@ -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
}
+1
View File
@@ -25,6 +25,7 @@ go_template_instance(
out = "vma_set.go",
consts = {
"minDegree": "8",
"trackGaps": "1",
},
imports = {
"usermem": "gvisor.dev/gvisor/pkg/usermem",
+2 -2
View File
@@ -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)
+3 -1
View File
@@ -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 {