Skip to content

Commit c883678

Browse files
author
Paweł Szulik
committed
intelrdt: Add Cache Monitoring Technology stats
Signed-off-by: Paweł Szulik <[email protected]>
1 parent d1e4c7b commit c883678

File tree

10 files changed

+334
-169
lines changed

10 files changed

+334
-169
lines changed

events.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,12 @@ func convertLibcontainerStats(ls *libcontainer.Stats) *types.Stats {
161161
s.IntelRdt.MemBwSchemaRoot = is.MemBwSchemaRoot
162162
s.IntelRdt.MemBwSchema = is.MemBwSchema
163163
}
164-
if intelrdt.IsMbmEnabled() {
164+
if intelrdt.IsMBMEnabled() {
165165
s.IntelRdt.MBMStats = is.MBMStats
166166
}
167+
if intelrdt.IsCMTEnabled() {
168+
s.IntelRdt.CMTStats = is.CMTStats
169+
}
167170
}
168171

169172
s.NetworkInterfaces = ls.Interfaces

libcontainer/intelrdt/cmt.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package intelrdt
2+
3+
var (
4+
cmtEnabled bool
5+
)
6+
7+
// Check if Intel RDT/CMT is enabled.
8+
func IsCMTEnabled() bool {
9+
return cmtEnabled
10+
}
11+
12+
func getCMTNumaNodeStats(numaPath string) (*CMTNumaNodeStats, error) {
13+
stats := &CMTNumaNodeStats{}
14+
15+
llcOccupancy, err := getIntelRdtParamUint(numaPath, "llc_occupancy")
16+
if err != nil {
17+
return nil, err
18+
}
19+
stats.LLCOccupancy = llcOccupancy
20+
21+
return stats, nil
22+
}

libcontainer/intelrdt/cmt_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package intelrdt
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"testing"
7+
)
8+
9+
func TestGetCMTNumaNodeStats(t *testing.T) {
10+
mocksNUMANodesToCreate := []string{"mon_l3_00", "mon_l3_01"}
11+
12+
mocksFilesToCreate := map[string]uint64{
13+
"llc_occupancy": 9123911,
14+
}
15+
16+
mockedL3_MON, err := mockResctrlL3_MON(mocksNUMANodesToCreate, mocksFilesToCreate)
17+
18+
defer func() {
19+
err := os.RemoveAll(mockedL3_MON)
20+
if err != nil {
21+
t.Fatal(err)
22+
}
23+
}()
24+
25+
if err != nil {
26+
t.Fatal(err)
27+
}
28+
29+
t.Run("Gather mbm", func(t *testing.T) {
30+
enabledMonFeatures.llcOccupancy = true
31+
32+
stats := make([]CMTNumaNodeStats, 0, len(mocksNUMANodesToCreate))
33+
for _, numa := range mocksNUMANodesToCreate {
34+
other, err := getCMTNumaNodeStats(filepath.Join(mockedL3_MON, "mon_data", numa))
35+
if err != nil {
36+
t.Fatal(err)
37+
}
38+
stats = append(stats, *other)
39+
}
40+
41+
expectedStats := CMTNumaNodeStats{
42+
LLCOccupancy: mocksFilesToCreate["llc_occupancy"],
43+
}
44+
45+
checkCMTStatCorrection(stats[0], expectedStats, t)
46+
checkCMTStatCorrection(stats[1], expectedStats, t)
47+
})
48+
}
49+
50+
func checkCMTStatCorrection(got CMTNumaNodeStats, expected CMTNumaNodeStats, t *testing.T) {
51+
if got.LLCOccupancy != expected.LLCOccupancy {
52+
t.Fatalf("Wrong value of `llc_occupancy`. Expected: %v but got: %v",
53+
expected.LLCOccupancy,
54+
got.LLCOccupancy)
55+
}
56+
}

