Skip to content

Commit 6ff0420

Browse files
authored
Merge pull request #3234 from kolyshkin/hugepage-v2
libct/cg: refactor/improve/rename GetHugePageSize -> HugePageSizes
2 parents 19d696e + 1da84d1 commit 6ff0420

File tree

6 files changed

+110
-101
lines changed

6 files changed

+110
-101
lines changed

libcontainer/cgroups/fs/fs.go

+16-19
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,22 @@ import (
1313
"github.com/opencontainers/runc/libcontainer/configs"
1414
)
1515

16-
var (
17-
subsystems = []subsystem{
18-
&CpusetGroup{},
19-
&DevicesGroup{},
20-
&MemoryGroup{},
21-
&CpuGroup{},
22-
&CpuacctGroup{},
23-
&PidsGroup{},
24-
&BlkioGroup{},
25-
&HugetlbGroup{},
26-
&NetClsGroup{},
27-
&NetPrioGroup{},
28-
&PerfEventGroup{},
29-
&FreezerGroup{},
30-
&RdmaGroup{},
31-
&NameGroup{GroupName: "name=systemd", Join: true},
32-
}
33-
HugePageSizes, _ = cgroups.GetHugePageSize()
34-
)
16+
var subsystems = []subsystem{
17+
&CpusetGroup{},
18+
&DevicesGroup{},
19+
&MemoryGroup{},
20+
&CpuGroup{},
21+
&CpuacctGroup{},
22+
&PidsGroup{},
23+
&BlkioGroup{},
24+
&HugetlbGroup{},
25+
&NetClsGroup{},
26+
&NetPrioGroup{},
27+
&PerfEventGroup{},
28+
&FreezerGroup{},
29+
&RdmaGroup{},
30+
&NameGroup{GroupName: "name=systemd", Join: true},
31+
}
3532

3633
var errSubsystemDoesNotExist = errors.New("cgroup: subsystem does not exist")
3734

libcontainer/cgroups/fs/hugetlb.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ func (s *HugetlbGroup) Set(path string, r *configs.Resources) error {
2929
}
3030

