Skip to content

Commit b431460

Browse files
corherekolyshkin
authored andcommitted
libct/intelrdt: skip reading /proc/cpuinfo
Reading /proc/cpuinfo is a surprisingly expensive operation. Since kernel version 4.12 [1], opening /proc/cpuinfo on an x86 system can block for around 20 milliseconds while the kernel samples the current CPU frequency. There is a very recent patch [2] which gets rid of the delay, but has yet to make it into the mainline kenel. Regardless, kernels for which opening /proc/cpuinfo takes 20ms will continue to be run in production for years to come. libcontainer only opens /proc/cpuinfo to read the processor feature flags so all the delays to get an accurate snapshot of the CPU frequency are just wasted time. If we wanted to, we could interrogate the CPU features directly from userspace using the `CPUID` instruction. However, Intel and AMD CPUs have flags in different positions for their analogous sub-features and there are CPU quirks [3] which would need to be accounted for. Some Haswell server CPUs support RDT/CAT but are missing the `CPUID` flags advertising their support; the kernel checks for support on that processor family by probing the the hardware using privileged RDMSR/WRMSR instructions [4]. This sort of probing could not be implemented in userspace so it would not be possible to check for RDT feature support in userspace without false negatives on some hardware configurations. It looks like libcontainer reads the CPU feature flags as a kind of optimization so that it can skip checking whether the kernel supports an RDT sub-feature if the hardware support is missing. As the kernel only exposes subtrees in the `resctrl` filesystem for RDT sub-features with hardware and kernel support, checking the CPU feature flags is redundant from a correctness point of view. Remove the /proc/cpuinfo check as it is an optimization which actually hurts performance. [1]: https://unix.stackexchange.com/a/526679 [2]: https://lore.kernel.org/all/[email protected]/ [3]: https://github.com/torvalds/linux/blob/7cf6a8a17f5b134b7e783c2d45c53298faef82a7/arch/x86/kernel/cpu/resctrl/core.c#L834-L851 [4]: https://github.com/torvalds/linux/blob/a6b450573b912316ad36262bfc70e7c3870c56d1/arch/x86/kernel/cpu/resctrl/core.c#L111-L153 Signed-off-by: Cory Snider <[email protected]> (cherry picked from commit 9f10748) Signed-off-by: Kir Kolyshkin <[email protected]>
1 parent edf67e0 commit b431460

File tree

1 file changed

+18
-83
lines changed

1 file changed

+18
-83
lines changed

libcontainer/intelrdt/intelrdt.go

Lines changed: 18 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package intelrdt
22

33
import (
4-
"bufio"
54
"bytes"
65
"errors"
76
"fmt"
@@ -199,40 +198,28 @@ func featuresInit() {
199198
return
200199
}
201200

202-
// 2. Check if hardware and kernel support Intel RDT sub-features.
203-
flagsSet, err := parseCpuInfoFile("/proc/cpuinfo")
204-
if err != nil {
205-
return
206-
}
207-
208-
// 3. Double check if Intel RDT sub-features are available in
209-
// "resource control" filesystem. Intel RDT sub-features can be
201+
// 2. Check if Intel RDT sub-features are available in "resource
202+
// control" filesystem. Intel RDT sub-features can be
210203
// selectively disabled or enabled by kernel command line
211204
// (e.g., rdt=!l3cat,mba) in 4.14 and newer kernel
212-
if flagsSet.CAT {
213-
if _, err := os.Stat(filepath.Join(root, "info", "L3")); err == nil {
214-
catEnabled = true
215-
}
205+
if _, err := os.Stat(filepath.Join(root, "info", "L3")); err == nil {
206+
catEnabled = true
216207
}
217-
if flagsSet.MBA {
218-
if _, err := os.Stat(filepath.Join(root, "info", "MB")); err == nil {
219-
mbaEnabled = true
220-
}
208+
if _, err := os.Stat(filepath.Join(root, "info", "MB")); err == nil {
209+
mbaEnabled = true
221210
}
222-
if flagsSet.MBMTotal || flagsSet.MBMLocal || flagsSet.CMT {
223-
if _, err := os.Stat(filepath.Join(root, "info", "L3_MON")); err != nil {
224-
return
225-
}
226-
enabledMonFeatures, err = getMonFeatures(root)
227-
if err != nil {
228-
return
229-
}
230-
if enabledMonFeatures.mbmTotalBytes || enabledMonFeatures.mbmLocalBytes {
231-
mbmEnabled = true
232-
}
233-
if enabledMonFeatures.llcOccupancy {
234-
cmtEnabled = true
235-
}
211+
if _, err := os.Stat(filepath.Join(root, "info", "L3_MON")); err != nil {
212+
return
213+
}
214+
enabledMonFeatures, err = getMonFeatures(root)
215+
if err != nil {
216+
return
217+
}
218+
if enabledMonFeatures.mbmTotalBytes || enabledMonFeatures.mbmLocalBytes {
219+
mbmEnabled = true
220+
}
221+
if enabledMonFeatures.llcOccupancy {
222+
cmtEnabled = true
236223
}
237224
})
238225
}
@@ -286,58 +273,6 @@ func Root() (string, error) {
286273
return intelRdtRoot, intelRdtRootErr
287274
}
288275

289-
type cpuInfoFlags struct {
290-
CAT bool // Cache Allocation Technology
291-
MBA bool // Memory Bandwidth Allocation
292-
293-
// Memory Bandwidth Monitoring related.
294-
MBMTotal bool
295-
MBMLocal bool
296-
297-
CMT bool // Cache Monitoring Technology
298-
}
299-
300-
func parseCpuInfoFile(path string) (cpuInfoFlags, error) {
301-
infoFlags := cpuInfoFlags{}
302-
303-
f, err := os.Open(path)
304-
if err != nil {
305-
return infoFlags, err
306-
}
307-
defer f.Close()
308-
309-
s := bufio.NewScanner(f)
310-
for s.Scan() {
311-
line := s.Text()
312-
313-
// Search "cat_l3" and "mba" flags in first "flags" line
314-
if strings.HasPrefix(line, "flags") {
315-
flags := strings.Split(line, " ")
316-
// "cat_l3" flag for CAT and "mba" flag for MBA
317-
for _, flag := range flags {
318-
switch flag {
319-
case "cat_l3":
320-
infoFlags.CAT = true
321-
case "mba":
322-
infoFlags.MBA = true
323-
case "cqm_mbm_total":
324-
infoFlags.MBMTotal = true
325-
case "cqm_mbm_local":
326-
infoFlags.MBMLocal = true
327-
case "cqm_occup_llc":
328-
infoFlags.CMT = true
329-
}
330-
}
331-
return infoFlags, nil
332-
}
333-
}
334-
if err := s.Err(); err != nil {
335-
return infoFlags, err
336-
}
337-
338-
return infoFlags, nil
339-
}
340-
341276
// Gets a single uint64 value from the specified file.
342277
func getIntelRdtParamUint(path, file string) (uint64, error) {
343278
fileName := filepath.Join(path, file)

0 commit comments

Comments
 (0)