Skip to content

Commit 64dc25b

Browse files
committed
runtime: add tests for addrRanges.add
Change-Id: I249deb482df74068b0538e9d773b9a87bc5a6df3 Reviewed-on: https://go-review.googlesource.com/c/go/+/242681 Run-TryBot: Michael Knyszek <[email protected]> TryBot-Result: Go Bot <[email protected]> Trust: Michael Knyszek <[email protected]> Reviewed-by: Austin Clements <[email protected]> Reviewed-by: Michael Pratt <[email protected]>
1 parent fe70866 commit 64dc25b

File tree

2 files changed

+163
-2
lines changed

2 files changed

+163
-2
lines changed

src/runtime/export_test.go

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -785,22 +785,64 @@ func (a AddrRange) Equals(b AddrRange) bool {
785785
return a == b
786786
}
787787

788+
// Size returns the size in bytes of the address range.
789+
func (a AddrRange) Size() uintptr {
790+
return a.addrRange.size()
791+
}
792+
788793
// AddrRanges is a wrapper around addrRanges for testing.
789794
type AddrRanges struct {
790795
addrRanges
796+
mutable bool
797+
}
798+
799+
// NewAddrRanges creates a new empty addrRanges.
800+
//
801+
// Note that this initializes addrRanges just like in the
802+
// runtime, so its memory is persistentalloc'd. Call this
803+
// function sparingly since the memory it allocates is
804+
// leaked.
805+
//
806+
// This AddrRanges is mutable, so we can test methods like
807+
// Add.
808+
func NewAddrRanges() AddrRanges {
809+
r := addrRanges{}
810+
r.init(new(uint64))
811+
return AddrRanges{r, true}
791812
}
792813

793814
// MakeAddrRanges creates a new addrRanges populated with
794815
// the ranges in a.
816+
//
817+
// The returned AddrRanges is immutable, so methods like
818+
// Add will fail.
795819
func MakeAddrRanges(a ...AddrRange) AddrRanges {
796820
// Methods that manipulate the backing store of addrRanges.ranges should
797821
// not be used on the result from this function (e.g. add) since they may
798-
// trigger reallocation.
822+
// trigger reallocation. That would normally be fine, except the new
823+
// backing store won't come from the heap, but from persistentalloc, so
824+
// we'll leak some memory implicitly.
799825
ranges := make([]addrRange, 0, len(a))
826+
total := uintptr(0)
800827
for _, r := range a {
801828
ranges = append(ranges, r.addrRange)
829+
total += r.Size()
830+
}
831+
return AddrRanges{addrRanges{
832+
ranges: ranges,
833+
totalBytes: total,
834+
sysStat: new(uint64),
835+
}, false}
836+
}
837+
838+
// Ranges returns a copy of the ranges described by the
839+
// addrRanges.
840+
func (a *AddrRanges) Ranges() []AddrRange {
841+
result := make([]AddrRange, 0, len(a.addrRanges.ranges))
842+
for _, r := range a.addrRanges.ranges {
843+
result = append(result, AddrRange{r})
802844
}
803-
return AddrRanges{addrRanges{ranges: ranges, sysStat: new(uint64)}}
845+
return result
804846
}
805847

806848
// FindSucc returns the successor to base. See addrRanges.findSucc
@@ -809,6 +851,22 @@ func (a *AddrRanges) FindSucc(base uintptr) int {
809851
return a.findSucc(base)
810852
}
811853

