Skip to content

Commit 95af9ef

Browse files
committed
libcontainer: intelrdt: add support for Intel RDT/MBA Software Controller in runc
MBA Software Controller feature is introduced in Linux kernel v4.18. It is a software enhancement to mitigate some limitations in MBA which describes in kernel documentation. It also makes the interface more user friendly - we could specify memory bandwidth in "MBps" (Mega Bytes per second) as well as in "percentages". The kernel underneath would use a software feedback mechanism or a "Software Controller" which reads the actual bandwidth using MBM counters and adjust the memory bandwidth percentages to ensure: "actual memory bandwidth < user specified memory bandwidth". We could enable this feature through mount option "-o mba_MBps": mount -t resctrl resctrl -o mba_MBps /sys/fs/resctrl In runc, we handle both memory bandwidth schemata in unified format: "MB:<cache_id0>=bandwidth0;<cache_id1>=bandwidth1;..." The unit of memory bandwidth is specified in "percentages" by default, and in "MBps" if MBA Software Controller is enabled. For more information about Intel RDT and MBA Software Controller: https://www.kernel.org/doc/Documentation/x86/intel_rdt_ui.txt Signed-off-by: Xiaochen Shen <[email protected]>
1 parent bb522d6 commit 95af9ef

File tree

4 files changed

+103
-7
lines changed

4 files changed

+103
-7
lines changed

libcontainer/SPEC.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,8 @@ service (CLOS) and each CLOS has a capacity bitmask (CBM).
167167

168168
Memory Bandwidth Allocation (MBA) provides indirect and approximate throttle
169169
over memory bandwidth for the software. A user controls the resource by
170-
indicating the percentage of maximum memory bandwidth.
170+
indicating the percentage of maximum memory bandwidth or memory bandwidth limit
171+
in MBps unit if MBA Software Controller is enabled.
171172

172173
It can be used to handle L3 cache and memory bandwidth resources allocation
173174
for containers if hardware and kernel support Intel RDT CAT and MBA features.
@@ -236,7 +237,7 @@ set in a group: 0xf, 0xf0, 0x3ff, 0x1f00 and etc.
236237

237238
Memory bandwidth schema:
238239
It has allocation values for memory bandwidth on each socket, which contains
239-
L3 cache id and memory bandwidth percentage.
240+
L3 cache id and memory bandwidth.
240241
```
241242
Format: "MB:<cache_id0>=bandwidth0;<cache_id1>=bandwidth1;..."
242243
```
@@ -249,6 +250,18 @@ that is allocated is also dependent on the CPU model and can be looked up at
249250
min_bw + N * bw_gran. Intermediate values are rounded to the next control
250251
step available on the hardware.
251252

253+
If MBA Software Controller is enabled through mount option "-o mba_MBps"
254+
mount -t resctrl resctrl -o mba_MBps /sys/fs/resctrl
255+
We could specify memory bandwidth in "MBps" (Mega Bytes per second) unit
256+
instead of "percentages". The kernel underneath would use a software feedback
257+
mechanism or a "Software Controller" which reads the actual bandwidth using
258+
MBM counters and adjust the memory bandwidth percentages to ensure:
259+
"actual memory bandwidth < user specified memory bandwidth".
260+
261+
For example, on a two-socket machine, the schema line could be
262+
"MB:0=5000;1=7000" which means 5000 MBps memory bandwidth limit on socket 0
263+
and 7000 MBps memory bandwidth limit on socket 1.
264+
252265
For more information about Intel RDT kernel interface:
253266
https://www.kernel.org/doc/Documentation/x86/intel_rdt_ui.txt
254267

libcontainer/configs/intelrdt.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ type IntelRdt struct {
55
// Format: "L3:<cache_id0>=<cbm0>;<cache_id1>=<cbm1>;..."
66
L3CacheSchema string `json:"l3_cache_schema,omitempty"`
77

8-
// The schema of memory bandwidth percentage per L3 cache id
8+
// The schema of memory bandwidth per L3 cache id
99
// Format: "MB:<cache_id0>=bandwidth0;<cache_id1>=bandwidth1;..."
10+
// The unit of memory bandwidth is specified in "percentages" by
11+
// default, and in "MBps" if MBA Software Controller is enabled.
1012
MemBwSchema string `json:"memBwSchema,omitempty"`
1113
}