3131
func (s *HugetlbGroup) GetStats(path string, stats *cgroups.Stats) error {
32-
hugetlbStats := cgroups.HugetlbStats{}
3332
if !cgroups.PathExists(path) {
3433
return nil
3534
}
36-
for _, pageSize := range HugePageSizes {
35+
hugetlbStats := cgroups.HugetlbStats{}
36+
for _, pageSize := range cgroups.HugePageSizes() {
3737
usage := "hugetlb." + pageSize + ".usage_in_bytes"
3838
value, err := fscommon.GetCgroupParamUint(path, usage)
3939
if err != nil {

libcontainer/cgroups/fs/hugetlb_test.go

+7-7
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@ func TestHugetlbSetHugetlb(t *testing.T) {
3131
hugetlbAfter = 512
3232
)
3333

34-
for _, pageSize := range HugePageSizes {
34+
for _, pageSize := range cgroups.HugePageSizes() {
3535
writeFileContents(t, path, map[string]string{
3636
fmt.Sprintf(limit, pageSize): strconv.Itoa(hugetlbBefore),
3737
})
3838
}
3939

4040
r := &configs.Resources{}
41-
for _, pageSize := range HugePageSizes {
41+
for _, pageSize := range cgroups.HugePageSizes() {
4242
r.HugetlbLimit = []*configs.HugepageLimit{
4343
{
4444
Pagesize: pageSize,
@@ -51,7 +51,7 @@ func TestHugetlbSetHugetlb(t *testing.T) {
5151
}
5252
}
5353

54-
for _, pageSize := range HugePageSizes {
54+
for _, pageSize := range cgroups.HugePageSizes() {
5555
limit := fmt.Sprintf(limit, pageSize)
5656
value, err := fscommon.GetCgroupParamUint(path, limit)
5757
if err != nil {
@@ -65,7 +65,7 @@ func TestHugetlbSetHugetlb(t *testing.T) {
6565

6666
func TestHugetlbStats(t *testing.T) {
6767
path := tempDir(t, "hugetlb")
68-
for _, pageSize := range HugePageSizes {
68+
for _, pageSize := range cgroups.HugePageSizes() {
6969
writeFileContents(t, path, map[string]string{
7070
fmt.Sprintf(usage, pageSize): hugetlbUsageContents,
7171
fmt.Sprintf(maxUsage, pageSize): hugetlbMaxUsageContents,
@@ -80,7 +80,7 @@ func TestHugetlbStats(t *testing.T) {
8080
t.Fatal(err)
8181
}
8282
expectedStats := cgroups.HugetlbStats{Usage: 128, MaxUsage: 256, Failcnt: 100}
83-
for _, pageSize := range HugePageSizes {
83+
for _, pageSize := range cgroups.HugePageSizes() {
8484
expectHugetlbStatEquals(t, expectedStats, actualStats.HugetlbStats[pageSize])
8585
}
8686
}
@@ -101,7 +101,7 @@ func TestHugetlbStatsNoUsageFile(t *testing.T) {
101101

102102
func TestHugetlbStatsNoMaxUsageFile(t *testing.T) {
103103
path := tempDir(t, "hugetlb")
104-
for _, pageSize := range HugePageSizes {
104+
for _, pageSize := range cgroups.HugePageSizes() {
105105
writeFileContents(t, path, map[string]string{
106106
fmt.Sprintf(usage, pageSize): hugetlbUsageContents,
107107
})
@@ -117,7 +117,7 @@ func TestHugetlbStatsNoMaxUsageFile(t *testing.T) {
117117

118118
func TestHugetlbStatsBadUsageFile(t *testing.T) {
119119
path := tempDir(t, "hugetlb")
120-
for _, pageSize := range HugePageSizes {
120+
for _, pageSize := range cgroups.HugePageSizes() {
121121
writeFileContents(t, path, map[string]string{
122122
fmt.Sprintf(usage, pageSize): "bad",
123123
maxUsage: hugetlbMaxUsageContents,

libcontainer/cgroups/fs2/hugetlb.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,8 @@ func setHugeTlb(dirPath string, r *configs.Resources) error {
2626
}
2727

2828
func statHugeTlb(dirPath string, stats *cgroups.Stats) error {
29-
hugePageSizes, _ := cgroups.GetHugePageSize()
3029
hugetlbStats := cgroups.HugetlbStats{}
31-
32-
for _, pagesize := range hugePageSizes {
30+
for _, pagesize := range cgroups.HugePageSizes() {
3331
value, err := fscommon.GetCgroupParamUint(dirPath, "hugetlb."+pagesize+".current")
3432
if err != nil {
3533
return err

libcontainer/cgroups/utils.go

+37-16
Original file line numberDiff line numberDiff line change
@@ -302,40 +302,61 @@ func RemovePaths(paths map[string]string) (err error) {
302302
return fmt.Errorf("Failed to remove paths: %v", paths)
303303
}
304304

305-
func GetHugePageSize() ([]string, error) {
306-
dir, err := os.OpenFile("/sys/kernel/mm/hugepages", unix.O_DIRECTORY|unix.O_RDONLY, 0)
307-
if err != nil {
308-
return nil, err
309-
}
310-
files, err := dir.Readdirnames(0)
311-
dir.Close()
312-
if err != nil {
313-
return nil, err
314-
}
305+
var (
306+
hugePageSizes []string
307+
initHPSOnce sync.Once
308+
)
315309

316-
return getHugePageSizeFromFilenames(files)
310+
func HugePageSizes() []string {
311+
initHPSOnce.Do(func() {
312+
dir, err := os.OpenFile("/sys/kernel/mm/hugepages", unix.O_DIRECTORY|unix.O_RDONLY, 0)
313+
if err != nil {
314+
return
315+
}
316+
files, err := dir.Readdirnames(0)
317+
dir.Close()
318+
if err != nil {
319+
return
320+
}
321+
322+
hugePageSizes, err = getHugePageSizeFromFilenames(files)
323+
if err != nil {
324+
logrus.Warn("HugePageSizes: ", err)
325+
}
326+
})
327+
328+
return hugePageSizes
317329
}
318330

319331
func getHugePageSizeFromFilenames(fileNames []string) ([]string, error) {
320332
pageSizes := make([]string, 0, len(fileNames))
333+
var warn error
321334

322335
for _, file := range fileNames {
323336
// example: hugepages-1048576kB
324337
val := strings.TrimPrefix(file, "hugepages-")
325338
if len(val) == len(file) {
326-
// unexpected file name: no prefix found
339+
// Unexpected file name: no prefix found, ignore it.
327340
continue
328341
}
329-
// The suffix is always "kB" (as of Linux 5.9)
342+
// The suffix is always "kB" (as of Linux 5.13). If we find
343+
// something else, produce an error but keep going.
330344
eLen := len(val) - 2
331345
val = strings.TrimSuffix(val, "kB")
332346
if len(val) != eLen {
333-
logrus.Warnf("GetHugePageSize: %s: invalid filename suffix (expected \"kB\")", file)
347+
// Highly unlikely.
348+
if warn == nil {
349+
warn = errors.New(file + `: invalid suffix (expected "kB")`)
350+
}
334351
continue
335352
}
336353
size, err := strconv.Atoi(val)
337354
if err != nil {
338-
return nil, err
355+
// Highly unlikely.
356+
if warn == nil {
357+
warn = fmt.Errorf("%s: %w", file, err)
358+
}
359+
continue
339360
}
340361
// Model after https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/mm/hugetlb_cgroup.c?id=eff48ddeab782e35e58ccc8853f7386bbae9dec4#n574
341362
// but in our case the size is in KB already.
@@ -349,7 +370,7 @@ func getHugePageSizeFromFilenames(fileNames []string) ([]string, error) {
349370
pageSizes = append(pageSizes, val)
350371
}
351372

352-
return pageSizes, nil
373+
return pageSizes, warn
353374
}
354375

355376
// GetPids returns all pids, that were added to cgroup at path.

libcontainer/cgroups/utils_test.go

+47-54
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"testing"
99

1010
"github.com/moby/sys/mountinfo"
11-
"github.com/sirupsen/logrus"
1211
)
1312

1413
const fedoraMountinfo = `15 35 0:3 / /proc rw,nosuid,nodev,noexec,relatime shared:5 - proc proc rw
@@ -448,19 +447,6 @@ func TestFindCgroupMountpointAndRoot(t *testing.T) {
448447
}
449448
}
450449

451-
func BenchmarkGetHugePageSize(b *testing.B) {
452-
var (
453-
output []string
454-
err error
455-
)
456-
for i := 0; i < b.N; i++ {
457-
output, err = GetHugePageSize()
458-
}
459-
if err != nil || len(output) == 0 {
460-
b.Fatal("unexpected results")
461-
}
462-
}
463-
464450
func BenchmarkGetHugePageSizeImpl(b *testing.B) {
465451
var (
466452
input = []string{"hugepages-1048576kB", "hugepages-2048kB", "hugepages-32768kB", "hugepages-64kB"}
@@ -477,71 +463,78 @@ func BenchmarkGetHugePageSizeImpl(b *testing.B) {
477463

478464
func TestGetHugePageSizeImpl(t *testing.T) {
479465
testCases := []struct {
466+
doc string
480467
input []string
481468
output []string
482469
isErr bool
483-
isWarn bool
484470
}{
485471
{
472+
doc: "normal input",
486473
input: []string{"hugepages-1048576kB", "hugepages-2048kB", "hugepages-32768kB", "hugepages-64kB"},
487474
output: []string{"1GB", "2MB", "32MB", "64KB"},
488475
},
489476
{
477+
doc: "empty input",
490478
input: []string{},
491479
output: []string{},
492480
},
493-
{ // not a number
481+
{
482+
doc: "not a number",
494483
input: []string{"hugepages-akB"},
495484
isErr: true,
496485
},
497-
{ // no prefix (silently skipped)
486+
{
487+
doc: "no prefix (silently skipped)",
498488
input: []string{"1024kB"},
499489
},
500-
{ // invalid prefix (silently skipped)
490+
{
491+
doc: "invalid prefix (silently skipped)",
501492
input: []string{"whatever-1024kB"},
502493
},
503-
{ // invalid suffix (skipped with a warning)
504-
input: []string{"hugepages-1024gB"},
505-
isWarn: true,
494+
{
495+
doc: "invalid suffix",
496+
input: []string{"hugepages-1024gB"},
497+
isErr: true,
506498
},
507-
{ // no suffix (skipped with a warning)
508-
input: []string{"hugepages-1024"},
509-
isWarn: true,
499+
{
500+
doc: "no suffix",
501+
input: []string{"hugepages-1024"},
502+
isErr: true,
503+
},
504+
{
505+
doc: "mixed valid and invalid entries",
506+
input: []string{"hugepages-4194304kB", "hugepages-2048kB", "hugepages-akB", "hugepages-64kB"},
507+
output: []string{"4GB", "2MB", "64KB"},
508+
isErr: true,
509+
},
510+
{
511+
doc: "more mixed valid and invalid entries",
512+
input: []string{"hugepages-2048kB", "hugepages-kB", "hugepages-64kB"},
513+
output: []string{"2MB", "64KB"},
514+
isErr: true,
510515
},
511516
}
512517

513-
// Need to catch warnings.
514-
savedOut := logrus.StandardLogger().Out
515-
defer logrus.SetOutput(savedOut)
516-
warns := new(bytes.Buffer)
517-
logrus.SetOutput(warns)
518-
519518
for _, c := range testCases {
520-
warns.Reset()
521-
output, err := getHugePageSizeFromFilenames(c.input)
522-
if err != nil {
523-
if !c.isErr {
524-
t.Errorf("input %v, expected nil, got error: %v", c.input, err)
519+
c := c
520+
t.Run(c.doc, func(t *testing.T) {
521+
output, err := getHugePageSizeFromFilenames(c.input)
522+
t.Log("input:", c.input, "; output:", output, "; err:", err)
523+
if err != nil {
524+
if !c.isErr {
525+
t.Errorf("input %v, expected nil, got error: %v", c.input, err)
526+
}
527+
// no more checks
528+
return
525529
}
526-
// no more checks
527-
continue
528-
}
529-
if c.isErr {
530-
t.Errorf("input %v, expected error, got error: nil, output: %v", c.input, output)
531-
// no more checks
532-
continue
533-
}
534-
// check for warnings
535-
if c.isWarn && warns.Len() == 0 {
536-
t.Errorf("input %v, expected a warning, got none", c.input)
537-
}
538-
if !c.isWarn && warns.Len() > 0 {
539-
t.Errorf("input %v, unexpected warning: %s", c.input, warns.String())
540-
}
541-
// check output
542-
if len(output) != len(c.output) || (len(output) > 0 && !reflect.DeepEqual(output, c.output)) {
543-
t.Errorf("input %v, expected %v, got %v", c.input, c.output, output)
544-
}
530+
if c.isErr {
531+
t.Errorf("input %v, expected error, got error: nil, output: %v", c.input, output)
532+
}
533+
// check output
534+
if len(output) != len(c.output) || (len(output) > 0 && !reflect.DeepEqual(output, c.output)) {
535+
t.Errorf("input %v, expected %v, got %v", c.input, c.output, output)
536+
}
537+
})
545538
}
546539
}
547540

0 commit comments

Comments
 (0)