| // 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) |
| } |
| }) |
| } |
| } |