intelrdt.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774
  1. // +build linux
  2. package intelrdt
  3. import (
  4. "bufio"
  5. "fmt"
  6. "io/ioutil"
  7. "os"
  8. "path/filepath"
  9. "strconv"
  10. "strings"
  11. "sync"
  12. "github.com/opencontainers/runc/libcontainer/configs"
  13. )
  14. /*
  15. * About Intel RDT features:
  16. * Intel platforms with new Xeon CPU support Resource Director Technology (RDT).
  17. * Cache Allocation Technology (CAT) and Memory Bandwidth Allocation (MBA) are
  18. * two sub-features of RDT.
  19. *
  20. * Cache Allocation Technology (CAT) provides a way for the software to restrict
  21. * cache allocation to a defined 'subset' of L3 cache which may be overlapping
  22. * with other 'subsets'. The different subsets are identified by class of
  23. * service (CLOS) and each CLOS has a capacity bitmask (CBM).
  24. *
  25. * Memory Bandwidth Allocation (MBA) provides indirect and approximate throttle
  26. * over memory bandwidth for the software. A user controls the resource by
  27. * indicating the percentage of maximum memory bandwidth or memory bandwidth
  28. * limit in MBps unit if MBA Software Controller is enabled.
  29. *
  30. * More details about Intel RDT CAT and MBA can be found in the section 17.18
  31. * of Intel Software Developer Manual:
  32. * https://software.intel.com/en-us/articles/intel-sdm
  33. *
  34. * About Intel RDT kernel interface:
  35. * In Linux 4.10 kernel or newer, the interface is defined and exposed via
  36. * "resource control" filesystem, which is a "cgroup-like" interface.
  37. *
  38. * Comparing with cgroups, it has similar process management lifecycle and
  39. * interfaces in a container. But unlike cgroups' hierarchy, it has single level
  40. * filesystem layout.
  41. *
  42. * CAT and MBA features are introduced in Linux 4.10 and 4.12 kernel via
  43. * "resource control" filesystem.
  44. *
  45. * Intel RDT "resource control" filesystem hierarchy:
  46. * mount -t resctrl resctrl /sys/fs/resctrl
  47. * tree /sys/fs/resctrl
  48. * /sys/fs/resctrl/
  49. * |-- info
  50. * | |-- L3
  51. * | | |-- cbm_mask
  52. * | | |-- min_cbm_bits
  53. * | | |-- num_closids
  54. * | |-- MB
  55. * | |-- bandwidth_gran
  56. * | |-- delay_linear
  57. * | |-- min_bandwidth
  58. * | |-- num_closids
  59. * |-- ...
  60. * |-- schemata
  61. * |-- tasks
  62. * |-- <container_id>
  63. * |-- ...
  64. * |-- schemata
  65. * |-- tasks
  66. *
  67. * For runc, we can make use of `tasks` and `schemata` configuration for L3
  68. * cache and memory bandwidth resources constraints.
  69. *
  70. * The file `tasks` has a list of tasks that belongs to this group (e.g.,
  71. * <container_id>" group). Tasks can be added to a group by writing the task ID
  72. * to the "tasks" file (which will automatically remove them from the previous
  73. * group to which they belonged). New tasks created by fork(2) and clone(2) are
  74. * added to the same group as their parent.
  75. *
  76. * The file `schemata` has a list of all the resources available to this group.
  77. * Each resource (L3 cache, memory bandwidth) has its own line and format.
  78. *
  79. * L3 cache schema:
  80. * It has allocation bitmasks/values for L3 cache on each socket, which
  81. * contains L3 cache id and capacity bitmask (CBM).
  82. * Format: "L3:<cache_id0>=<cbm0>;<cache_id1>=<cbm1>;..."
  83. * For example, on a two-socket machine, the schema line could be "L3:0=ff;1=c0"
  84. * which means L3 cache id 0's CBM is 0xff, and L3 cache id 1's CBM is 0xc0.
  85. *
  86. * The valid L3 cache CBM is a *contiguous bits set* and number of bits that can
  87. * be set is less than the max bit. The max bits in the CBM is varied among
  88. * supported Intel CPU models. Kernel will check if it is valid when writing.
  89. * e.g., default value 0xfffff in root indicates the max bits of CBM is 20
  90. * bits, which mapping to entire L3 cache capacity. Some valid CBM values to
  91. * set in a group: 0xf, 0xf0, 0x3ff, 0x1f00 and etc.
  92. *
  93. * Memory bandwidth schema:
  94. * It has allocation values for memory bandwidth on each socket, which contains
  95. * L3 cache id and memory bandwidth.
  96. * Format: "MB:<cache_id0>=bandwidth0;<cache_id1>=bandwidth1;..."
  97. * For example, on a two-socket machine, the schema line could be "MB:0=20;1=70"
  98. *
  99. * The minimum bandwidth percentage value for each CPU model is predefined and
  100. * can be looked up through "info/MB/min_bandwidth". The bandwidth granularity
  101. * that is allocated is also dependent on the CPU model and can be looked up at
  102. * "info/MB/bandwidth_gran". The available bandwidth control steps are:
  103. * min_bw + N * bw_gran. Intermediate values are rounded to the next control
  104. * step available on the hardware.
  105. *
  106. * If MBA Software Controller is enabled through mount option "-o mba_MBps":
  107. * mount -t resctrl resctrl -o mba_MBps /sys/fs/resctrl
  108. * We could specify memory bandwidth in "MBps" (Mega Bytes per second) unit
  109. * instead of "percentages". The kernel underneath would use a software feedback
  110. * mechanism or a "Software Controller" which reads the actual bandwidth using
  111. * MBM counters and adjust the memory bandwidth percentages to ensure:
  112. * "actual memory bandwidth < user specified memory bandwidth".
  113. *
  114. * For example, on a two-socket machine, the schema line could be
  115. * "MB:0=5000;1=7000" which means 5000 MBps memory bandwidth limit on socket 0
  116. * and 7000 MBps memory bandwidth limit on socket 1.
  117. *
  118. * For more information about Intel RDT kernel interface:
  119. * https://www.kernel.org/doc/Documentation/x86/intel_rdt_ui.txt
  120. *
  121. * An example for runc:
  122. * Consider a two-socket machine with two L3 caches where the default CBM is
  123. * 0x7ff and the max CBM length is 11 bits, and minimum memory bandwidth of 10%
  124. * with a memory bandwidth granularity of 10%.
  125. *
  126. * Tasks inside the container only have access to the "upper" 7/11 of L3 cache
  127. * on socket 0 and the "lower" 5/11 L3 cache on socket 1, and may use a
  128. * maximum memory bandwidth of 20% on socket 0 and 70% on socket 1.
  129. *
  130. * "linux": {
  131. * "intelRdt": {
  132. * "l3CacheSchema": "L3:0=7f0;1=1f",
  133. * "memBwSchema": "MB:0=20;1=70"
  134. * }
  135. * }
  136. */
  137. type Manager interface {
  138. // Applies Intel RDT configuration to the process with the specified pid
  139. Apply(pid int) error
  140. // Returns statistics for Intel RDT
  141. GetStats() (*Stats, error)
  142. // Destroys the Intel RDT 'container_id' group
  143. Destroy() error
  144. // Returns Intel RDT path to save in a state file and to be able to
  145. // restore the object later
  146. GetPath() string
  147. // Set Intel RDT "resource control" filesystem as configured.
  148. Set(container *configs.Config) error
  149. }
  150. // This implements interface Manager
  151. type IntelRdtManager struct {
  152. mu sync.Mutex
  153. Config *configs.Config
  154. Id string
  155. Path string
  156. }
  157. const (
  158. IntelRdtTasks = "tasks"
  159. )
  160. var (
  161. // The absolute root path of the Intel RDT "resource control" filesystem
  162. intelRdtRoot string
  163. intelRdtRootLock sync.Mutex
  164. // The flag to indicate if Intel RDT/CAT is enabled
  165. isCatEnabled bool
  166. // The flag to indicate if Intel RDT/MBA is enabled
  167. isMbaEnabled bool
  168. // The flag to indicate if Intel RDT/MBA Software Controller is enabled
  169. isMbaScEnabled bool
  170. )
  171. type intelRdtData struct {
  172. root string
  173. config *configs.Config
  174. pid int
  175. }
  176. // Check if Intel RDT sub-features are enabled in init()
  177. func init() {
  178. // 1. Check if hardware and kernel support Intel RDT sub-features
  179. // "cat_l3" flag for CAT and "mba" flag for MBA
  180. isCatFlagSet, isMbaFlagSet, err := parseCpuInfoFile("/proc/cpuinfo")
  181. if err != nil {
  182. return
  183. }
  184. // 2. Check if Intel RDT "resource control" filesystem is mounted
  185. // The user guarantees to mount the filesystem
  186. if !isIntelRdtMounted() {
  187. return
  188. }
  189. // 3. Double check if Intel RDT sub-features are available in
  190. // "resource control" filesystem. Intel RDT sub-features can be
  191. // selectively disabled or enabled by kernel command line
  192. // (e.g., rdt=!l3cat,mba) in 4.14 and newer kernel
  193. if isCatFlagSet {
  194. if _, err := os.Stat(filepath.Join(intelRdtRoot, "info", "L3")); err == nil {
  195. isCatEnabled = true
  196. }
  197. }
  198. if isMbaScEnabled {
  199. // We confirm MBA Software Controller is enabled in step 2,
  200. // MBA should be enabled because MBA Software Controller
  201. // depends on MBA
  202. isMbaEnabled = true
  203. } else if isMbaFlagSet {
  204. if _, err := os.Stat(filepath.Join(intelRdtRoot, "info", "MB")); err == nil {
  205. isMbaEnabled = true
  206. }
  207. }
  208. }
  209. // Return the mount point path of Intel RDT "resource control" filesysem
  210. func findIntelRdtMountpointDir() (string, error) {
  211. f, err := os.Open("/proc/self/mountinfo")
  212. if err != nil {
  213. return "", err
  214. }
  215. defer f.Close()
  216. s := bufio.NewScanner(f)
  217. for s.Scan() {
  218. text := s.Text()
  219. fields := strings.Split(text, " ")
  220. // Safe as mountinfo encodes mountpoints with spaces as \040.
  221. index := strings.Index(text, " - ")
  222. postSeparatorFields := strings.Fields(text[index+3:])
  223. numPostFields := len(postSeparatorFields)
  224. // This is an error as we can't detect if the mount is for "Intel RDT"
  225. if numPostFields == 0 {
  226. return "", fmt.Errorf("Found no fields post '-' in %q", text)
  227. }
  228. if postSeparatorFields[0] == "resctrl" {
  229. // Check that the mount is properly formatted.
  230. if numPostFields < 3 {
  231. return "", fmt.Errorf("Error found less than 3 fields post '-' in %q", text)
  232. }
  233. // Check if MBA Software Controller is enabled through mount option "-o mba_MBps"
  234. if strings.Contains(postSeparatorFields[2], "mba_MBps") {
  235. isMbaScEnabled = true
  236. }
  237. return fields[4], nil
  238. }
  239. }
  240. if err := s.Err(); err != nil {
  241. return "", err
  242. }
  243. return "", NewNotFoundError("Intel RDT")
  244. }
  245. // Gets the root path of Intel RDT "resource control" filesystem
  246. func getIntelRdtRoot() (string, error) {
  247. intelRdtRootLock.Lock()
  248. defer intelRdtRootLock.Unlock()
  249. if intelRdtRoot != "" {
  250. return intelRdtRoot, nil
  251. }
  252. root, err := findIntelRdtMountpointDir()
  253. if err != nil {
  254. return "", err
  255. }
  256. if _, err := os.Stat(root); err != nil {
  257. return "", err
  258. }
  259. intelRdtRoot = root
  260. return intelRdtRoot, nil
  261. }
  262. func isIntelRdtMounted() bool {
  263. _, err := getIntelRdtRoot()
  264. if err != nil {
  265. return false
  266. }
  267. return true
  268. }
  269. func parseCpuInfoFile(path string) (bool, bool, error) {
  270. isCatFlagSet := false
  271. isMbaFlagSet := false
  272. f, err := os.Open(path)
  273. if err != nil {
  274. return false, false, err
  275. }
  276. defer f.Close()
  277. s := bufio.NewScanner(f)
  278. for s.Scan() {
  279. if err := s.Err(); err != nil {
  280. return false, false, err
  281. }
  282. line := s.Text()
  283. // Search "cat_l3" and "mba" flags in first "flags" line
  284. if strings.Contains(line, "flags") {
  285. flags := strings.Split(line, " ")
  286. // "cat_l3" flag for CAT and "mba" flag for MBA
  287. for _, flag := range flags {
  288. switch flag {
  289. case "cat_l3":
  290. isCatFlagSet = true
  291. case "mba":
  292. isMbaFlagSet = true
  293. }
  294. }
  295. return isCatFlagSet, isMbaFlagSet, nil
  296. }
  297. }
  298. return isCatFlagSet, isMbaFlagSet, nil
  299. }
  300. func parseUint(s string, base, bitSize int) (uint64, error) {
  301. value, err := strconv.ParseUint(s, base, bitSize)
  302. if err != nil {
  303. intValue, intErr := strconv.ParseInt(s, base, bitSize)
  304. // 1. Handle negative values greater than MinInt64 (and)
  305. // 2. Handle negative values lesser than MinInt64
  306. if intErr == nil && intValue < 0 {
  307. return 0, nil
  308. } else if intErr != nil && intErr.(*strconv.NumError).Err == strconv.ErrRange && intValue < 0 {
  309. return 0, nil
  310. }
  311. return value, err
  312. }
  313. return value, nil
  314. }
  315. // Gets a single uint64 value from the specified file.
  316. func getIntelRdtParamUint(path, file string) (uint64, error) {
  317. fileName := filepath.Join(path, file)
  318. contents, err := ioutil.ReadFile(fileName)
  319. if err != nil {
  320. return 0, err
  321. }
  322. res, err := parseUint(strings.TrimSpace(string(contents)), 10, 64)
  323. if err != nil {
  324. return res, fmt.Errorf("unable to parse %q as a uint from file %q", string(contents), fileName)
  325. }
  326. return res, nil
  327. }
  328. // Gets a string value from the specified file
  329. func getIntelRdtParamString(path, file string) (string, error) {
  330. contents, err := ioutil.ReadFile(filepath.Join(path, file))
  331. if err != nil {
  332. return "", err
  333. }
  334. return strings.TrimSpace(string(contents)), nil
  335. }
  336. func writeFile(dir, file, data string) error {
  337. if dir == "" {
  338. return fmt.Errorf("no such directory for %s", file)
  339. }
  340. if err := ioutil.WriteFile(filepath.Join(dir, file), []byte(data+"\n"), 0700); err != nil {
  341. return fmt.Errorf("failed to write %v to %v: %v", data, file, err)
  342. }
  343. return nil
  344. }
  345. func getIntelRdtData(c *configs.Config, pid int) (*intelRdtData, error) {
  346. rootPath, err := getIntelRdtRoot()
  347. if err != nil {
  348. return nil, err
  349. }
  350. return &intelRdtData{
  351. root: rootPath,
  352. config: c,
  353. pid: pid,
  354. }, nil
  355. }
  356. // Get the read-only L3 cache information
  357. func getL3CacheInfo() (*L3CacheInfo, error) {
  358. l3CacheInfo := &L3CacheInfo{}
  359. rootPath, err := getIntelRdtRoot()
  360. if err != nil {
  361. return l3CacheInfo, err
  362. }
  363. path := filepath.Join(rootPath, "info", "L3")
  364. cbmMask, err := getIntelRdtParamString(path, "cbm_mask")
  365. if err != nil {
  366. return l3CacheInfo, err
  367. }
  368. minCbmBits, err := getIntelRdtParamUint(path, "min_cbm_bits")
  369. if err != nil {
  370. return l3CacheInfo, err
  371. }
  372. numClosids, err := getIntelRdtParamUint(path, "num_closids")
  373. if err != nil {
  374. return l3CacheInfo, err
  375. }
  376. l3CacheInfo.CbmMask = cbmMask
  377. l3CacheInfo.MinCbmBits = minCbmBits
  378. l3CacheInfo.NumClosids = numClosids
  379. return l3CacheInfo, nil
  380. }
  381. // Get the read-only memory bandwidth information
  382. func getMemBwInfo() (*MemBwInfo, error) {
  383. memBwInfo := &MemBwInfo{}
  384. rootPath, err := getIntelRdtRoot()
  385. if err != nil {
  386. return memBwInfo, err
  387. }
  388. path := filepath.Join(rootPath, "info", "MB")
  389. bandwidthGran, err := getIntelRdtParamUint(path, "bandwidth_gran")
  390. if err != nil {
  391. return memBwInfo, err
  392. }
  393. delayLinear, err := getIntelRdtParamUint(path, "delay_linear")
  394. if err != nil {
  395. return memBwInfo, err
  396. }
  397. minBandwidth, err := getIntelRdtParamUint(path, "min_bandwidth")
  398. if err != nil {
  399. return memBwInfo, err
  400. }
  401. numClosids, err := getIntelRdtParamUint(path, "num_closids")
  402. if err != nil {
  403. return memBwInfo, err
  404. }
  405. memBwInfo.BandwidthGran = bandwidthGran
  406. memBwInfo.DelayLinear = delayLinear
  407. memBwInfo.MinBandwidth = minBandwidth
  408. memBwInfo.NumClosids = numClosids
  409. return memBwInfo, nil
  410. }
  411. // Get diagnostics for last filesystem operation error from file info/last_cmd_status
  412. func getLastCmdStatus() (string, error) {
  413. rootPath, err := getIntelRdtRoot()
  414. if err != nil {
  415. return "", err
  416. }
  417. path := filepath.Join(rootPath, "info")
  418. lastCmdStatus, err := getIntelRdtParamString(path, "last_cmd_status")
  419. if err != nil {
  420. return "", err
  421. }
  422. return lastCmdStatus, nil
  423. }
  424. // WriteIntelRdtTasks writes the specified pid into the "tasks" file
  425. func WriteIntelRdtTasks(dir string, pid int) error {
  426. if dir == "" {
  427. return fmt.Errorf("no such directory for %s", IntelRdtTasks)
  428. }
  429. // Don't attach any pid if -1 is specified as a pid
  430. if pid != -1 {
  431. if err := ioutil.WriteFile(filepath.Join(dir, IntelRdtTasks), []byte(strconv.Itoa(pid)), 0700); err != nil {
  432. return fmt.Errorf("failed to write %v to %v: %v", pid, IntelRdtTasks, err)
  433. }
  434. }
  435. return nil
  436. }
  437. // Check if Intel RDT/CAT is enabled
  438. func IsCatEnabled() bool {
  439. return isCatEnabled
  440. }
  441. // Check if Intel RDT/MBA is enabled
  442. func IsMbaEnabled() bool {
  443. return isMbaEnabled
  444. }
  445. // Check if Intel RDT/MBA Software Controller is enabled
  446. func IsMbaScEnabled() bool {
  447. return isMbaScEnabled
  448. }
  449. // Get the 'container_id' path in Intel RDT "resource control" filesystem
  450. func GetIntelRdtPath(id string) (string, error) {
  451. rootPath, err := getIntelRdtRoot()
  452. if err != nil {
  453. return "", err
  454. }
  455. path := filepath.Join(rootPath, id)
  456. return path, nil
  457. }
  458. // Applies Intel RDT configuration to the process with the specified pid
  459. func (m *IntelRdtManager) Apply(pid int) (err error) {
  460. // If intelRdt is not specified in config, we do nothing
  461. if m.Config.IntelRdt == nil {
  462. return nil
  463. }
  464. d, err := getIntelRdtData(m.Config, pid)
  465. if err != nil && !IsNotFound(err) {
  466. return err
  467. }
  468. m.mu.Lock()
  469. defer m.mu.Unlock()
  470. path, err := d.join(m.Id)
  471. if err != nil {
  472. return err
  473. }
  474. m.Path = path
  475. return nil
  476. }
  477. // Destroys the Intel RDT 'container_id' group
  478. func (m *IntelRdtManager) Destroy() error {
  479. m.mu.Lock()
  480. defer m.mu.Unlock()
  481. if err := os.RemoveAll(m.GetPath()); err != nil {
  482. return err
  483. }
  484. m.Path = ""
  485. return nil
  486. }
  487. // Returns Intel RDT path to save in a state file and to be able to
  488. // restore the object later
  489. func (m *IntelRdtManager) GetPath() string {
  490. if m.Path == "" {
  491. m.Path, _ = GetIntelRdtPath(m.Id)
  492. }
  493. return m.Path
  494. }
  495. // Returns statistics for Intel RDT
  496. func (m *IntelRdtManager) GetStats() (*Stats, error) {
  497. // If intelRdt is not specified in config
  498. if m.Config.IntelRdt == nil {
  499. return nil, nil
  500. }
  501. m.mu.Lock()
  502. defer m.mu.Unlock()
  503. stats := NewStats()
  504. rootPath, err := getIntelRdtRoot()
  505. if err != nil {
  506. return nil, err
  507. }
  508. // The read-only L3 cache and memory bandwidth schemata in root
  509. tmpRootStrings, err := getIntelRdtParamString(rootPath, "schemata")
  510. if err != nil {
  511. return nil, err
  512. }
  513. schemaRootStrings := strings.Split(tmpRootStrings, "\n")
  514. // The L3 cache and memory bandwidth schemata in 'container_id' group
  515. tmpStrings, err := getIntelRdtParamString(m.GetPath(), "schemata")
  516. if err != nil {
  517. return nil, err
  518. }
  519. schemaStrings := strings.Split(tmpStrings, "\n")
  520. if IsCatEnabled() {
  521. // The read-only L3 cache information
  522. l3CacheInfo, err := getL3CacheInfo()
  523. if err != nil {
  524. return nil, err
  525. }
  526. stats.L3CacheInfo = l3CacheInfo
  527. // The read-only L3 cache schema in root
  528. for _, schemaRoot := range schemaRootStrings {
  529. if strings.Contains(schemaRoot, "L3") {
  530. stats.L3CacheSchemaRoot = strings.TrimSpace(schemaRoot)
  531. }
  532. }
  533. // The L3 cache schema in 'container_id' group
  534. for _, schema := range schemaStrings {
  535. if strings.Contains(schema, "L3") {
  536. stats.L3CacheSchema = strings.TrimSpace(schema)
  537. }
  538. }
  539. }
  540. if IsMbaEnabled() {
  541. // The read-only memory bandwidth information
  542. memBwInfo, err := getMemBwInfo()
  543. if err != nil {
  544. return nil, err
  545. }
  546. stats.MemBwInfo = memBwInfo
  547. // The read-only memory bandwidth information
  548. for _, schemaRoot := range schemaRootStrings {
  549. if strings.Contains(schemaRoot, "MB") {
  550. stats.MemBwSchemaRoot = strings.TrimSpace(schemaRoot)
  551. }
  552. }
  553. // The memory bandwidth schema in 'container_id' group
  554. for _, schema := range schemaStrings {
  555. if strings.Contains(schema, "MB") {
  556. stats.MemBwSchema = strings.TrimSpace(schema)
  557. }
  558. }
  559. }
  560. return stats, nil
  561. }
  562. // Set Intel RDT "resource control" filesystem as configured.
  563. func (m *IntelRdtManager) Set(container *configs.Config) error {
  564. // About L3 cache schema:
  565. // It has allocation bitmasks/values for L3 cache on each socket,
  566. // which contains L3 cache id and capacity bitmask (CBM).
  567. // Format: "L3:<cache_id0>=<cbm0>;<cache_id1>=<cbm1>;..."
  568. // For example, on a two-socket machine, the schema line could be:
  569. // L3:0=ff;1=c0
  570. // which means L3 cache id 0's CBM is 0xff, and L3 cache id 1's CBM
  571. // is 0xc0.
  572. //
  573. // The valid L3 cache CBM is a *contiguous bits set* and number of
  574. // bits that can be set is less than the max bit. The max bits in the
  575. // CBM is varied among supported Intel CPU models. Kernel will check
  576. // if it is valid when writing. e.g., default value 0xfffff in root
  577. // indicates the max bits of CBM is 20 bits, which mapping to entire
  578. // L3 cache capacity. Some valid CBM values to set in a group:
  579. // 0xf, 0xf0, 0x3ff, 0x1f00 and etc.
  580. //
  581. //
  582. // About memory bandwidth schema:
  583. // It has allocation values for memory bandwidth on each socket, which
  584. // contains L3 cache id and memory bandwidth.
  585. // Format: "MB:<cache_id0>=bandwidth0;<cache_id1>=bandwidth1;..."
  586. // For example, on a two-socket machine, the schema line could be:
  587. // "MB:0=20;1=70"
  588. //
  589. // The minimum bandwidth percentage value for each CPU model is
  590. // predefined and can be looked up through "info/MB/min_bandwidth".
  591. // The bandwidth granularity that is allocated is also dependent on
  592. // the CPU model and can be looked up at "info/MB/bandwidth_gran".
  593. // The available bandwidth control steps are: min_bw + N * bw_gran.
  594. // Intermediate values are rounded to the next control step available
  595. // on the hardware.
  596. //
  597. // If MBA Software Controller is enabled through mount option
  598. // "-o mba_MBps": mount -t resctrl resctrl -o mba_MBps /sys/fs/resctrl
  599. // We could specify memory bandwidth in "MBps" (Mega Bytes per second)
  600. // unit instead of "percentages". The kernel underneath would use a
  601. // software feedback mechanism or a "Software Controller" which reads
  602. // the actual bandwidth using MBM counters and adjust the memory
  603. // bandwidth percentages to ensure:
  604. // "actual memory bandwidth < user specified memory bandwidth".
  605. //
  606. // For example, on a two-socket machine, the schema line could be
  607. // "MB:0=5000;1=7000" which means 5000 MBps memory bandwidth limit on
  608. // socket 0 and 7000 MBps memory bandwidth limit on socket 1.
  609. if container.IntelRdt != nil {
  610. path := m.GetPath()
  611. l3CacheSchema := container.IntelRdt.L3CacheSchema
  612. memBwSchema := container.IntelRdt.MemBwSchema
  613. // Write a single joint schema string to schemata file
  614. if l3CacheSchema != "" && memBwSchema != "" {
  615. if err := writeFile(path, "schemata", l3CacheSchema+"\n"+memBwSchema); err != nil {
  616. return NewLastCmdError(err)
  617. }
  618. }
  619. // Write only L3 cache schema string to schemata file
  620. if l3CacheSchema != "" && memBwSchema == "" {
  621. if err := writeFile(path, "schemata", l3CacheSchema); err != nil {
  622. return NewLastCmdError(err)
  623. }
  624. }
  625. // Write only memory bandwidth schema string to schemata file
  626. if l3CacheSchema == "" && memBwSchema != "" {
  627. if err := writeFile(path, "schemata", memBwSchema); err != nil {
  628. return NewLastCmdError(err)
  629. }
  630. }
  631. }
  632. return nil
  633. }
  634. func (raw *intelRdtData) join(id string) (string, error) {
  635. path := filepath.Join(raw.root, id)
  636. if err := os.MkdirAll(path, 0755); err != nil {
  637. return "", NewLastCmdError(err)
  638. }
  639. if err := WriteIntelRdtTasks(path, raw.pid); err != nil {
  640. return "", NewLastCmdError(err)
  641. }
  642. return path, nil
  643. }
  644. type NotFoundError struct {
  645. ResourceControl string
  646. }
  647. func (e *NotFoundError) Error() string {
  648. return fmt.Sprintf("mountpoint for %s not found", e.ResourceControl)
  649. }
  650. func NewNotFoundError(res string) error {
  651. return &NotFoundError{
  652. ResourceControl: res,
  653. }
  654. }
  655. func IsNotFound(err error) bool {
  656. if err == nil {
  657. return false
  658. }
  659. _, ok := err.(*NotFoundError)
  660. return ok
  661. }
  662. type LastCmdError struct {
  663. LastCmdStatus string
  664. Err error
  665. }
  666. func (e *LastCmdError) Error() string {
  667. return fmt.Sprintf(e.Err.Error() + ", last_cmd_status: " + e.LastCmdStatus)
  668. }
  669. func NewLastCmdError(err error) error {
  670. lastCmdStatus, err1 := getLastCmdStatus()
  671. if err1 == nil {
  672. return &LastCmdError{
  673. LastCmdStatus: lastCmdStatus,
  674. Err: err,
  675. }
  676. }
  677. return err
  678. }