| // Copyright 2019 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 ( | 
 | 	"fmt" | 
 | 	"math/rand" | 
 | 	. "runtime" | 
 | 	"testing" | 
 | ) | 
 |  | 
 | // Ensures that got and want are the same, and if not, reports | 
 | // detailed diff information. | 
 | func checkPallocBits(t *testing.T, got, want *PallocBits) bool { | 
 | 	d := DiffPallocBits(got, want) | 
 | 	if len(d) != 0 { | 
 | 		t.Errorf("%d range(s) different", len(d)) | 
 | 		for _, bits := range d { | 
 | 			t.Logf("\t@ bit index %d", bits.I) | 
 | 			t.Logf("\t|  got: %s", StringifyPallocBits(got, bits)) | 
 | 			t.Logf("\t| want: %s", StringifyPallocBits(want, bits)) | 
 | 		} | 
 | 		return false | 
 | 	} | 
 | 	return true | 
 | } | 
 |  | 
 | // makePallocBits produces an initialized PallocBits by setting | 
 | // the ranges in s to 1 and the rest to zero. | 
 | func makePallocBits(s []BitRange) *PallocBits { | 
 | 	b := new(PallocBits) | 
 | 	for _, v := range s { | 
 | 		b.AllocRange(v.I, v.N) | 
 | 	} | 
 | 	return b | 
 | } | 
 |  | 
 | // Ensures that PallocBits.AllocRange works, which is a fundamental | 
 | // method used for testing and initialization since it's used by | 
 | // makePallocBits. | 
 | func TestPallocBitsAllocRange(t *testing.T) { | 
 | 	test := func(t *testing.T, i, n uint, want *PallocBits) { | 
 | 		checkPallocBits(t, makePallocBits([]BitRange{{i, n}}), want) | 
 | 	} | 
 | 	t.Run("OneLow", func(t *testing.T) { | 
 | 		want := new(PallocBits) | 
 | 		want[0] = 0x1 | 
 | 		test(t, 0, 1, want) | 
 | 	}) | 
 | 	t.Run("OneHigh", func(t *testing.T) { | 
 | 		want := new(PallocBits) | 
 | 		want[PallocChunkPages/64-1] = 1 << 63 | 
 | 		test(t, PallocChunkPages-1, 1, want) | 
 | 	}) | 
 | 	t.Run("Inner", func(t *testing.T) { | 
 | 		want := new(PallocBits) | 
 | 		want[2] = 0x3e | 
 | 		test(t, 129, 5, want) | 
 | 	}) | 
 | 	t.Run("Aligned", func(t *testing.T) { | 
 | 		want := new(PallocBits) | 
 | 		want[2] = ^uint64(0) | 
 | 		want[3] = ^uint64(0) | 
 | 		test(t, 128, 128, want) | 
 | 	}) | 
 | 	t.Run("Begin", func(t *testing.T) { | 
 | 		want := new(PallocBits) | 
 | 		want[0] = ^uint64(0) | 
 | 		want[1] = ^uint64(0) | 
 | 		want[2] = ^uint64(0) | 
 | 		want[3] = ^uint64(0) | 
 | 		want[4] = ^uint64(0) | 
 | 		want[5] = 0x1 | 
 | 		test(t, 0, 321, want) | 
 | 	}) | 
 | 	t.Run("End", func(t *testing.T) { | 
 | 		want := new(PallocBits) | 
 | 		want[PallocChunkPages/64-1] = ^uint64(0) | 
 | 		want[PallocChunkPages/64-2] = ^uint64(0) | 
 | 		want[PallocChunkPages/64-3] = ^uint64(0) | 
 | 		want[PallocChunkPages/64-4] = 1 << 63 | 
 | 		test(t, PallocChunkPages-(64*3+1), 64*3+1, want) | 
 | 	}) | 
 | 	t.Run("All", func(t *testing.T) { | 
 | 		want := new(PallocBits) | 
 | 		for i := range want { | 
 | 			want[i] = ^uint64(0) | 
 | 		} | 
 | 		test(t, 0, PallocChunkPages, want) | 
 | 	}) | 
 | } | 
 |  | 
 | // Inverts every bit in the PallocBits. | 
 | func invertPallocBits(b *PallocBits) { | 
 | 	for i := range b { | 
 | 		b[i] = ^b[i] | 
 | 	} | 
 | } | 
 |  | 
 | // Ensures two packed summaries are identical, and reports a detailed description | 
 | // of the difference if they're not. | 
 | func checkPallocSum(t testing.TB, got, want PallocSum) { | 
 | 	if got.Start() != want.Start() { | 
 | 		t.Errorf("inconsistent start: got %d, want %d", got.Start(), want.Start()) | 
 | 	} | 
 | 	if got.Max() != want.Max() { | 
 | 		t.Errorf("inconsistent max: got %d, want %d", got.Max(), want.Max()) | 
 | 	} | 
 | 	if got.End() != want.End() { | 
 | 		t.Errorf("inconsistent end: got %d, want %d", got.End(), want.End()) | 
 | 	} | 
 | } | 
 |  | 
 | func TestMallocBitsPopcntRange(t *testing.T) { | 
 | 	type test struct { | 
 | 		i, n uint // bit range to popcnt over. | 
 | 		want uint // expected popcnt result on that range. | 
 | 	} | 
 | 	tests := map[string]struct { | 
 | 		init  []BitRange // bit ranges to set to 1 in the bitmap. | 
 | 		tests []test     // a set of popcnt tests to run over the bitmap. | 
 | 	}{ | 
 | 		"None": { | 
 | 			tests: []test{ | 
 | 				{0, 1, 0}, | 
 | 				{5, 3, 0}, | 
 | 				{2, 11, 0}, | 
 | 				{PallocChunkPages/4 + 1, PallocChunkPages / 2, 0}, | 
 | 				{0, PallocChunkPages, 0}, | 
 | 			}, | 
 | 		}, | 
 | 		"All": { | 
 | 			init: []BitRange{{0, PallocChunkPages}}, | 
 | 			tests: []test{ | 
 | 				{0, 1, 1}, | 
 | 				{5, 3, 3}, | 
 | 				{2, 11, 11}, | 
 | 				{PallocChunkPages/4 + 1, PallocChunkPages / 2, PallocChunkPages / 2}, | 
 | 				{0, PallocChunkPages, PallocChunkPages}, | 
 | 			}, | 
 | 		}, | 
 | 		"Half": { | 
 | 			init: []BitRange{{PallocChunkPages / 2, PallocChunkPages / 2}}, | 
 | 			tests: []test{ | 
 | 				{0, 1, 0}, | 
 | 				{5, 3, 0}, | 
 | 				{2, 11, 0}, | 
 | 				{PallocChunkPages/2 - 1, 1, 0}, | 
 | 				{PallocChunkPages / 2, 1, 1}, | 
 | 				{PallocChunkPages/2 + 10, 1, 1}, | 
 | 				{PallocChunkPages/2 - 1, 2, 1}, | 
 | 				{PallocChunkPages / 4, PallocChunkPages / 4, 0}, | 
 | 				{PallocChunkPages / 4, PallocChunkPages/4 + 1, 1}, | 
 | 				{PallocChunkPages/4 + 1, PallocChunkPages / 2, PallocChunkPages/4 + 1}, | 
 | 				{0, PallocChunkPages, PallocChunkPages / 2}, | 
 | 			}, | 
 | 		}, | 
 | 		"OddBound": { | 
 | 			init: []BitRange{{0, 111}}, | 
 | 			tests: []test{ | 
 | 				{0, 1, 1}, | 
 | 				{5, 3, 3}, | 
 | 				{2, 11, 11}, | 
 | 				{110, 2, 1}, | 
 | 				{99, 50, 12}, | 
 | 				{110, 1, 1}, | 
 | 				{111, 1, 0}, | 
 | 				{99, 1, 1}, | 
 | 				{120, 1, 0}, | 
 | 				{PallocChunkPages / 2, PallocChunkPages / 2, 0}, | 
 | 				{0, PallocChunkPages, 111}, | 
 | 			}, | 
 | 		}, | 
 | 		"Scattered": { | 
 | 			init: []BitRange{ | 
 | 				{1, 3}, {5, 1}, {7, 1}, {10, 2}, {13, 1}, {15, 4}, | 
 | 				{21, 1}, {23, 1}, {26, 2}, {30, 5}, {36, 2}, {40, 3}, | 
 | 				{44, 6}, {51, 1}, {53, 2}, {58, 3}, {63, 1}, {67, 2}, | 
 | 				{71, 10}, {84, 1}, {89, 7}, {99, 2}, {103, 1}, {107, 2}, | 
 | 				{111, 1}, {113, 1}, {115, 1}, {118, 1}, {120, 2}, {125, 5}, | 
 | 			}, | 
 | 			tests: []test{ | 
 | 				{0, 11, 6}, | 
 | 				{0, 64, 39}, | 
 | 				{13, 64, 40}, | 
 | 				{64, 64, 34}, | 
 | 				{0, 128, 73}, | 
 | 				{1, 128, 74}, | 
 | 				{0, PallocChunkPages, 75}, | 
 | 			}, | 
 | 		}, | 
 | 	} | 
 | 	for name, v := range tests { | 
 | 		v := v | 
 | 		t.Run(name, func(t *testing.T) { | 
 | 			b := makePallocBits(v.init) | 
 | 			for _, h := range v.tests { | 
 | 				if got := b.PopcntRange(h.i, h.n); got != h.want { | 
 | 					t.Errorf("bad popcnt (i=%d, n=%d): got %d, want %d", h.i, h.n, got, h.want) | 
 | 				} | 
 | 			} | 
 | 		}) | 
 | 	} | 
 | } | 
 |  | 
 | // Ensures computing bit summaries works as expected by generating random | 
 | // bitmaps and checking against a reference implementation. | 
 | func TestPallocBitsSummarizeRandom(t *testing.T) { | 
 | 	b := new(PallocBits) | 
 | 	for i := 0; i < 1000; i++ { | 
 | 		// Randomize bitmap. | 
 | 		for i := range b { | 
 | 			b[i] = rand.Uint64() | 
 | 		} | 
 | 		// Check summary against reference implementation. | 
 | 		checkPallocSum(t, b.Summarize(), SummarizeSlow(b)) | 
 | 	} | 
 | } | 
 |  | 
 | // Ensures computing bit summaries works as expected. | 
 | func TestPallocBitsSummarize(t *testing.T) { | 
 | 	var emptySum = PackPallocSum(PallocChunkPages, PallocChunkPages, PallocChunkPages) | 
 | 	type test struct { | 
 | 		free []BitRange // Ranges of free (zero) bits. | 
 | 		hits []PallocSum | 
 | 	} | 
 | 	tests := make(map[string]test) | 
 | 	tests["NoneFree"] = test{ | 
 | 		free: []BitRange{}, | 
 | 		hits: []PallocSum{ | 
 | 			PackPallocSum(0, 0, 0), | 
 | 		}, | 
 | 	} | 
 | 	tests["OnlyStart"] = test{ | 
 | 		free: []BitRange{{0, 10}}, | 
 | 		hits: []PallocSum{ | 
 | 			PackPallocSum(10, 10, 0), | 
 | 		}, | 
 | 	} | 
 | 	tests["OnlyEnd"] = test{ | 
 | 		free: []BitRange{{PallocChunkPages - 40, 40}}, | 
 | 		hits: []PallocSum{ | 
 | 			PackPallocSum(0, 40, 40), | 
 | 		}, | 
 | 	} | 
 | 	tests["StartAndEnd"] = test{ | 
 | 		free: []BitRange{{0, 11}, {PallocChunkPages - 23, 23}}, | 
 | 		hits: []PallocSum{ | 
 | 			PackPallocSum(11, 23, 23), | 
 | 		}, | 
 | 	} | 
 | 	tests["StartMaxEnd"] = test{ | 
 | 		free: []BitRange{{0, 4}, {50, 100}, {PallocChunkPages - 4, 4}}, | 
 | 		hits: []PallocSum{ | 
 | 			PackPallocSum(4, 100, 4), | 
 | 		}, | 
 | 	} | 
 | 	tests["OnlyMax"] = test{ | 
 | 		free: []BitRange{{1, 20}, {35, 241}, {PallocChunkPages - 50, 30}}, | 
 | 		hits: []PallocSum{ | 
 | 			PackPallocSum(0, 241, 0), | 
 | 		}, | 
 | 	} | 
 | 	tests["MultiMax"] = test{ | 
 | 		free: []BitRange{{35, 2}, {40, 5}, {100, 5}}, | 
 | 		hits: []PallocSum{ | 
 | 			PackPallocSum(0, 5, 0), | 
 | 		}, | 
 | 	} | 
 | 	tests["One"] = test{ | 
 | 		free: []BitRange{{2, 1}}, | 
 | 		hits: []PallocSum{ | 
 | 			PackPallocSum(0, 1, 0), | 
 | 		}, | 
 | 	} | 
 | 	tests["AllFree"] = test{ | 
 | 		free: []BitRange{{0, PallocChunkPages}}, | 
 | 		hits: []PallocSum{ | 
 | 			emptySum, | 
 | 		}, | 
 | 	} | 
 | 	for name, v := range tests { | 
 | 		v := v | 
 | 		t.Run(name, func(t *testing.T) { | 
 | 			b := makePallocBits(v.free) | 
 | 			// In the PallocBits we create 1's represent free spots, but in our actual | 
 | 			// PallocBits 1 means not free, so invert. | 
 | 			invertPallocBits(b) | 
 | 			for _, h := range v.hits { | 
 | 				checkPallocSum(t, b.Summarize(), h) | 
 | 			} | 
 | 		}) | 
 | 	} | 
 | } | 
 |  | 
 | // Benchmarks how quickly we can summarize a PallocBits. | 
 | func BenchmarkPallocBitsSummarize(b *testing.B) { | 
 | 	patterns := []uint64{ | 
 | 		0, | 
 | 		^uint64(0), | 
 | 		0xaa, | 
 | 		0xaaaaaaaaaaaaaaaa, | 
 | 		0x80000000aaaaaaaa, | 
 | 		0xaaaaaaaa00000001, | 
 | 		0xbbbbbbbbbbbbbbbb, | 
 | 		0x80000000bbbbbbbb, | 
 | 		0xbbbbbbbb00000001, | 
 | 		0xcccccccccccccccc, | 
 | 		0x4444444444444444, | 
 | 		0x4040404040404040, | 
 | 		0x4000400040004000, | 
 | 		0x1000404044ccaaff, | 
 | 	} | 
 | 	for _, p := range patterns { | 
 | 		buf := new(PallocBits) | 
 | 		for i := 0; i < len(buf); i++ { | 
 | 			buf[i] = p | 
 | 		} | 
 | 		b.Run(fmt.Sprintf("Unpacked%02X", p), func(b *testing.B) { | 
 | 			checkPallocSum(b, buf.Summarize(), SummarizeSlow(buf)) | 
 | 			for i := 0; i < b.N; i++ { | 
 | 				buf.Summarize() | 
 | 			} | 
 | 		}) | 
 | 	} | 
 | } | 
 |  | 
 | // Ensures page allocation works. | 
 | func TestPallocBitsAlloc(t *testing.T) { | 
 | 	tests := map[string]struct { | 
 | 		before []BitRange | 
 | 		after  []BitRange | 
 | 		npages uintptr | 
 | 		hits   []uint | 
 | 	}{ | 
 | 		"AllFree1": { | 
 | 			npages: 1, | 
 | 			hits:   []uint{0, 1, 2, 3, 4, 5}, | 
 | 			after:  []BitRange{{0, 6}}, | 
 | 		}, | 
 | 		"AllFree2": { | 
 | 			npages: 2, | 
 | 			hits:   []uint{0, 2, 4, 6, 8, 10}, | 
 | 			after:  []BitRange{{0, 12}}, | 
 | 		}, | 
 | 		"AllFree5": { | 
 | 			npages: 5, | 
 | 			hits:   []uint{0, 5, 10, 15, 20}, | 
 | 			after:  []BitRange{{0, 25}}, | 
 | 		}, | 
 | 		"AllFree64": { | 
 | 			npages: 64, | 
 | 			hits:   []uint{0, 64, 128}, | 
 | 			after:  []BitRange{{0, 192}}, | 
 | 		}, | 
 | 		"AllFree65": { | 
 | 			npages: 65, | 
 | 			hits:   []uint{0, 65, 130}, | 
 | 			after:  []BitRange{{0, 195}}, | 
 | 		}, | 
 | 		"SomeFree64": { | 
 | 			before: []BitRange{{0, 32}, {64, 32}, {100, PallocChunkPages - 100}}, | 
 | 			npages: 64, | 
 | 			hits:   []uint{^uint(0)}, | 
 | 			after:  []BitRange{{0, 32}, {64, 32}, {100, PallocChunkPages - 100}}, | 
 | 		}, | 
 | 		"NoneFree1": { | 
 | 			before: []BitRange{{0, PallocChunkPages}}, | 
 | 			npages: 1, | 
 | 			hits:   []uint{^uint(0), ^uint(0)}, | 
 | 			after:  []BitRange{{0, PallocChunkPages}}, | 
 | 		}, | 
 | 		"NoneFree2": { | 
 | 			before: []BitRange{{0, PallocChunkPages}}, | 
 | 			npages: 2, | 
 | 			hits:   []uint{^uint(0), ^uint(0)}, | 
 | 			after:  []BitRange{{0, PallocChunkPages}}, | 
 | 		}, | 
 | 		"NoneFree5": { | 
 | 			before: []BitRange{{0, PallocChunkPages}}, | 
 | 			npages: 5, | 
 | 			hits:   []uint{^uint(0), ^uint(0)}, | 
 | 			after:  []BitRange{{0, PallocChunkPages}}, | 
 | 		}, | 
 | 		"NoneFree65": { | 
 | 			before: []BitRange{{0, PallocChunkPages}}, | 
 | 			npages: 65, | 
 | 			hits:   []uint{^uint(0), ^uint(0)}, | 
 | 			after:  []BitRange{{0, PallocChunkPages}}, | 
 | 		}, | 
 | 		"ExactFit1": { | 
 | 			before: []BitRange{{0, PallocChunkPages/2 - 3}, {PallocChunkPages/2 - 2, PallocChunkPages/2 + 2}}, | 
 | 			npages: 1, | 
 | 			hits:   []uint{PallocChunkPages/2 - 3, ^uint(0)}, | 
 | 			after:  []BitRange{{0, PallocChunkPages}}, | 
 | 		}, | 
 | 		"ExactFit2": { | 
 | 			before: []BitRange{{0, PallocChunkPages/2 - 3}, {PallocChunkPages/2 - 1, PallocChunkPages/2 + 1}}, | 
 | 			npages: 2, | 
 | 			hits:   []uint{PallocChunkPages/2 - 3, ^uint(0)}, | 
 | 			after:  []BitRange{{0, PallocChunkPages}}, | 
 | 		}, | 
 | 		"ExactFit5": { | 
 | 			before: []BitRange{{0, PallocChunkPages/2 - 3}, {PallocChunkPages/2 + 2, PallocChunkPages/2 - 2}}, | 
 | 			npages: 5, | 
 | 			hits:   []uint{PallocChunkPages/2 - 3, ^uint(0)}, | 
 | 			after:  []BitRange{{0, PallocChunkPages}}, | 
 | 		}, | 
 | 		"ExactFit65": { | 
 | 			before: []BitRange{{0, PallocChunkPages/2 - 31}, {PallocChunkPages/2 + 34, PallocChunkPages/2 - 34}}, | 
 | 			npages: 65, | 
 | 			hits:   []uint{PallocChunkPages/2 - 31, ^uint(0)}, | 
 | 			after:  []BitRange{{0, PallocChunkPages}}, | 
 | 		}, | 
 | 		"SomeFree161": { | 
 | 			before: []BitRange{{0, 185}, {331, 1}}, | 
 | 			npages: 161, | 
 | 			hits:   []uint{332}, | 
 | 			after:  []BitRange{{0, 185}, {331, 162}}, | 
 | 		}, | 
 | 	} | 
 | 	for name, v := range tests { | 
 | 		v := v | 
 | 		t.Run(name, func(t *testing.T) { | 
 | 			b := makePallocBits(v.before) | 
 | 			for iter, i := range v.hits { | 
 | 				a, _ := b.Find(v.npages, 0) | 
 | 				if i != a { | 
 | 					t.Fatalf("find #%d picked wrong index: want %d, got %d", iter+1, i, a) | 
 | 				} | 
 | 				if i != ^uint(0) { | 
 | 					b.AllocRange(a, uint(v.npages)) | 
 | 				} | 
 | 			} | 
 | 			want := makePallocBits(v.after) | 
 | 			checkPallocBits(t, b, want) | 
 | 		}) | 
 | 	} | 
 | } | 
 |  | 
 | // Ensures page freeing works. | 
 | func TestPallocBitsFree(t *testing.T) { | 
 | 	tests := map[string]struct { | 
 | 		beforeInv []BitRange | 
 | 		afterInv  []BitRange | 
 | 		frees     []uint | 
 | 		npages    uintptr | 
 | 	}{ | 
 | 		"SomeFree": { | 
 | 			npages:    1, | 
 | 			beforeInv: []BitRange{{0, 32}, {64, 32}, {100, 1}}, | 
 | 			frees:     []uint{32}, | 
 | 			afterInv:  []BitRange{{0, 33}, {64, 32}, {100, 1}}, | 
 | 		}, | 
 | 		"NoneFree1": { | 
 | 			npages:   1, | 
 | 			frees:    []uint{0, 1, 2, 3, 4, 5}, | 
 | 			afterInv: []BitRange{{0, 6}}, | 
 | 		}, | 
 | 		"NoneFree2": { | 
 | 			npages:   2, | 
 | 			frees:    []uint{0, 2, 4, 6, 8, 10}, | 
 | 			afterInv: []BitRange{{0, 12}}, | 
 | 		}, | 
 | 		"NoneFree5": { | 
 | 			npages:   5, | 
 | 			frees:    []uint{0, 5, 10, 15, 20}, | 
 | 			afterInv: []BitRange{{0, 25}}, | 
 | 		}, | 
 | 		"NoneFree64": { | 
 | 			npages:   64, | 
 | 			frees:    []uint{0, 64, 128}, | 
 | 			afterInv: []BitRange{{0, 192}}, | 
 | 		}, | 
 | 		"NoneFree65": { | 
 | 			npages:   65, | 
 | 			frees:    []uint{0, 65, 130}, | 
 | 			afterInv: []BitRange{{0, 195}}, | 
 | 		}, | 
 | 	} | 
 | 	for name, v := range tests { | 
 | 		v := v | 
 | 		t.Run(name, func(t *testing.T) { | 
 | 			b := makePallocBits(v.beforeInv) | 
 | 			invertPallocBits(b) | 
 | 			for _, i := range v.frees { | 
 | 				b.Free(i, uint(v.npages)) | 
 | 			} | 
 | 			want := makePallocBits(v.afterInv) | 
 | 			invertPallocBits(want) | 
 | 			checkPallocBits(t, b, want) | 
 | 		}) | 
 | 	} | 
 | } | 
 |  | 
 | func TestFindBitRange64(t *testing.T) { | 
 | 	check := func(x uint64, n uint, result uint) { | 
 | 		i := FindBitRange64(x, n) | 
 | 		if result == ^uint(0) && i < 64 { | 
 | 			t.Errorf("case (%016x, %d): got %d, want failure", x, n, i) | 
 | 		} else if result != ^uint(0) && i != result { | 
 | 			t.Errorf("case (%016x, %d): got %d, want %d", x, n, i, result) | 
 | 		} | 
 | 	} | 
 | 	for i := uint(1); i <= 64; i++ { | 
 | 		check(^uint64(0), i, 0) | 
 | 	} | 
 | 	for i := uint(1); i <= 64; i++ { | 
 | 		check(0, i, ^uint(0)) | 
 | 	} | 
 | 	check(0x8000000000000000, 1, 63) | 
 | 	check(0xc000010001010000, 2, 62) | 
 | 	check(0xc000010001030000, 2, 16) | 
 | 	check(0xe000030001030000, 3, 61) | 
 | 	check(0xe000030001070000, 3, 16) | 
 | 	check(0xffff03ff01070000, 16, 48) | 
 | 	check(0xffff03ff0107ffff, 16, 0) | 
 | 	check(0x0fff03ff01079fff, 16, ^uint(0)) | 
 | } | 
 |  | 
 | func BenchmarkFindBitRange64(b *testing.B) { | 
 | 	patterns := []uint64{ | 
 | 		0, | 
 | 		^uint64(0), | 
 | 		0xaa, | 
 | 		0xaaaaaaaaaaaaaaaa, | 
 | 		0x80000000aaaaaaaa, | 
 | 		0xaaaaaaaa00000001, | 
 | 		0xbbbbbbbbbbbbbbbb, | 
 | 		0x80000000bbbbbbbb, | 
 | 		0xbbbbbbbb00000001, | 
 | 		0xcccccccccccccccc, | 
 | 		0x4444444444444444, | 
 | 		0x4040404040404040, | 
 | 		0x4000400040004000, | 
 | 	} | 
 | 	sizes := []uint{ | 
 | 		2, 8, 32, | 
 | 	} | 
 | 	for _, pattern := range patterns { | 
 | 		for _, size := range sizes { | 
 | 			b.Run(fmt.Sprintf("Pattern%02XSize%d", pattern, size), func(b *testing.B) { | 
 | 				for i := 0; i < b.N; i++ { | 
 | 					FindBitRange64(pattern, size) | 
 | 				} | 
 | 			}) | 
 | 		} | 
 | 	} | 
 | } |