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