854+
// Add adds a new AddrRange to the AddrRanges.
855+
//
856+
// The AddrRange must be mutable (i.e. created by NewAddrRanges),
857+
// otherwise this method will throw.
858+
func (a *AddrRanges) Add(r AddrRange) {
859+
if !a.mutable {
860+
throw("attempt to mutate immutable AddrRanges")
861+
}
862+
a.add(r.addrRange)
863+
}
864+
865+
// TotalBytes returns the totalBytes field of the addrRanges.
866+
func (a *AddrRanges) TotalBytes() uintptr {
867+
return a.addrRanges.totalBytes
868+
}
869+
812870
// BitRange represents a range over a bitmap.
813871
type BitRange struct {
814872
I, N uint // bit index and length in bits

src/runtime/mranges_test.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,109 @@ import (
99
"testing"
1010
)
1111

12+
func validateAddrRanges(t *testing.T, a *AddrRanges, want ...AddrRange) {
13+
ranges := a.Ranges()
14+
if len(ranges) != len(want) {
15+
t.Errorf("want %v, got %v", want, ranges)
16+
t.Fatal("different lengths")
17+
}
18+
gotTotalBytes := uintptr(0)
19+
wantTotalBytes := uintptr(0)
20+
for i := range ranges {
21+
gotTotalBytes += ranges[i].Size()
22+
wantTotalBytes += want[i].Size()
23+
if ranges[i].Base() >= ranges[i].Limit() {
24+
t.Error("empty range found")
25+
}
26+
// Ensure this is equivalent to what we want.
27+
if !ranges[i].Equals(want[i]) {
28+
t.Errorf("range %d: got [0x%x, 0x%x), want [0x%x, 0x%x)", i,
29+
ranges[i].Base(), ranges[i].Limit(),
30+
want[i].Base(), want[i].Limit(),
31+
)
32+
}
33+
if i != 0 {
34+
// Ensure the ranges are sorted.
35+
if ranges[i-1].Base() >= ranges[i].Base() {
36+
t.Errorf("ranges %d and %d are out of sorted order", i-1, i)
37+
}
38+
// Check for a failure to coalesce.
39+
if ranges[i-1].Limit() == ranges[i].Base() {
40+
t.Errorf("ranges %d and %d should have coalesced", i-1, i)
41+
}
42+
// Check if any ranges overlap. Because the ranges are sorted
43+
// by base, it's sufficient to just check neighbors.
44+
if ranges[i-1].Limit() > ranges[i].Base() {
45+
t.Errorf("ranges %d and %d overlap", i-1, i)
46+
}
47+
}
48+
}
49+
if wantTotalBytes != gotTotalBytes {
50+
t.Errorf("expected %d total bytes, got %d", wantTotalBytes, gotTotalBytes)
51+
}
52+
if b := a.TotalBytes(); b != gotTotalBytes {
53+
t.Errorf("inconsistent total bytes: want %d, got %d", gotTotalBytes, b)
54+
}
55+
if t.Failed() {
56+
t.Errorf("addrRanges: %v", ranges)
57+
t.Fatal("detected bad addrRanges")
58+
}
59+
}
60+
61+
func TestAddrRangesAdd(t *testing.T) {
62+
a := NewAddrRanges()
63+
64+
// First range.
65+
a.Add(MakeAddrRange(512, 1024))
66+
validateAddrRanges(t, &a,
67+
MakeAddrRange(512, 1024),
68+
)
69+
70+
// Coalesce up.
71+
a.Add(MakeAddrRange(1024, 2048))
72+
validateAddrRanges(t, &a,
73+
MakeAddrRange(512, 2048),
74+
)
75+
76+
// Add new independent range.
77+
a.Add(MakeAddrRange(4096, 8192))
78+
validateAddrRanges(t, &a,
79+
MakeAddrRange(512, 2048),
80+
MakeAddrRange(4096, 8192),
81+
)
82+
83+
// Coalesce down.
84+
a.Add(MakeAddrRange(3776, 4096))
85+
validateAddrRanges(t, &a,
86+
MakeAddrRange(512, 2048),
87+
MakeAddrRange(3776, 8192),
88+
)
89+
90+
// Coalesce up and down.
91+
a.Add(MakeAddrRange(2048, 3776))
92+
validateAddrRanges(t, &a,
93+
MakeAddrRange(512, 8192),
94+
)
95+
96+
// Push a bunch of independent ranges to the end to try and force growth.
97+
expectedRanges := []AddrRange{MakeAddrRange(512, 8192)}
98+
for i := uintptr(0); i < 64; i++ {
99+
dRange := MakeAddrRange(8192+(i+1)*2048, 8192+(i+1)*2048+10)
100+
a.Add(dRange)
101+
expectedRanges = append(expectedRanges, dRange)
102+
validateAddrRanges(t, &a, expectedRanges...)
103+
}
104+
105+
// Push a bunch of independent ranges to the beginning to try and force growth.
106+
var bottomRanges []AddrRange
107+
for i := uintptr(0); i < 63; i++ {
108+
dRange := MakeAddrRange(8+i*8, 8+i*8+4)
109+
a.Add(dRange)
110+
bottomRanges = append(bottomRanges, dRange)
111+
validateAddrRanges(t, &a, append(bottomRanges, expectedRanges...)...)
112+
}
113+
}
114+
12115
func TestAddrRangesFindSucc(t *testing.T) {
13116
var large []AddrRange
14117
for i := 0; i < 100; i++ {

0 commit comments

Comments
 (0)