|  | // Copyright 2020 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package runtime_test | 
|  |  | 
|  | import ( | 
|  | . "runtime" | 
|  | "testing" | 
|  | ) | 
|  |  | 
|  | func validateAddrRanges(t *testing.T, a *AddrRanges, want ...AddrRange) { | 
|  | ranges := a.Ranges() | 
|  | if len(ranges) != len(want) { | 
|  | t.Errorf("want %v, got %v", want, ranges) | 
|  | t.Fatal("different lengths") | 
|  | } | 
|  | gotTotalBytes := uintptr(0) | 
|  | wantTotalBytes := uintptr(0) | 
|  | for i := range ranges { | 
|  | gotTotalBytes += ranges[i].Size() | 
|  | wantTotalBytes += want[i].Size() | 
|  | if ranges[i].Base() >= ranges[i].Limit() { | 
|  | t.Error("empty range found") | 
|  | } | 
|  | // Ensure this is equivalent to what we want. | 
|  | if !ranges[i].Equals(want[i]) { | 
|  | t.Errorf("range %d: got [0x%x, 0x%x), want [0x%x, 0x%x)", i, | 
|  | ranges[i].Base(), ranges[i].Limit(), | 
|  | want[i].Base(), want[i].Limit(), | 
|  | ) | 
|  | } | 
|  | if i != 0 { | 
|  | // Ensure the ranges are sorted. | 
|  | if ranges[i-1].Base() >= ranges[i].Base() { | 
|  | t.Errorf("ranges %d and %d are out of sorted order", i-1, i) | 
|  | } | 
|  | // Check for a failure to coalesce. | 
|  | if ranges[i-1].Limit() == ranges[i].Base() { | 
|  | t.Errorf("ranges %d and %d should have coalesced", i-1, i) | 
|  | } | 
|  | // Check if any ranges overlap. Because the ranges are sorted | 
|  | // by base, it's sufficient to just check neighbors. | 
|  | if ranges[i-1].Limit() > ranges[i].Base() { | 
|  | t.Errorf("ranges %d and %d overlap", i-1, i) | 
|  | } | 
|  | } | 
|  | } | 
|  | if wantTotalBytes != gotTotalBytes { | 
|  | t.Errorf("expected %d total bytes, got %d", wantTotalBytes, gotTotalBytes) | 
|  | } | 
|  | if b := a.TotalBytes(); b != gotTotalBytes { | 
|  | t.Errorf("inconsistent total bytes: want %d, got %d", gotTotalBytes, b) | 
|  | } | 
|  | if t.Failed() { | 
|  | t.Errorf("addrRanges: %v", ranges) | 
|  | t.Fatal("detected bad addrRanges") | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestAddrRangesAdd(t *testing.T) { | 
|  | a := NewAddrRanges() | 
|  |  | 
|  | // First range. | 
|  | a.Add(MakeAddrRange(512, 1024)) | 
|  | validateAddrRanges(t, &a, | 
|  | MakeAddrRange(512, 1024), | 
|  | ) | 
|  |  | 
|  | // Coalesce up. | 
|  | a.Add(MakeAddrRange(1024, 2048)) | 
|  | validateAddrRanges(t, &a, | 
|  | MakeAddrRange(512, 2048), | 
|  | ) | 
|  |  | 
|  | // Add new independent range. | 
|  | a.Add(MakeAddrRange(4096, 8192)) | 
|  | validateAddrRanges(t, &a, | 
|  | MakeAddrRange(512, 2048), | 
|  | MakeAddrRange(4096, 8192), | 
|  | ) | 
|  |  | 
|  | // Coalesce down. | 
|  | a.Add(MakeAddrRange(3776, 4096)) | 
|  | validateAddrRanges(t, &a, | 
|  | MakeAddrRange(512, 2048), | 
|  | MakeAddrRange(3776, 8192), | 
|  | ) | 
|  |  | 
|  | // Coalesce up and down. | 
|  | a.Add(MakeAddrRange(2048, 3776)) | 
|  | validateAddrRanges(t, &a, | 
|  | MakeAddrRange(512, 8192), | 
|  | ) | 
|  |  | 
|  | // Push a bunch of independent ranges to the end to try and force growth. | 
|  | expectedRanges := []AddrRange{MakeAddrRange(512, 8192)} | 
|  | for i := uintptr(0); i < 64; i++ { | 
|  | dRange := MakeAddrRange(8192+(i+1)*2048, 8192+(i+1)*2048+10) | 
|  | a.Add(dRange) | 
|  | expectedRanges = append(expectedRanges, dRange) | 
|  | validateAddrRanges(t, &a, expectedRanges...) | 
|  | } | 
|  |  | 
|  | // Push a bunch of independent ranges to the beginning to try and force growth. | 
|  | var bottomRanges []AddrRange | 
|  | for i := uintptr(0); i < 63; i++ { | 
|  | dRange := MakeAddrRange(8+i*8, 8+i*8+4) | 
|  | a.Add(dRange) | 
|  | bottomRanges = append(bottomRanges, dRange) | 
|  | validateAddrRanges(t, &a, append(bottomRanges, expectedRanges...)...) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestAddrRangesFindSucc(t *testing.T) { | 
|  | var large []AddrRange | 
|  | for i := 0; i < 100; i++ { | 
|  | large = append(large, MakeAddrRange(5+uintptr(i)*5, 5+uintptr(i)*5+3)) | 
|  | } | 
|  |  | 
|  | type testt struct { | 
|  | name   string | 
|  | base   uintptr | 
|  | expect int | 
|  | ranges []AddrRange | 
|  | } | 
|  | tests := []testt{ | 
|  | { | 
|  | name:   "Empty", | 
|  | base:   12, | 
|  | expect: 0, | 
|  | ranges: []AddrRange{}, | 
|  | }, | 
|  | { | 
|  | name:   "OneBefore", | 
|  | base:   12, | 
|  | expect: 0, | 
|  | ranges: []AddrRange{ | 
|  | MakeAddrRange(14, 16), | 
|  | }, | 
|  | }, | 
|  | { | 
|  | name:   "OneWithin", | 
|  | base:   14, | 
|  | expect: 1, | 
|  | ranges: []AddrRange{ | 
|  | MakeAddrRange(14, 16), | 
|  | }, | 
|  | }, | 
|  | { | 
|  | name:   "OneAfterLimit", | 
|  | base:   16, | 
|  | expect: 1, | 
|  | ranges: []AddrRange{ | 
|  | MakeAddrRange(14, 16), | 
|  | }, | 
|  | }, | 
|  | { | 
|  | name:   "OneAfter", | 
|  | base:   17, | 
|  | expect: 1, | 
|  | ranges: []AddrRange{ | 
|  | MakeAddrRange(14, 16), | 
|  | }, | 
|  | }, | 
|  | { | 
|  | name:   "ThreeBefore", | 
|  | base:   3, | 
|  | expect: 0, | 
|  | ranges: []AddrRange{ | 
|  | MakeAddrRange(6, 10), | 
|  | MakeAddrRange(12, 16), | 
|  | MakeAddrRange(19, 22), | 
|  | }, | 
|  | }, | 
|  | { | 
|  | name:   "ThreeAfter", | 
|  | base:   24, | 
|  | expect: 3, | 
|  | ranges: []AddrRange{ | 
|  | MakeAddrRange(6, 10), | 
|  | MakeAddrRange(12, 16), | 
|  | MakeAddrRange(19, 22), | 
|  | }, | 
|  | }, | 
|  | { | 
|  | name:   "ThreeBetween", | 
|  | base:   11, | 
|  | expect: 1, | 
|  | ranges: []AddrRange{ | 
|  | MakeAddrRange(6, 10), | 
|  | MakeAddrRange(12, 16), | 
|  | MakeAddrRange(19, 22), | 
|  | }, | 
|  | }, | 
|  | { | 
|  | name:   "ThreeWithin", | 
|  | base:   9, | 
|  | expect: 1, | 
|  | ranges: []AddrRange{ | 
|  | MakeAddrRange(6, 10), | 
|  | MakeAddrRange(12, 16), | 
|  | MakeAddrRange(19, 22), | 
|  | }, | 
|  | }, | 
|  | { | 
|  | name:   "Zero", | 
|  | base:   0, | 
|  | expect: 1, | 
|  | ranges: []AddrRange{ | 
|  | MakeAddrRange(0, 10), | 
|  | }, | 
|  | }, | 
|  | { | 
|  | name:   "Max", | 
|  | base:   ^uintptr(0), | 
|  | expect: 1, | 
|  | ranges: []AddrRange{ | 
|  | MakeAddrRange(^uintptr(0)-5, ^uintptr(0)), | 
|  | }, | 
|  | }, | 
|  | { | 
|  | name:   "LargeBefore", | 
|  | base:   2, | 
|  | expect: 0, | 
|  | ranges: large, | 
|  | }, | 
|  | { | 
|  | name:   "LargeAfter", | 
|  | base:   5 + uintptr(len(large))*5 + 30, | 
|  | expect: len(large), | 
|  | ranges: large, | 
|  | }, | 
|  | { | 
|  | name:   "LargeBetweenLow", | 
|  | base:   14, | 
|  | expect: 2, | 
|  | ranges: large, | 
|  | }, | 
|  | { | 
|  | name:   "LargeBetweenHigh", | 
|  | base:   249, | 
|  | expect: 49, | 
|  | ranges: large, | 
|  | }, | 
|  | { | 
|  | name:   "LargeWithinLow", | 
|  | base:   25, | 
|  | expect: 5, | 
|  | ranges: large, | 
|  | }, | 
|  | { | 
|  | name:   "LargeWithinHigh", | 
|  | base:   396, | 
|  | expect: 79, | 
|  | ranges: large, | 
|  | }, | 
|  | { | 
|  | name:   "LargeWithinMiddle", | 
|  | base:   250, | 
|  | expect: 50, | 
|  | ranges: large, | 
|  | }, | 
|  | } | 
|  |  | 
|  | for _, test := range tests { | 
|  | t.Run(test.name, func(t *testing.T) { | 
|  | a := MakeAddrRanges(test.ranges...) | 
|  | i := a.FindSucc(test.base) | 
|  | if i != test.expect { | 
|  | t.Fatalf("expected %d, got %d", test.expect, i) | 
|  | } | 
|  | }) | 
|  | } | 
|  | } |