Skip to content

Commit 27560ac

Browse files
committed
libcontainer: intelrdt: add support for Intel RDT/MBA in runc
Memory Bandwidth Allocation (MBA) is a resource allocation sub-feature of Intel Resource Director Technology (RDT) which is supported on some Intel Xeon platforms. Intel RDT/MBA provides indirect and approximate throttle over memory bandwidth for the software. A user controls the resource by indicating the percentage of maximum memory bandwidth. Hardware details of Intel RDT/MBA can be found in section 17.18 of Intel Software Developer Manual: https://software.intel.com/en-us/articles/intel-sdm In Linux 4.12 kernel and newer, Intel RDT/MBA is enabled by kernel config CONFIG_INTEL_RDT. If hardware support, CPU flags `rdt_a` and `mba` will be set in /proc/cpuinfo. Intel RDT "resource control" filesystem hierarchy: mount -t resctrl resctrl /sys/fs/resctrl tree /sys/fs/resctrl /sys/fs/resctrl/ |-- info | |-- L3 | | |-- cbm_mask | | |-- min_cbm_bits | | |-- num_closids | |-- MB | |-- bandwidth_gran | |-- delay_linear | |-- min_bandwidth | |-- num_closids |-- ... |-- schemata |-- tasks |-- <container_id> |-- ... |-- schemata |-- tasks For MBA support for `runc`, we will reuse the infrastructure and code base of Intel RDT/CAT which implemented in opencontainers#1279. We could also make use of `tasks` and `schemata` configuration for memory bandwidth resource constraints. The file `tasks` has a list of tasks that belongs to this group (e.g., <container_id>" group). Tasks can be added to a group by writing the task ID to the "tasks" file (which will automatically remove them from the previous group to which they belonged). New tasks created by fork(2) and clone(2) are added to the same group as their parent. The file `schemata` has a list of all the resources available to this group. Each resource (L3 cache, memory bandwidth) has its own line and format. Memory bandwidth schema: It has allocation values for memory bandwidth on each socket, which contains L3 cache id and memory bandwidth percentage. Format: "MB:<cache_id0>=bandwidth0;<cache_id1>=bandwidth1;..." The minimum bandwidth percentage value for each CPU model is predefined and can be looked up through "info/MB/min_bandwidth". The bandwidth granularity that is allocated is also dependent on the CPU model and can be looked up at "info/MB/bandwidth_gran". The available bandwidth control steps are: min_bw + N * bw_gran. Intermediate values are rounded to the next control step available on the hardware. For more information about Intel RDT kernel interface: https://www.kernel.org/doc/Documentation/x86/intel_rdt_ui.txt An example for runc: Consider a two-socket machine with two L3 caches where the minimum memory bandwidth of 10% with a memory bandwidth granularity of 10%. Tasks inside the container may use a maximum memory bandwidth of 20% on socket 0 and 70% on socket 1. "linux": { "intelRdt": { "memBwSchema": "MB:0=20;1=70" } } Signed-off-by: Xiaochen Shen <[email protected]>
1 parent c1cece7 commit 27560ac

File tree

10 files changed

+319
-125
lines changed

10 files changed

+319
-125
lines changed

events.go

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,13 @@ type l3CacheInfo struct {
104104
NumClosids uint64 `json:"num_closids,omitempty"`
105105
}
106106