libcontainer/intelrdt/intelrdt.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,8 @@ func init() {
228228

229229
if flagsSet.MBMTotal || flagsSet.MBMLocal {
230230
if _, err := os.Stat(filepath.Join(intelRdtRoot, "info", "L3_MON")); err == nil {
231-
isMbmEnabled = true
231+
mbmEnabled = true
232+
cmtEnabled = true
232233
}
233234

234235
enabledMonFeatures, err = getMonFeatures(intelRdtRoot)
@@ -665,12 +666,9 @@ func (m *IntelRdtManager) GetStats() (*Stats, error) {
665666
}
666667
}
667668

668-
if IsMbmEnabled() {
669-
mbmStats, err := getMBMStats(containerPath)
670-
if err != nil {
671-
return stats, err
672-
}
673-
stats.MBMStats = mbmStats
669+
err = getMonitoringStats(containerPath, stats)
670+
if err != nil {
671+
return nil, err
674672
}
675673

676674
return stats, nil

libcontainer/intelrdt/mbm.go

Lines changed: 4 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -2,82 +2,14 @@
22

33
package intelrdt
44

5-
import (
6-
"bufio"
7-
"io"
8-
"io/ioutil"
9-
"os"
10-
"path/filepath"
11-
12-
"github.com/sirupsen/logrus"
13-
)
14-
155
var (
166
// The flag to indicate if Intel RDT/MBM is enabled
17-
isMbmEnabled bool
18-
19-
enabledMonFeatures monFeatures
7+
mbmEnabled bool
208
)
219

22-
type monFeatures struct {
23-
mbmTotalBytes bool
24-
mbmLocalBytes bool
25-
}
26-
27-
// Check if Intel RDT/MBM is enabled
28-
func IsMbmEnabled() bool {
29-
return isMbmEnabled
30-
}
31-
32-
func getMonFeatures(intelRdtRoot string) (monFeatures, error) {
33-
file, err := os.Open(filepath.Join(intelRdtRoot, "info", "L3_MON", "mon_features"))
34-
defer file.Close()
35-
if err != nil {
36-
return monFeatures{}, err
37-
}
38-
return parseMonFeatures(file)
39-
}
40-
41-
func parseMonFeatures(reader io.Reader) (monFeatures, error) {
42-
scanner := bufio.NewScanner(reader)
43-
44-
monFeatures := monFeatures{}
45-
46-
for scanner.Scan() {
47-
48-
switch feature := scanner.Text(); feature {
49-
50-
case "mbm_total_bytes":
51-
monFeatures.mbmTotalBytes = true
52-
case "mbm_local_bytes":
53-
monFeatures.mbmLocalBytes = true
54-
default:
55-
logrus.Warnf("Unsupported Intel RDT monitoring feature: %s", feature)
56-
}
57-
}
58-
59-
return monFeatures, scanner.Err()
60-
}
61-
62-
func getMBMStats(containerPath string) (*[]MBMNumaNodeStats, error) {
63-
var mbmStats []MBMNumaNodeStats
64-
65-
numaFiles, err := ioutil.ReadDir(filepath.Join(containerPath, "mon_data"))
66-
if err != nil {
67-
return &mbmStats, err
68-
}
69-
70-
for _, file := range numaFiles {
71-
if file.IsDir() {
72-
numaStats, err := getMBMNumaNodeStats(filepath.Join(containerPath, "mon_data", file.Name()))
73-
if err != nil {
74-
return &mbmStats, nil
75-
}
76-
mbmStats = append(mbmStats, *numaStats)
77-
}
78-
}
79-
80-
return &mbmStats, nil
10+
// Check if Intel RDT/MBM is enabled.
11+
func IsMBMEnabled() bool {
12+
return mbmEnabled
8113
}
8214

8315
func getMBMNumaNodeStats(numaPath string) (*MBMNumaNodeStats, error) {

libcontainer/intelrdt/mbm_test.go

Lines changed: 26 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -3,82 +3,23 @@
33
package intelrdt
44

55
import (
6-
"io/ioutil"
76
"os"
87
"path/filepath"
9-
"strconv"
10-
"strings"
118
"testing"
129
)
1310

14-
func TestParseMonFeatures(t *testing.T) {
15-
t.Run("All features available", func(t *testing.T) {
16-
parsedMonFeatures, err := parseMonFeatures(
17-
strings.NewReader("mbm_total_bytes\nmbm_local_bytes"))
18-
if err != nil {
19-
t.Errorf("Error while parsing mon features err = %v", err)
20-
}
21-
22-
expectedMonFeatures := monFeatures{true, true}
23-
24-
if parsedMonFeatures != expectedMonFeatures {
25-
t.Error("Cannot gather all features!")
26-
}
27-
})
28-
29-
t.Run("No features available", func(t *testing.T) {
30-
parsedMonFeatures, err := parseMonFeatures(strings.NewReader(""))
31-
32-
if err != nil {
33-
t.Errorf("Error while parsing mon features err = %v", err)
34-
}
35-
36-
expectedMonFeatures := monFeatures{false, false}
37-
38-
if parsedMonFeatures != expectedMonFeatures {
39-
t.Error("Expected no features available but there is any!")
40-
}
41-
})
42-
}
43-
44-
func mockMBM(NUMANodes []string, mocks map[string]uint64) (string, error) {
45-
testDir, err := ioutil.TempDir("", "rdt_mbm_test")
46-
if err != nil {
47-
return "", err
48-
}
49-
monDataPath := filepath.Join(testDir, "mon_data")
50-
51-
for _, numa := range NUMANodes {
52-
numaPath := filepath.Join(monDataPath, numa)
53-
err = os.MkdirAll(numaPath, os.ModePerm)
54-
if err != nil {
55-
return "", err
56-
}
57-
58-
for fileName, value := range mocks {
59-
err := ioutil.WriteFile(filepath.Join(numaPath, fileName), []byte(strconv.FormatUint(value, 10)), 777)
60-
if err != nil {
61-
return "", err
62-
}
63-
}
64-
65-
}
66-
67-
return testDir, nil
68-
}
69-
70-
func TestGetMbmStats(t *testing.T) {
11+
func TestGetMBMNumaNodeStats(t *testing.T) {
7112
mocksNUMANodesToCreate := []string{"mon_l3_00", "mon_l3_01"}
7213

7314
mocksFilesToCreate := map[string]uint64{
7415
"mbm_total_bytes": 9123911,
7516
"mbm_local_bytes": 2361361,
7617
}
7718

78-
mockedMBM, err := mockMBM(mocksNUMANodesToCreate, mocksFilesToCreate)
19+
mockedL3_MON, err := mockResctrlL3_MON(mocksNUMANodesToCreate, mocksFilesToCreate)
7920

8021
defer func() {
81-
err := os.RemoveAll(mockedMBM)
22+
err := os.RemoveAll(mockedL3_MON)
8223
if err != nil {
8324
t.Fatal(err)
8425
}
@@ -92,37 +33,36 @@ func TestGetMbmStats(t *testing.T) {
9233
enabledMonFeatures.mbmTotalBytes = true
9334
enabledMonFeatures.mbmLocalBytes = true
9435

95-
stats, err := getMBMStats(mockedMBM)
96-
if err != nil {
97-
t.Fatal(err)
98-
}
99-
100-
if len(*stats) != len(mocksNUMANodesToCreate) {
101-
t.Fatalf("Wrong number of stats slices from NUMA nodes. Expected: %v but got: %v",
102-
len(mocksNUMANodesToCreate), len(*stats))
103-
}
104-
105-
checkStatCorrection := func(got MBMNumaNodeStats, expected MBMNumaNodeStats, t *testing.T) {
106-
if got.MBMTotalBytes != expected.MBMTotalBytes {
107-
t.Fatalf("Wrong value of mbm_total_bytes. Expected: %v but got: %v",
108-
expected.MBMTotalBytes,
109-
got.MBMTotalBytes)
110-
}
111-
112-
if got.MBMLocalBytes != expected.MBMLocalBytes {
113-
t.Fatalf("Wrong value of mbm_local_bytes. Expected: %v but got: %v",
114-
expected.MBMLocalBytes,
115-
got.MBMLocalBytes)
36+
stats := make([]MBMNumaNodeStats, 0, len(mocksNUMANodesToCreate))
37+
for _, numa := range mocksNUMANodesToCreate {
38+
other, err := getMBMNumaNodeStats(filepath.Join(mockedL3_MON, "mon_data", numa))
39+
if err != nil {
40+
t.Fatal(err)
11641
}
117-
42+
stats = append(stats, *other)
11843
}
11944

12045
expectedStats := MBMNumaNodeStats{
12146
MBMTotalBytes: mocksFilesToCreate["mbm_total_bytes"],
12247
MBMLocalBytes: mocksFilesToCreate["mbm_local_bytes"],
12348
}
12449

125-
checkStatCorrection((*stats)[0], expectedStats, t)
126-
checkStatCorrection((*stats)[1], expectedStats, t)
50+
checkMBMStatCorrection(stats[0], expectedStats, t)
51+
checkMBMStatCorrection(stats[1], expectedStats, t)
12752
})
12853
}
54+
55+
func checkMBMStatCorrection(got MBMNumaNodeStats, expected MBMNumaNodeStats, t *testing.T) {
56+
if got.MBMTotalBytes != expected.MBMTotalBytes {
57+
t.Fatalf("Wrong value of mbm_total_bytes. Expected: %v but got: %v",
58+
expected.MBMTotalBytes,
59+
got.MBMTotalBytes)
60+
}
61+
62+
if got.MBMLocalBytes != expected.MBMLocalBytes {
63+
t.Fatalf("Wrong value of mbm_local_bytes. Expected: %v but got: %v",
64+
expected.MBMLocalBytes,
65+
got.MBMLocalBytes)
66+
}
67+
68+
}

0 commit comments

Comments
 (0)