intelrdt.go 20 KB

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