107+
type memBwInfo struct {
108+
BandwidthGran uint64 `json:"bandwidth_gran,omitempty"`
109+
DelayLinear uint64 `json:"delay_linear,omitempty"`
110+
MinBandwidth uint64 `json:"min_bandwidth,omitempty"`
111+
NumClosids uint64 `json:"num_closids,omitempty"`
112+
}
113+
107114
type intelRdt struct {
108115
// The read-only L3 cache information
109116
L3CacheInfo *l3CacheInfo `json:"l3_cache_info,omitempty"`
@@ -113,6 +120,15 @@ type intelRdt struct {
113120

114121
// The L3 cache schema in 'container_id' group
115122
L3CacheSchema string `json:"l3_cache_schema,omitempty"`
123+
124+
// The read-only memory bandwidth information
125+
MemBwInfo *memBwInfo `json:"mem_bw_info,omitempty"`
126+
127+
// The read-only memory bandwidth schema in root
128+
MemBwSchemaRoot string `json:"mem_bw_schema_root,omitempty"`
129+
130+
// The memory bandwidth schema in 'container_id' group
131+
MemBwSchema string `json:"mem_bw_schema,omitempty"`
116132
}
117133

118134
var eventsCommand = cli.Command{
@@ -248,9 +264,16 @@ func convertLibcontainerStats(ls *libcontainer.Stats) *stats {
248264
}
249265

250266
if is := ls.IntelRdtStats; is != nil {
251-
s.IntelRdt.L3CacheInfo = convertL3CacheInfo(is.L3CacheInfo)
252-
s.IntelRdt.L3CacheSchemaRoot = is.L3CacheSchemaRoot
253-
s.IntelRdt.L3CacheSchema = is.L3CacheSchema
267+
if intelrdt.IsCatEnabled() {
268+
s.IntelRdt.L3CacheInfo = convertL3CacheInfo(is.L3CacheInfo)
269+
s.IntelRdt.L3CacheSchemaRoot = is.L3CacheSchemaRoot
270+
s.IntelRdt.L3CacheSchema = is.L3CacheSchema
271+
}
272+
if intelrdt.IsMbaEnabled() {
273+
s.IntelRdt.MemBwInfo = convertMemBwInfo(is.MemBwInfo)
274+
s.IntelRdt.MemBwSchemaRoot = is.MemBwSchemaRoot
275+
s.IntelRdt.MemBwSchema = is.MemBwSchema
276+
}
254277
}
255278

256279
return &s
@@ -293,3 +316,12 @@ func convertL3CacheInfo(i *intelrdt.L3CacheInfo) *l3CacheInfo {
293316
NumClosids: i.NumClosids,
294317
}
295318
}
319+
320+
func convertMemBwInfo(i *intelrdt.MemBwInfo) *memBwInfo {
321+
return &memBwInfo{
322+
BandwidthGran: i.BandwidthGran,
323+
DelayLinear: i.DelayLinear,
324+
MinBandwidth: i.MinBandwidth,
325+
NumClosids: i.NumClosids,
326+
}
327+
}

libcontainer/configs/config.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,8 @@ type Config struct {
186186
// callers keyring in this case.
187187
NoNewKeyring bool `json:"no_new_keyring"`
188188

189-
// IntelRdt specifies settings for Intel RDT/CAT group that the container is placed into
190-
// to limit the resources (e.g., L3 cache) the container has available
189+
// IntelRdt specifies settings for Intel RDT group that the container is placed into
190+
// to limit the resources (e.g., L3 cache, memory bandwidth) the container has available
191191
IntelRdt *IntelRdt `json:"intel_rdt,omitempty"`
192192

193193
// RootlessEUID is set when the runc was launched with non-zero EUID.

libcontainer/configs/intelrdt.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,8 @@ type IntelRdt struct {
44
// The schema for L3 cache id and capacity bitmask (CBM)
55
// Format: "L3:<cache_id0>=<cbm0>;<cache_id1>=<cbm1>;..."
66
L3CacheSchema string `json:"l3_cache_schema,omitempty"`
7+
8+
// The schema of memory bandwidth percentage per L3 cache id
9+
// Format: "MB:<cache_id0>=bandwidth0;<cache_id1>=bandwidth1;..."
10+
MemBwSchema string `json:"memBwSchema,omitempty"`
711
}

libcontainer/configs/validate/validator.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -169,11 +169,22 @@ func (v *ConfigValidator) sysctl(config *configs.Config) error {
169169

170170
func (v *ConfigValidator) intelrdt(config *configs.Config) error {
171171
if config.IntelRdt != nil {
172-
if !intelrdt.IsEnabled() {
173-
return fmt.Errorf("intelRdt is specified in config, but Intel RDT feature is not supported or enabled")
172+
if !intelrdt.IsCatEnabled() && !intelrdt.IsMbaEnabled() {
173+
return fmt.Errorf("intelRdt is specified in config, but Intel RDT is not supported or enabled")
174174
}
175-
if config.IntelRdt.L3CacheSchema == "" {
176-
return fmt.Errorf("intelRdt is specified in config, but intelRdt.l3CacheSchema is empty")
175+
176+
if !intelrdt.IsCatEnabled() && config.IntelRdt.L3CacheSchema != "" {
177+
return fmt.Errorf("intelRdt.l3CacheSchema is specified in config, but Intel RDT/CAT is not enabled")
178+
}
179+
if !intelrdt.IsMbaEnabled() && config.IntelRdt.MemBwSchema != "" {
180+
return fmt.Errorf("intelRdt.memBwSchema is specified in config, but Intel RDT/MBA is not enabled")
181+
}
182+
183+
if intelrdt.IsCatEnabled() && config.IntelRdt.L3CacheSchema == "" {
184+
return fmt.Errorf("Intel RDT/CAT is enabled and intelRdt is specified in config, but intelRdt.l3CacheSchema is empty")
185+
}
186+
if intelrdt.IsMbaEnabled() && config.IntelRdt.MemBwSchema == "" {
187+
return fmt.Errorf("Intel RDT/MBA is enabled and intelRdt is specified in config, but intelRdt.memBwSchema is empty")
177188
}
178189
}
179190

libcontainer/factory_linux.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ func RootlessCgroupfs(l *LinuxFactory) error {
9292

9393
// IntelRdtfs is an options func to configure a LinuxFactory to return
9494
// containers that use the Intel RDT "resource control" filesystem to
95-
// create and manage Intel Xeon platform shared resources (e.g., L3 cache).
95+
// create and manage Intel RDT resources (e.g., L3 cache, memory bandwidth).
9696
func IntelRdtFs(l *LinuxFactory) error {
9797
l.NewIntelRdtManager = func(config *configs.Config, id string, path string) intelrdt.Manager {
9898
return &intelrdt.IntelRdtManager{
@@ -222,7 +222,7 @@ func (l *LinuxFactory) Create(id string, config *configs.Config) (Container, err
222222
newgidmapPath: l.NewgidmapPath,
223223
cgroupManager: l.NewCgroupsManager(config.Cgroups, nil),
224224
}
225-
if intelrdt.IsEnabled() {
225+
if intelrdt.IsCatEnabled() || intelrdt.IsMbaEnabled() {
226226
c.intelRdtManager = l.NewIntelRdtManager(config, id, "")
227227
}
228228
c.state = &stoppedState{c: c}
@@ -268,7 +268,7 @@ func (l *LinuxFactory) Load(id string) (Container, error) {
268268
if err := c.refreshState(); err != nil {
269269
return nil, err
270270
}
271-
if intelrdt.IsEnabled() {
271+
if intelrdt.IsCatEnabled() || intelrdt.IsMbaEnabled() {
272272
c.intelRdtManager = l.NewIntelRdtManager(&state.Config, id, state.IntelRdtPath)
273273
}
274274
return c, nil

0 commit comments

Comments
 (0)