2019-04-29 14:25:05 -07:00
|
|
|
// Copyright 2018 The gVisor Authors.
|
2018-04-27 10:37:02 -07:00
|
|
|
//
|
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
//
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
//
|
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
2019-03-14 08:11:36 -07:00
|
|
|
package pgalloc
|
2018-04-27 10:37:02 -07:00
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"testing"
|
|
|
|
|
|
2021-03-29 13:28:32 -07:00
|
|
|
"gvisor.dev/gvisor/pkg/hostarch"
|
2024-06-28 12:53:33 -07:00
|
|
|
"gvisor.dev/gvisor/pkg/sentry/memmap"
|
2018-04-27 10:37:02 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
2021-03-29 13:28:32 -07:00
|
|
|
page = hostarch.PageSize
|
|
|
|
|
hugepage = hostarch.HugePageSize
|
2018-04-27 10:37:02 -07:00
|
|
|
)
|
|
|
|
|
|
2024-06-28 12:53:33 -07:00
|
|
|
// existingSegment represents a range of pages in a test MemoryFile that is not
|
|
|
|
|
// void or free.
|
|
|
|
|
type existingSegment struct {
|
|
|
|
|
start uint64
|
|
|
|
|
end uint64
|
|
|
|
|
state int
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Possible values for existingSegment.state:
|
|
|
|
|
const (
|
|
|
|
|
existingUnspecified = iota
|
|
|
|
|
existingUsed
|
|
|
|
|
existingWaste
|
|
|
|
|
existingReleasing // or sub-releasing
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func TestFindAllocatable(t *testing.T) {
|
2018-04-27 10:37:02 -07:00
|
|
|
for _, test := range []struct {
|
2024-06-28 12:53:33 -07:00
|
|
|
name string
|
|
|
|
|
// Initial state:
|
|
|
|
|
chunkHuge []bool
|
|
|
|
|
existing []existingSegment
|
|
|
|
|
// Allocation parameters:
|
|
|
|
|
length uint64
|
|
|
|
|
huge bool
|
|
|
|
|
recycle bool
|
|
|
|
|
dir Direction
|
|
|
|
|
// Expected outcome:
|
|
|
|
|
want uint64
|
2018-04-27 10:37:02 -07:00
|
|
|
}{
|
|
|
|
|
{
|
2024-06-28 12:53:33 -07:00
|
|
|
name: "initial small allocation, bottom-up",
|
|
|
|
|
length: page,
|
|
|
|
|
want: 0,
|
2018-04-27 10:37:02 -07:00
|
|
|
},
|
|
|
|
|
{
|
2024-06-28 12:53:33 -07:00
|
|
|
name: "initial small allocation, top-down",
|
|
|
|
|
length: page,
|
|
|
|
|
dir: TopDown,
|
|
|
|
|
want: chunkSize - page,
|
2021-11-10 17:10:18 -08:00
|
|
|
},
|
|
|
|
|
{
|
2024-06-28 12:53:33 -07:00
|
|
|
name: "initial small allocation, multiple pages, top-down",
|
|
|
|
|
length: 2 * page,
|
|
|
|
|
dir: TopDown,
|
|
|
|
|
want: chunkSize - 2*page,
|
2021-11-10 17:10:18 -08:00
|
|
|
},
|
|
|
|
|
{
|
2024-06-28 12:53:33 -07:00
|
|
|
name: "initial small allocation, recycling enabled, bottom-up",
|
|
|
|
|
length: page,
|
|
|
|
|
recycle: true,
|
|
|
|
|
want: 0,
|
2020-06-05 15:38:38 -07:00
|
|
|
},
|
|
|
|
|
{
|
2024-06-28 12:53:33 -07:00
|
|
|
name: "initial huge allocation, bottom-up",
|
|
|
|
|
length: hugepage,
|
|
|
|
|
huge: true,
|
|
|
|
|
want: 0,
|
2018-04-27 10:37:02 -07:00
|
|
|
},
|
|
|
|
|
{
|
2024-06-28 12:53:33 -07:00
|
|
|
name: "initial huge allocation, top-down",
|
|
|
|
|
length: hugepage,
|
|
|
|
|
huge: true,
|
|
|
|
|
dir: TopDown,
|
|
|
|
|
want: chunkSize - hugepage,
|
2021-11-10 17:10:18 -08:00
|
|
|
},
|
|
|
|
|
{
|
2024-06-28 12:53:33 -07:00
|
|
|
name: "initial huge allocation, multiple pages, top-down",
|
|
|
|
|
length: 2 * hugepage,
|
|
|
|
|
huge: true,
|
|
|
|
|
dir: TopDown,
|
|
|
|
|
want: chunkSize - 2*hugepage,
|
2018-04-27 10:37:02 -07:00
|
|
|
},
|
|
|
|
|
{
|
2024-06-28 12:53:33 -07:00
|
|
|
name: "initial huge allocation, recycling enabled, bottom-up",
|
|
|
|
|
length: hugepage,
|
|
|
|
|
huge: true,
|
|
|
|
|
recycle: true,
|
|
|
|
|
want: 0,
|
2021-11-10 17:10:18 -08:00
|
|
|
},
|
|
|
|
|
{
|
2024-06-28 12:53:33 -07:00
|
|
|
name: "huge allocation uses huge pages in new chunk",
|
|
|
|
|
chunkHuge: []bool{false},
|
2021-11-10 17:10:18 -08:00
|
|
|
length: hugepage,
|
2024-06-28 12:53:33 -07:00
|
|
|
huge: true,
|
|
|
|
|
want: chunkSize,
|
2021-11-10 17:10:18 -08:00
|
|
|
},
|
|
|
|
|
{
|
2024-06-28 12:53:33 -07:00
|
|
|
name: "huge allocation uses huge pages in existing chunk",
|
|
|
|
|
chunkHuge: []bool{false, true},
|
2020-06-05 15:38:38 -07:00
|
|
|
length: hugepage,
|
2024-06-28 12:53:33 -07:00
|
|
|
huge: true,
|
|
|
|
|
want: chunkSize,
|
2018-07-16 18:18:06 -07:00
|
|
|
},
|
|
|
|
|
{
|
2024-06-28 12:53:33 -07:00
|
|
|
name: "hugepage-sized non-huge allocation uses small pages in new chunk",
|
|
|
|
|
chunkHuge: []bool{true},
|
2020-06-05 15:38:38 -07:00
|
|
|
length: hugepage,
|
2024-06-28 12:53:33 -07:00
|
|
|
want: chunkSize,
|
2020-06-05 15:38:38 -07:00
|
|
|
},
|
2020-06-16 16:14:26 -07:00
|
|
|
{
|
2024-06-28 12:53:33 -07:00
|
|
|
name: "hugepage-sized non-huge allocation uses small pages in existing chunk",
|
|
|
|
|
chunkHuge: []bool{true, false},
|
|
|
|
|
length: hugepage,
|
|
|
|
|
want: chunkSize,
|
2020-06-16 16:14:26 -07:00
|
|
|
},
|
2020-06-05 15:38:38 -07:00
|
|
|
{
|
2024-06-28 12:53:33 -07:00
|
|
|
name: "bottom-up small allocation begins at start of file",
|
|
|
|
|
chunkHuge: []bool{false},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{page, 2 * page, existingUsed},
|
2018-07-16 18:18:06 -07:00
|
|
|
},
|
2024-06-28 12:53:33 -07:00
|
|
|
length: page,
|
|
|
|
|
want: 0,
|
2018-07-16 18:18:06 -07:00
|
|
|
},
|
|
|
|
|
{
|
2024-06-28 12:53:33 -07:00
|
|
|
name: "top-down small allocation begins at end of last chunk",
|
|
|
|
|
chunkHuge: []bool{false},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{chunkSize - 2*page, chunkSize - page, existingUsed},
|
2020-06-05 15:38:38 -07:00
|
|
|
},
|
2024-06-28 12:53:33 -07:00
|
|
|
length: page,
|
|
|
|
|
dir: TopDown,
|
|
|
|
|
want: chunkSize - page,
|
2020-06-05 15:38:38 -07:00
|
|
|
},
|
|
|
|
|
{
|
2024-06-28 12:53:33 -07:00
|
|
|
name: "bottom-up huge allocation begins at start of file",
|
|
|
|
|
chunkHuge: []bool{true},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{hugepage, 2 * hugepage, existingUsed},
|
2020-06-05 15:38:38 -07:00
|
|
|
},
|
2024-06-28 12:53:33 -07:00
|
|
|
length: hugepage,
|
|
|
|
|
huge: true,
|
|
|
|
|
want: 0,
|
2020-06-05 15:38:38 -07:00
|
|
|
},
|
|
|
|
|
{
|
2024-06-28 12:53:33 -07:00
|
|
|
name: "top-down huge allocation begins at end of last chunk",
|
|
|
|
|
chunkHuge: []bool{true},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{chunkSize - 2*hugepage, chunkSize - hugepage, existingUsed},
|
2018-07-16 18:18:06 -07:00
|
|
|
},
|
2024-06-28 12:53:33 -07:00
|
|
|
length: hugepage,
|
|
|
|
|
huge: true,
|
|
|
|
|
dir: TopDown,
|
|
|
|
|
want: chunkSize - hugepage,
|
2020-06-05 15:38:38 -07:00
|
|
|
},
|
|
|
|
|
{
|
2024-06-28 12:53:33 -07:00
|
|
|
name: "bottom-up small allocation can extend multiple chunks",
|
|
|
|
|
chunkHuge: []bool{false},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{chunkSize/2 - page, chunkSize / 2, existingUsed},
|
2020-06-05 15:38:38 -07:00
|
|
|
},
|
2024-06-28 12:53:33 -07:00
|
|
|
length: 2*chunkSize + page,
|
|
|
|
|
want: chunkSize / 2,
|
2020-06-05 15:38:38 -07:00
|
|
|
},
|
|
|
|
|
{
|
2024-06-28 12:53:33 -07:00
|
|
|
name: "top-down small allocation can extend multiple chunks",
|
|
|
|
|
chunkHuge: []bool{false},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{chunkSize/2 - page, chunkSize / 2, existingUsed},
|
2020-06-05 15:38:38 -07:00
|
|
|
},
|
2024-06-28 12:53:33 -07:00
|
|
|
length: 2*chunkSize + page,
|
|
|
|
|
dir: TopDown,
|
|
|
|
|
want: chunkSize - page,
|
2018-04-27 10:37:02 -07:00
|
|
|
},
|
2021-11-10 17:10:18 -08:00
|
|
|
{
|
2024-06-28 12:53:33 -07:00
|
|
|
name: "bottom-up huge allocation can extend multiple chunks",
|
|
|
|
|
chunkHuge: []bool{true},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{chunkSize/2 - hugepage, chunkSize / 2, existingUsed},
|
2021-11-10 17:10:18 -08:00
|
|
|
},
|
2024-06-28 12:53:33 -07:00
|
|
|
length: 2*chunkSize + hugepage,
|
|
|
|
|
huge: true,
|
|
|
|
|
want: chunkSize / 2,
|
2021-11-10 17:10:18 -08:00
|
|
|
},
|
|
|
|
|
{
|
2024-06-28 12:53:33 -07:00
|
|
|
name: "top-down huge allocation can extend multiple chunks",
|
|
|
|
|
chunkHuge: []bool{true},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{chunkSize/2 - hugepage, chunkSize / 2, existingUsed},
|
2021-11-10 17:10:18 -08:00
|
|
|
},
|
2024-06-28 12:53:33 -07:00
|
|
|
length: 2*chunkSize + hugepage,
|
|
|
|
|
huge: true,
|
|
|
|
|
dir: TopDown,
|
|
|
|
|
want: chunkSize - hugepage,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "bottom-up small allocation finds first free gap",
|
|
|
|
|
chunkHuge: []bool{false},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{0, page, existingUsed},
|
|
|
|
|
{2 * page, 3 * page, existingUsed},
|
|
|
|
|
},
|
|
|
|
|
length: page,
|
|
|
|
|
want: page,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "top-down small allocation finds last free gap",
|
|
|
|
|
chunkHuge: []bool{false},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{chunkSize - page, chunkSize, existingUsed},
|
|
|
|
|
{chunkSize - 3*page, chunkSize - 2*page, existingUsed},
|
|
|
|
|
},
|
|
|
|
|
length: page,
|
|
|
|
|
dir: TopDown,
|
|
|
|
|
want: chunkSize - 2*page,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "bottom-up huge allocation finds first free gap",
|
|
|
|
|
chunkHuge: []bool{true},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{0, hugepage, existingUsed},
|
|
|
|
|
{2 * hugepage, 3 * hugepage, existingUsed},
|
|
|
|
|
},
|
|
|
|
|
length: hugepage,
|
|
|
|
|
huge: true,
|
|
|
|
|
want: hugepage,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "top-down huge allocation finds last free gap",
|
|
|
|
|
chunkHuge: []bool{true},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{chunkSize - hugepage, chunkSize, existingUsed},
|
|
|
|
|
{chunkSize - 3*hugepage, chunkSize - 2*hugepage, existingUsed},
|
|
|
|
|
},
|
|
|
|
|
length: hugepage,
|
|
|
|
|
huge: true,
|
|
|
|
|
dir: TopDown,
|
|
|
|
|
want: chunkSize - 2*hugepage,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "bottom-up small allocation skips undersized free gap",
|
|
|
|
|
chunkHuge: []bool{false},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{0, page, existingUsed},
|
|
|
|
|
{2 * page, 3 * page, existingUsed},
|
|
|
|
|
},
|
|
|
|
|
length: 2 * page,
|
|
|
|
|
want: 3 * page,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "top-down small allocation skips undersized free gap",
|
|
|
|
|
chunkHuge: []bool{false},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{chunkSize - page, chunkSize, existingUsed},
|
|
|
|
|
{chunkSize - 3*page, chunkSize - 2*page, existingUsed},
|
|
|
|
|
},
|
|
|
|
|
length: 2 * page,
|
|
|
|
|
dir: TopDown,
|
|
|
|
|
want: chunkSize - 5*page,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "bottom-up huge allocation skips undersized free gap",
|
|
|
|
|
chunkHuge: []bool{true},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{0, hugepage, existingUsed},
|
|
|
|
|
{2 * hugepage, 3 * hugepage, existingUsed},
|
|
|
|
|
},
|
|
|
|
|
length: 2 * hugepage,
|
|
|
|
|
huge: true,
|
|
|
|
|
want: 3 * hugepage,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "top-down huge allocation skips undersized free gap",
|
|
|
|
|
chunkHuge: []bool{true},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{chunkSize - hugepage, chunkSize, existingUsed},
|
|
|
|
|
{chunkSize - 3*hugepage, chunkSize - 2*hugepage, existingUsed},
|
|
|
|
|
},
|
|
|
|
|
length: 2 * hugepage,
|
|
|
|
|
huge: true,
|
|
|
|
|
dir: TopDown,
|
|
|
|
|
want: chunkSize - 5*hugepage,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "recycling bottom-up small allocation skips used pages",
|
|
|
|
|
chunkHuge: []bool{false},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{0, page, existingUsed},
|
|
|
|
|
},
|
|
|
|
|
length: page,
|
|
|
|
|
recycle: true,
|
|
|
|
|
want: page,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "recycling top-down small allocation skips used pages",
|
|
|
|
|
chunkHuge: []bool{false},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{chunkSize - page, chunkSize, existingUsed},
|
|
|
|
|
},
|
|
|
|
|
length: page,
|
|
|
|
|
recycle: true,
|
|
|
|
|
dir: TopDown,
|
|
|
|
|
want: chunkSize - 2*page,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "recycling bottom-up huge allocation skips used pages",
|
|
|
|
|
chunkHuge: []bool{true},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{0, hugepage, existingUsed},
|
|
|
|
|
},
|
|
|
|
|
length: hugepage,
|
|
|
|
|
huge: true,
|
|
|
|
|
recycle: true,
|
|
|
|
|
want: hugepage,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "recycling top-down huge allocation skips used pages",
|
|
|
|
|
chunkHuge: []bool{true},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{chunkSize - hugepage, chunkSize, existingUsed},
|
|
|
|
|
},
|
|
|
|
|
length: hugepage,
|
|
|
|
|
huge: true,
|
|
|
|
|
recycle: true,
|
|
|
|
|
dir: TopDown,
|
|
|
|
|
want: chunkSize - 2*hugepage,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "non-recycling bottom-up small allocation skips waste pages",
|
|
|
|
|
chunkHuge: []bool{false},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{0, page, existingWaste},
|
|
|
|
|
},
|
|
|
|
|
length: page,
|
|
|
|
|
want: page,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "non-recycling top-down small allocation skips waste pages",
|
|
|
|
|
chunkHuge: []bool{false},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{chunkSize - page, chunkSize, existingWaste},
|
|
|
|
|
},
|
|
|
|
|
length: page,
|
|
|
|
|
dir: TopDown,
|
|
|
|
|
want: chunkSize - 2*page,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "non-recycling bottom-up huge allocation skips waste pages",
|
|
|
|
|
chunkHuge: []bool{true},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{0, hugepage, existingWaste},
|
|
|
|
|
},
|
|
|
|
|
length: hugepage,
|
|
|
|
|
huge: true,
|
|
|
|
|
want: hugepage,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "non-recycling top-down huge allocation skips waste pages",
|
|
|
|
|
chunkHuge: []bool{true},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{chunkSize - hugepage, chunkSize, existingWaste},
|
|
|
|
|
},
|
|
|
|
|
length: hugepage,
|
|
|
|
|
huge: true,
|
|
|
|
|
dir: TopDown,
|
|
|
|
|
want: chunkSize - 2*hugepage,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "recycling bottom-up small allocation recycles waste pages",
|
|
|
|
|
chunkHuge: []bool{false},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{0, page, existingWaste},
|
|
|
|
|
},
|
|
|
|
|
length: page,
|
|
|
|
|
recycle: true,
|
|
|
|
|
want: 0,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "recycling top-down small allocation recycles waste pages",
|
|
|
|
|
chunkHuge: []bool{false},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{chunkSize - page, chunkSize, existingWaste},
|
|
|
|
|
},
|
|
|
|
|
length: page,
|
|
|
|
|
recycle: true,
|
|
|
|
|
dir: TopDown,
|
|
|
|
|
want: chunkSize - page,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "recycling bottom-up huge allocation recycles waste pages",
|
|
|
|
|
chunkHuge: []bool{true},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{0, hugepage, existingWaste},
|
|
|
|
|
},
|
|
|
|
|
length: hugepage,
|
|
|
|
|
huge: true,
|
|
|
|
|
recycle: true,
|
|
|
|
|
want: 0,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "recycling top-down huge allocation recycles waste pages",
|
|
|
|
|
chunkHuge: []bool{true},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{chunkSize - hugepage, chunkSize, existingWaste},
|
|
|
|
|
},
|
|
|
|
|
length: hugepage,
|
|
|
|
|
huge: true,
|
|
|
|
|
recycle: true,
|
|
|
|
|
dir: TopDown,
|
|
|
|
|
want: chunkSize - hugepage,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "non-recycling bottom-up small allocation skips releasing pages",
|
|
|
|
|
chunkHuge: []bool{false},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{0, page, existingReleasing},
|
|
|
|
|
},
|
|
|
|
|
length: page,
|
|
|
|
|
want: page,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "non-recycling top-down small allocation skips releasing pages",
|
|
|
|
|
chunkHuge: []bool{false},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{chunkSize - page, chunkSize, existingReleasing},
|
|
|
|
|
},
|
|
|
|
|
length: page,
|
|
|
|
|
dir: TopDown,
|
|
|
|
|
want: chunkSize - 2*page,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "non-recycling bottom-up huge allocation skips releasing pages",
|
|
|
|
|
chunkHuge: []bool{true},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{0, hugepage, existingReleasing},
|
|
|
|
|
},
|
|
|
|
|
length: hugepage,
|
|
|
|
|
huge: true,
|
|
|
|
|
want: hugepage,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "non-recycling top-down huge allocation skips releasing pages",
|
|
|
|
|
chunkHuge: []bool{true},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{chunkSize - hugepage, chunkSize, existingReleasing},
|
|
|
|
|
},
|
|
|
|
|
length: hugepage,
|
|
|
|
|
huge: true,
|
|
|
|
|
dir: TopDown,
|
|
|
|
|
want: chunkSize - 2*hugepage,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "recycling bottom-up small allocation skips releasing pages",
|
|
|
|
|
chunkHuge: []bool{false},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{0, page, existingReleasing},
|
|
|
|
|
},
|
|
|
|
|
length: page,
|
|
|
|
|
recycle: true,
|
|
|
|
|
want: page,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "recycling top-down small allocation skips releasing pages",
|
|
|
|
|
chunkHuge: []bool{false},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{chunkSize - page, chunkSize, existingReleasing},
|
|
|
|
|
},
|
|
|
|
|
length: page,
|
|
|
|
|
recycle: true,
|
|
|
|
|
dir: TopDown,
|
|
|
|
|
want: chunkSize - 2*page,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "recycling bottom-up huge allocation skips releasing pages",
|
|
|
|
|
chunkHuge: []bool{true},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{0, hugepage, existingReleasing},
|
|
|
|
|
},
|
|
|
|
|
length: hugepage,
|
|
|
|
|
huge: true,
|
|
|
|
|
recycle: true,
|
|
|
|
|
want: hugepage,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "recycling top-down huge allocation skips releasing pages",
|
|
|
|
|
chunkHuge: []bool{true},
|
|
|
|
|
existing: []existingSegment{
|
|
|
|
|
{chunkSize - hugepage, chunkSize, existingReleasing},
|
|
|
|
|
},
|
|
|
|
|
length: hugepage,
|
|
|
|
|
huge: true,
|
|
|
|
|
recycle: true,
|
|
|
|
|
dir: TopDown,
|
|
|
|
|
want: chunkSize - 2*hugepage,
|
2021-11-10 17:10:18 -08:00
|
|
|
},
|
2018-04-27 10:37:02 -07:00
|
|
|
} {
|
2024-06-28 12:53:33 -07:00
|
|
|
t.Run(test.name, func(t *testing.T) {
|
|
|
|
|
// Build the fake MemoryFile.
|
|
|
|
|
f := &MemoryFile{
|
|
|
|
|
opts: MemoryFileOpts{
|
|
|
|
|
ExpectHugepages: true,
|
|
|
|
|
DisableMemoryAccounting: true,
|
|
|
|
|
},
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
2024-06-28 12:53:33 -07:00
|
|
|
f.initFields()
|
|
|
|
|
chunks := make([]chunkInfo, len(test.chunkHuge))
|
|
|
|
|
for i, huge := range test.chunkHuge {
|
|
|
|
|
chunks[i].huge = huge
|
|
|
|
|
chunkFR := memmap.FileRange{uint64(i) * chunkSize, uint64(i+1) * chunkSize}
|
|
|
|
|
if huge {
|
|
|
|
|
f.unfreeHuge.RemoveRange(chunkFR)
|
|
|
|
|
} else {
|
|
|
|
|
f.unfreeSmall.RemoveRange(chunkFR)
|
2021-11-10 17:10:18 -08:00
|
|
|
}
|
2024-06-28 12:53:33 -07:00
|
|
|
}
|
|
|
|
|
f.chunks.Store(&chunks)
|
|
|
|
|
for _, es := range test.existing {
|
|
|
|
|
f.forEachChunk(memmap.FileRange{es.start, es.end}, func(chunk *chunkInfo, chunkFR memmap.FileRange) bool {
|
|
|
|
|
unwaste, unfree := &f.unwasteSmall, &f.unfreeSmall
|
|
|
|
|
if chunk.huge {
|
|
|
|
|
unwaste, unfree = &f.unwasteHuge, &f.unfreeHuge
|
|
|
|
|
}
|
|
|
|
|
switch es.state {
|
|
|
|
|
case existingUsed:
|
|
|
|
|
unfree.InsertRange(chunkFR, unfreeInfo{refs: 1})
|
|
|
|
|
case existingWaste:
|
|
|
|
|
unfree.InsertRange(chunkFR, unfreeInfo{refs: 0})
|
|
|
|
|
unwaste.RemoveRange(chunkFR)
|
|
|
|
|
case existingReleasing:
|
|
|
|
|
unfree.InsertRange(chunkFR, unfreeInfo{refs: 0})
|
|
|
|
|
default:
|
|
|
|
|
t.Fatalf("existingSegment %+v has unknown state", es)
|
|
|
|
|
}
|
|
|
|
|
f.memAcct.InsertRange(chunkFR, memAcctInfo{
|
|
|
|
|
wasteOrReleasing: es.state != existingUsed,
|
|
|
|
|
})
|
|
|
|
|
return true
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Perform the test allocation.
|
|
|
|
|
alloc := allocState{
|
|
|
|
|
length: test.length,
|
|
|
|
|
opts: AllocOpts{
|
|
|
|
|
Huge: test.huge,
|
|
|
|
|
Dir: test.dir,
|
|
|
|
|
},
|
|
|
|
|
huge: test.huge,
|
|
|
|
|
}
|
|
|
|
|
if test.recycle {
|
|
|
|
|
alloc.opts.Mode = AllocateCallerIndirectCommit
|
|
|
|
|
alloc.willCommit = true
|
|
|
|
|
}
|
|
|
|
|
fr, err := f.findAllocatableAndMarkUsed(&alloc)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("findAllocatableAndMarkUsed(%+v): failed: %v, want: %#x\n%v", alloc, err, test.want, f)
|
|
|
|
|
}
|
|
|
|
|
if fr.Start != test.want {
|
|
|
|
|
t.Errorf("findAllocatableAndMarkUsed(%+v): got: start=%#x, want: %#x\n%v", alloc, fr.Start, test.want, f)
|
|
|
|
|
}
|
|
|
|
|
if wantEnd := test.want + test.length; fr.End != wantEnd {
|
|
|
|
|
t.Errorf("findAllocatableAndMarkUsed(%+v): got: end=%#x, want: %#x\n%v", alloc, fr.End, wantEnd, f)
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|