libcontainer/intelrdt/intelrdt.go

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ import (
2828
*
2929
* Memory Bandwidth Allocation (MBA) provides indirect and approximate throttle
3030
* over memory bandwidth for the software. A user controls the resource by
31-
* indicating the percentage of maximum memory bandwidth.
31+
* indicating the percentage of maximum memory bandwidth or memory bandwidth
32+
* limit in MBps unit if MBA Software Controller is enabled.
3233
*
3334
* More details about Intel RDT CAT and MBA can be found in the section 17.18
3435
* of Intel Software Developer Manual:
@@ -95,7 +96,7 @@ import (
9596
*
9697
* Memory bandwidth schema:
9798
* It has allocation values for memory bandwidth on each socket, which contains
98-
* L3 cache id and memory bandwidth percentage.
99+
* L3 cache id and memory bandwidth.
99100
* Format: "MB:<cache_id0>=bandwidth0;<cache_id1>=bandwidth1;..."
100101
* For example, on a two-socket machine, the schema line could be "MB:0=20;1=70"
101102
*
@@ -106,6 +107,18 @@ import (
106107
* min_bw + N * bw_gran. Intermediate values are rounded to the next control
107108
* step available on the hardware.
108109
*
110+
* If MBA Software Controller is enabled through mount option "-o mba_MBps":
111+
* mount -t resctrl resctrl -o mba_MBps /sys/fs/resctrl
112+
* We could specify memory bandwidth in "MBps" (Mega Bytes per second) unit
113+
* instead of "percentages". The kernel underneath would use a software feedback
114+
* mechanism or a "Software Controller" which reads the actual bandwidth using
115+
* MBM counters and adjust the memory bandwidth percentages to ensure:
116+
* "actual memory bandwidth < user specified memory bandwidth".
117+
*
118+
* For example, on a two-socket machine, the schema line could be
119+
* "MB:0=5000;1=7000" which means 5000 MBps memory bandwidth limit on socket 0
120+
* and 7000 MBps memory bandwidth limit on socket 1.
121+
*
109122
* For more information about Intel RDT kernel interface:
110123
* https://www.kernel.org/doc/Documentation/x86/intel_rdt_ui.txt
111124
*
@@ -165,6 +178,8 @@ var (
165178
isCatEnabled bool
166179
// The flag to indicate if Intel RDT/MBA is enabled
167180
isMbaEnabled bool
181+
// The flag to indicate if Intel RDT/MBA Software Controller is enabled
182+
isMbaScEnabled bool
168183
)
169184

170185
type intelRdtData struct {
@@ -197,7 +212,12 @@ func init() {
197212
isCatEnabled = true
198213
}
199214
}
200-
if isMbaFlagSet {
215+
if isMbaScEnabled {
216+
// We confirm MBA Software Controller is enabled in step 2,
217+
// MBA should be enabled because MBA Software Controller
218+
// depends on MBA
219+
isMbaEnabled = true
220+
} else if isMbaFlagSet {
201221
if _, err := os.Stat(filepath.Join(intelRdtRoot, "info", "MB")); err == nil {
202222
isMbaEnabled = true
203223
}
@@ -232,6 +252,11 @@ func findIntelRdtMountpointDir() (string, error) {
232252
return "", fmt.Errorf("Error found less than 3 fields post '-' in %q", text)
233253
}
234254

255+
// Check if MBA Software Controller is enabled through mount option "-o mba_MBps"
256+
if strings.Contains(postSeparatorFields[2], "mba_MBps") {
257+
isMbaScEnabled = true
258+
}
259+
235260
return fields[4], nil
236261
}
237262
}
@@ -480,6 +505,11 @@ func IsMbaEnabled() bool {
480505
return isMbaEnabled
481506
}
482507

508+
// Check if Intel RDT/MBA Software Controller is enabled
509+
func IsMbaScEnabled() bool {
510+
return isMbaScEnabled
511+
}
512+
483513
// Get the 'container_id' path in Intel RDT "resource control" filesystem
484514
func GetIntelRdtPath(id string) (string, error) {
485515
rootPath, err := getIntelRdtRoot()
@@ -633,7 +663,7 @@ func (m *IntelRdtManager) Set(container *configs.Config) error {
633663
//
634664
// About memory bandwidth schema:
635665
// It has allocation values for memory bandwidth on each socket, which
636-
// contains L3 cache id and memory bandwidth percentage.
666+
// contains L3 cache id and memory bandwidth.
637667
// Format: "MB:<cache_id0>=bandwidth0;<cache_id1>=bandwidth1;..."
638668
// For example, on a two-socket machine, the schema line could be:
639669
// "MB:0=20;1=70"
@@ -645,6 +675,19 @@ func (m *IntelRdtManager) Set(container *configs.Config) error {
645675
// The available bandwidth control steps are: min_bw + N * bw_gran.
646676
// Intermediate values are rounded to the next control step available
647677
// on the hardware.
678+
//
679+
// If MBA Software Controller is enabled through mount option
680+
// "-o mba_MBps": mount -t resctrl resctrl -o mba_MBps /sys/fs/resctrl
681+
// We could specify memory bandwidth in "MBps" (Mega Bytes per second)
682+
// unit instead of "percentages". The kernel underneath would use a
683+
// software feedback mechanism or a "Software Controller" which reads
684+
// the actual bandwidth using MBM counters and adjust the memory
685+
// bandwidth percentages to ensure:
686+
// "actual memory bandwidth < user specified memory bandwidth".
687+
//
688+
// For example, on a two-socket machine, the schema line could be
689+
// "MB:0=5000;1=7000" which means 5000 MBps memory bandwidth limit on
690+
// socket 0 and 7000 MBps memory bandwidth limit on socket 1.
648691
if container.IntelRdt != nil {
649692
path := m.GetPath()
650693
l3CacheSchema := container.IntelRdt.L3CacheSchema

libcontainer/intelrdt/intelrdt_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,41 @@ func TestIntelRdtSetMemBwSchema(t *testing.T) {
8282
t.Fatal("Got the wrong value, set 'schemata' failed.")
8383
}
8484
}
85+
86+
func TestIntelRdtSetMemBwScSchema(t *testing.T) {
87+
if !IsMbaScEnabled() {
88+
return
89+
}
90+
91+
helper := NewIntelRdtTestUtil(t)
92+
defer helper.cleanup()
93+
94+
const (
95+
memBwScSchemaBefore = "MB:0=5000;1=7000"
96+
memBwScSchemeAfter = "MB:0=9000;1=4000"
97+
)
98+
99+
helper.writeFileContents(map[string]string{
100+
"schemata": memBwScSchemaBefore + "\n",
101+
})
102+
103+
helper.IntelRdtData.config.IntelRdt.MemBwSchema = memBwScSchemeAfter
104+
intelrdt := &IntelRdtManager{
105+
Config: helper.IntelRdtData.config,
106+
Path: helper.IntelRdtPath,
107+
}
108+
if err := intelrdt.Set(helper.IntelRdtData.config); err != nil {
109+
t.Fatal(err)
110+
}
111+
112+
tmpStrings, err := getIntelRdtParamString(helper.IntelRdtPath, "schemata")
113+
if err != nil {
114+
t.Fatalf("Failed to parse file 'schemata' - %s", err)
115+
}
116+
values := strings.Split(tmpStrings, "\n")
117+
value := values[0]
118+
119+
if value != memBwScSchemeAfter {
120+
t.Fatal("Got the wrong value, set 'schemata' failed.")
121+
}
122+
}

0 commit comments

Comments
 (0)