Skip to content

Commit 47fa744

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 #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 3782d11 commit 47fa744

File tree

10 files changed

+314
-124
lines changed

10 files changed

+314
-124
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
@@ -188,8 +188,8 @@ type Config struct {
188188
// Rootless specifies whether the container is a rootless container.
189189
Rootless bool `json:"rootless"`
190190

191-
// IntelRdt specifies settings for Intel RDT/CAT group that the container is placed into
192-
// to limit the resources (e.g., L3 cache) the container has available
191+
// IntelRdt specifies settings for Intel RDT group that the container is placed into
192+
// to limit the resources (e.g., L3 cache, memory bandwidth) the container has available
193193
IntelRdt *IntelRdt `json:"intel_rdt,omitempty"`
194194
}
195195

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: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,11 +159,18 @@ func (v *ConfigValidator) sysctl(config *configs.Config) error {
159159

160160
func (v *ConfigValidator) intelrdt(config *configs.Config) error {
161161
if config.IntelRdt != nil {
162-
if !intelrdt.IsEnabled() {
162+
if !intelrdt.IsCatEnabled() && !intelrdt.IsMbaEnabled() {
163163
return fmt.Errorf("intelRdt is specified in config, but Intel RDT feature is not supported or enabled")
164164
}
165-
if config.IntelRdt.L3CacheSchema == "" {
166-
return fmt.Errorf("intelRdt is specified in config, but intelRdt.l3CacheSchema is empty")
165+
if intelrdt.IsCatEnabled() && !intelrdt.IsMbaEnabled() {
166+
if config.IntelRdt.L3CacheSchema == "" {
167+
return fmt.Errorf("Intel RDT/CAT is enabled and intelRdt is specified in config, but l3CacheSchema is empty")
168+
}
169+
}
170+
if !intelrdt.IsCatEnabled() && intelrdt.IsMbaEnabled() {
171+
if config.IntelRdt.MemBwSchema == "" {
172+
return fmt.Errorf("Intel RDT/MBA is enabled and intelRdt is specified in config, but memBwSchema is empty")
173+
}
167174
}
168175
}
169176

libcontainer/factory_linux.go

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

7575
// IntelRdtfs is an options func to configure a LinuxFactory to return
7676
// containers that use the Intel RDT "resource control" filesystem to
77-
// create and manage Intel Xeon platform shared resources (e.g., L3 cache).
77+
// create and manage Intel RDT resources (e.g., L3 cache, memory bandwidth).
7878
func IntelRdtFs(l *LinuxFactory) error {
7979
l.NewIntelRdtManager = func(config *configs.Config, id string, path string) intelrdt.Manager {
8080
return &intelrdt.IntelRdtManager{
@@ -201,7 +201,7 @@ func (l *LinuxFactory) Create(id string, config *configs.Config) (Container, err
201201
newgidmapPath: l.NewgidmapPath,
202202
cgroupManager: l.NewCgroupsManager(config.Cgroups, nil),
203203
}
204-
if intelrdt.IsEnabled() {
204+
if intelrdt.IsCatEnabled() || intelrdt.IsMbaEnabled() {
205205
c.intelRdtManager = l.NewIntelRdtManager(config, id, "")
206206
}
207207
c.state = &stoppedState{c: c}
@@ -240,7 +240,7 @@ func (l *LinuxFactory) Load(id string) (Container, error) {
240240
if err := c.refreshState(); err != nil {
241241
return nil, err
242242
}
243-
if intelrdt.IsEnabled() {
243+
if intelrdt.IsCatEnabled() || intelrdt.IsMbaEnabled() {
244244
c.intelRdtManager = l.NewIntelRdtManager(&state.Config, id, state.IntelRdtPath)
245245
}
246246
return c, nil

0 commit comments

Comments
 (0)