resctrlfs.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Basic resctrl file system operations
  4. *
  5. * Copyright (C) 2018 Intel Corporation
  6. *
  7. * Authors:
  8. * Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
  9. * Fenghua Yu <fenghua.yu@intel.com>
  10. */
  11. #include <fcntl.h>
  12. #include <limits.h>
  13. #include "resctrl.h"
  14. static int find_resctrl_mount(char *buffer)
  15. {
  16. FILE *mounts;
  17. char line[256], *fs, *mntpoint;
  18. mounts = fopen("/proc/mounts", "r");
  19. if (!mounts) {
  20. ksft_perror("/proc/mounts");
  21. return -ENXIO;
  22. }
  23. while (!feof(mounts)) {
  24. if (!fgets(line, 256, mounts))
  25. break;
  26. fs = strtok(line, " \t");
  27. if (!fs)
  28. continue;
  29. mntpoint = strtok(NULL, " \t");
  30. if (!mntpoint)
  31. continue;
  32. fs = strtok(NULL, " \t");
  33. if (!fs)
  34. continue;
  35. if (strcmp(fs, "resctrl"))
  36. continue;
  37. fclose(mounts);
  38. if (buffer)
  39. strncpy(buffer, mntpoint, 256);
  40. return 0;
  41. }
  42. fclose(mounts);
  43. return -ENOENT;
  44. }
  45. /*
  46. * mount_resctrlfs - Mount resctrl FS at /sys/fs/resctrl
  47. *
  48. * Mounts resctrl FS. Fails if resctrl FS is already mounted to avoid
  49. * pre-existing settings interfering with the test results.
  50. *
  51. * Return: 0 on success, < 0 on error.
  52. */
  53. int mount_resctrlfs(void)
  54. {
  55. int ret;
  56. ret = find_resctrl_mount(NULL);
  57. if (ret != -ENOENT)
  58. return -1;
  59. ksft_print_msg("Mounting resctrl to \"%s\"\n", RESCTRL_PATH);
  60. ret = mount("resctrl", RESCTRL_PATH, "resctrl", 0, NULL);
  61. if (ret)
  62. ksft_perror("mount");
  63. return ret;
  64. }
  65. int umount_resctrlfs(void)
  66. {
  67. char mountpoint[256];
  68. int ret;
  69. ret = find_resctrl_mount(mountpoint);
  70. if (ret == -ENOENT)
  71. return 0;
  72. if (ret)
  73. return ret;
  74. if (umount(mountpoint)) {
  75. ksft_perror("Unable to umount resctrl");
  76. return -1;
  77. }
  78. return 0;
  79. }
  80. /*
  81. * get_cache_level - Convert cache level from string to integer
  82. * @cache_type: Cache level as string
  83. *
  84. * Return: cache level as integer or -1 if @cache_type is invalid.
  85. */
  86. static int get_cache_level(const char *cache_type)
  87. {
  88. if (!strcmp(cache_type, "L3"))
  89. return 3;
  90. if (!strcmp(cache_type, "L2"))
  91. return 2;
  92. ksft_print_msg("Invalid cache level\n");
  93. return -1;
  94. }
  95. static int get_resource_cache_level(const char *resource)
  96. {
  97. /* "MB" use L3 (LLC) as resource */
  98. if (!strcmp(resource, "MB"))
  99. return 3;
  100. return get_cache_level(resource);
  101. }
  102. /*
  103. * get_domain_id - Get resctrl domain ID for a specified CPU
  104. * @resource: resource name
  105. * @cpu_no: CPU number
  106. * @domain_id: domain ID (cache ID; for MB, L3 cache ID)
  107. *
  108. * Return: >= 0 on success, < 0 on failure.
  109. */
  110. int get_domain_id(const char *resource, int cpu_no, int *domain_id)
  111. {
  112. char phys_pkg_path[1024];
  113. int cache_num;
  114. FILE *fp;
  115. cache_num = get_resource_cache_level(resource);
  116. if (cache_num < 0)
  117. return cache_num;
  118. sprintf(phys_pkg_path, "%s%d/cache/index%d/id", PHYS_ID_PATH, cpu_no, cache_num);
  119. fp = fopen(phys_pkg_path, "r");
  120. if (!fp) {
  121. ksft_perror("Failed to open cache id file");
  122. return -1;
  123. }
  124. if (fscanf(fp, "%d", domain_id) <= 0) {
  125. ksft_perror("Could not get domain ID");
  126. fclose(fp);
  127. return -1;
  128. }
  129. fclose(fp);
  130. return 0;
  131. }
  132. /*
  133. * get_cache_size - Get cache size for a specified CPU
  134. * @cpu_no: CPU number
  135. * @cache_type: Cache level L2/L3
  136. * @cache_size: pointer to cache_size
  137. *
  138. * Return: = 0 on success, < 0 on failure.
  139. */
  140. int get_cache_size(int cpu_no, const char *cache_type, unsigned long *cache_size)
  141. {
  142. char cache_path[1024], cache_str[64];
  143. int length, i, cache_num;
  144. FILE *fp;
  145. cache_num = get_cache_level(cache_type);
  146. if (cache_num < 0)
  147. return cache_num;
  148. sprintf(cache_path, "/sys/bus/cpu/devices/cpu%d/cache/index%d/size",
  149. cpu_no, cache_num);
  150. fp = fopen(cache_path, "r");
  151. if (!fp) {
  152. ksft_perror("Failed to open cache size");
  153. return -1;
  154. }
  155. if (fscanf(fp, "%63s", cache_str) <= 0) {
  156. ksft_perror("Could not get cache_size");
  157. fclose(fp);
  158. return -1;
  159. }
  160. fclose(fp);
  161. length = (int)strlen(cache_str);
  162. *cache_size = 0;
  163. for (i = 0; i < length; i++) {
  164. if ((cache_str[i] >= '0') && (cache_str[i] <= '9'))
  165. *cache_size = *cache_size * 10 + (cache_str[i] - '0');
  166. else if (cache_str[i] == 'K')
  167. *cache_size = *cache_size * 1024;
  168. else if (cache_str[i] == 'M')
  169. *cache_size = *cache_size * 1024 * 1024;
  170. else
  171. break;
  172. }
  173. return 0;
  174. }
  175. #define CORE_SIBLINGS_PATH "/sys/bus/cpu/devices/cpu"
  176. /*
  177. * get_bit_mask - Get bit mask from given file
  178. * @filename: File containing the mask
  179. * @mask: The bit mask returned as unsigned long
  180. *
  181. * Return: = 0 on success, < 0 on failure.
  182. */
  183. static int get_bit_mask(const char *filename, unsigned long *mask)
  184. {
  185. FILE *fp;
  186. if (!filename || !mask)
  187. return -1;
  188. fp = fopen(filename, "r");
  189. if (!fp) {
  190. ksft_print_msg("Failed to open bit mask file '%s': %s\n",
  191. filename, strerror(errno));
  192. return -1;
  193. }
  194. if (fscanf(fp, "%lx", mask) <= 0) {
  195. ksft_print_msg("Could not read bit mask file '%s': %s\n",
  196. filename, strerror(errno));
  197. fclose(fp);
  198. return -1;
  199. }
  200. fclose(fp);
  201. return 0;
  202. }
  203. /*
  204. * resource_info_unsigned_get - Read an unsigned value from
  205. * /sys/fs/resctrl/info/@resource/@filename
  206. * @resource: Resource name that matches directory name in
  207. * /sys/fs/resctrl/info
  208. * @filename: File in /sys/fs/resctrl/info/@resource
  209. * @val: Contains read value on success.
  210. *
  211. * Return: = 0 on success, < 0 on failure. On success the read
  212. * value is saved into @val.
  213. */
  214. int resource_info_unsigned_get(const char *resource, const char *filename,
  215. unsigned int *val)
  216. {
  217. char file_path[PATH_MAX];
  218. FILE *fp;
  219. snprintf(file_path, sizeof(file_path), "%s/%s/%s", INFO_PATH, resource,
  220. filename);
  221. fp = fopen(file_path, "r");
  222. if (!fp) {
  223. ksft_print_msg("Error opening %s: %m\n", file_path);
  224. return -1;
  225. }
  226. if (fscanf(fp, "%u", val) <= 0) {
  227. ksft_print_msg("Could not get contents of %s: %m\n", file_path);
  228. fclose(fp);
  229. return -1;
  230. }
  231. fclose(fp);
  232. return 0;
  233. }
  234. /*
  235. * create_bit_mask- Create bit mask from start, len pair
  236. * @start: LSB of the mask
  237. * @len Number of bits in the mask
  238. */
  239. unsigned long create_bit_mask(unsigned int start, unsigned int len)
  240. {
  241. return ((1UL << len) - 1UL) << start;
  242. }
  243. /*
  244. * count_contiguous_bits - Returns the longest train of bits in a bit mask
  245. * @val A bit mask
  246. * @start The location of the least-significant bit of the longest train
  247. *
  248. * Return: The length of the contiguous bits in the longest train of bits
  249. */
  250. unsigned int count_contiguous_bits(unsigned long val, unsigned int *start)
  251. {
  252. unsigned long last_val;
  253. unsigned int count = 0;
  254. while (val) {
  255. last_val = val;
  256. val &= (val >> 1);
  257. count++;
  258. }
  259. if (start) {
  260. if (count)
  261. *start = ffsl(last_val) - 1;
  262. else
  263. *start = 0;
  264. }
  265. return count;
  266. }
  267. /*
  268. * get_full_cbm - Get full Cache Bit Mask (CBM)
  269. * @cache_type: Cache type as "L2" or "L3"
  270. * @mask: Full cache bit mask representing the maximal portion of cache
  271. * available for allocation, returned as unsigned long.
  272. *
  273. * Return: = 0 on success, < 0 on failure.
  274. */
  275. int get_full_cbm(const char *cache_type, unsigned long *mask)
  276. {
  277. char cbm_path[PATH_MAX];
  278. int ret;
  279. if (!cache_type)
  280. return -1;
  281. snprintf(cbm_path, sizeof(cbm_path), "%s/%s/cbm_mask",
  282. INFO_PATH, cache_type);
  283. ret = get_bit_mask(cbm_path, mask);
  284. if (ret || !*mask)
  285. return -1;
  286. return 0;
  287. }
  288. /*
  289. * get_shareable_mask - Get shareable mask from shareable_bits
  290. * @cache_type: Cache type as "L2" or "L3"
  291. * @shareable_mask: Shareable mask returned as unsigned long
  292. *
  293. * Return: = 0 on success, < 0 on failure.
  294. */
  295. static int get_shareable_mask(const char *cache_type, unsigned long *shareable_mask)
  296. {
  297. char mask_path[PATH_MAX];
  298. if (!cache_type)
  299. return -1;
  300. snprintf(mask_path, sizeof(mask_path), "%s/%s/shareable_bits",
  301. INFO_PATH, cache_type);
  302. return get_bit_mask(mask_path, shareable_mask);
  303. }
  304. /*
  305. * get_mask_no_shareable - Get Cache Bit Mask (CBM) without shareable bits
  306. * @cache_type: Cache type as "L2" or "L3"
  307. * @mask: The largest exclusive portion of the cache out of the
  308. * full CBM, returned as unsigned long
  309. *
  310. * Parts of a cache may be shared with other devices such as GPU. This function
  311. * calculates the largest exclusive portion of the cache where no other devices
  312. * besides CPU have access to the cache portion.
  313. *
  314. * Return: = 0 on success, < 0 on failure.
  315. */
  316. int get_mask_no_shareable(const char *cache_type, unsigned long *mask)
  317. {
  318. unsigned long full_mask, shareable_mask;
  319. unsigned int start, len;
  320. if (get_full_cbm(cache_type, &full_mask) < 0)
  321. return -1;
  322. if (get_shareable_mask(cache_type, &shareable_mask) < 0)
  323. return -1;
  324. len = count_contiguous_bits(full_mask & ~shareable_mask, &start);
  325. if (!len)
  326. return -1;
  327. *mask = create_bit_mask(start, len);
  328. return 0;
  329. }
  330. /*
  331. * taskset_benchmark - Taskset PID (i.e. benchmark) to a specified cpu
  332. * @bm_pid: PID that should be binded
  333. * @cpu_no: CPU number at which the PID would be binded
  334. * @old_affinity: When not NULL, set to old CPU affinity
  335. *
  336. * Return: 0 on success, < 0 on error.
  337. */
  338. int taskset_benchmark(pid_t bm_pid, int cpu_no, cpu_set_t *old_affinity)
  339. {
  340. cpu_set_t my_set;
  341. if (old_affinity) {
  342. CPU_ZERO(old_affinity);
  343. if (sched_getaffinity(bm_pid, sizeof(*old_affinity),
  344. old_affinity)) {
  345. ksft_perror("Unable to read CPU affinity");
  346. return -1;
  347. }
  348. }
  349. CPU_ZERO(&my_set);
  350. CPU_SET(cpu_no, &my_set);
  351. if (sched_setaffinity(bm_pid, sizeof(cpu_set_t), &my_set)) {
  352. ksft_perror("Unable to taskset benchmark");
  353. return -1;
  354. }
  355. return 0;
  356. }
  357. /*
  358. * taskset_restore - Taskset PID to the earlier CPU affinity
  359. * @bm_pid: PID that should be reset
  360. * @old_affinity: The old CPU affinity to restore
  361. *
  362. * Return: 0 on success, < 0 on error.
  363. */
  364. int taskset_restore(pid_t bm_pid, cpu_set_t *old_affinity)
  365. {
  366. if (sched_setaffinity(bm_pid, sizeof(*old_affinity), old_affinity)) {
  367. ksft_perror("Unable to restore CPU affinity");
  368. return -1;
  369. }
  370. return 0;
  371. }
  372. /*
  373. * create_grp - Create a group only if one doesn't exist
  374. * @grp_name: Name of the group
  375. * @grp: Full path and name of the group
  376. * @parent_grp: Full path and name of the parent group
  377. *
  378. * Creates a group @grp_name if it does not exist yet. If @grp_name is NULL,
  379. * it is interpreted as the root group which always results in success.
  380. *
  381. * Return: 0 on success, < 0 on error.
  382. */
  383. static int create_grp(const char *grp_name, char *grp, const char *parent_grp)
  384. {
  385. int found_grp = 0;
  386. struct dirent *ep;
  387. DIR *dp;
  388. if (!grp_name)
  389. return 0;
  390. /* Check if requested grp exists or not */
  391. dp = opendir(parent_grp);
  392. if (dp) {
  393. while ((ep = readdir(dp)) != NULL) {
  394. if (strcmp(ep->d_name, grp_name) == 0)
  395. found_grp = 1;
  396. }
  397. closedir(dp);
  398. } else {
  399. ksft_perror("Unable to open resctrl for group");
  400. return -1;
  401. }
  402. /* Requested grp doesn't exist, hence create it */
  403. if (found_grp == 0) {
  404. if (mkdir(grp, 0) == -1) {
  405. ksft_perror("Unable to create group");
  406. return -1;
  407. }
  408. }
  409. return 0;
  410. }
  411. static int write_pid_to_tasks(char *tasks, pid_t pid)
  412. {
  413. FILE *fp;
  414. fp = fopen(tasks, "w");
  415. if (!fp) {
  416. ksft_perror("Failed to open tasks file");
  417. return -1;
  418. }
  419. if (fprintf(fp, "%d\n", (int)pid) < 0) {
  420. ksft_print_msg("Failed to write pid to tasks file\n");
  421. fclose(fp);
  422. return -1;
  423. }
  424. fclose(fp);
  425. return 0;
  426. }
  427. /*
  428. * write_bm_pid_to_resctrl - Write a PID (i.e. benchmark) to resctrl FS
  429. * @bm_pid: PID that should be written
  430. * @ctrlgrp: Name of the control monitor group (con_mon grp)
  431. * @mongrp: Name of the monitor group (mon grp)
  432. *
  433. * If a con_mon grp is requested, create it and write pid to it, otherwise
  434. * write pid to root con_mon grp.
  435. * If a mon grp is requested, create it and write pid to it, otherwise
  436. * pid is not written, this means that pid is in con_mon grp and hence
  437. * should consult con_mon grp's mon_data directory for results.
  438. *
  439. * Return: 0 on success, < 0 on error.
  440. */
  441. int write_bm_pid_to_resctrl(pid_t bm_pid, const char *ctrlgrp, const char *mongrp)
  442. {
  443. char controlgroup[128], monitorgroup[512], monitorgroup_p[256];
  444. char tasks[1024];
  445. int ret = 0;
  446. if (ctrlgrp)
  447. sprintf(controlgroup, "%s/%s", RESCTRL_PATH, ctrlgrp);
  448. else
  449. sprintf(controlgroup, "%s", RESCTRL_PATH);
  450. /* Create control and monitoring group and write pid into it */
  451. ret = create_grp(ctrlgrp, controlgroup, RESCTRL_PATH);
  452. if (ret)
  453. goto out;
  454. sprintf(tasks, "%s/tasks", controlgroup);
  455. ret = write_pid_to_tasks(tasks, bm_pid);
  456. if (ret)
  457. goto out;
  458. /* Create monitor group and write pid into if it is used */
  459. if (mongrp) {
  460. sprintf(monitorgroup_p, "%s/mon_groups", controlgroup);
  461. sprintf(monitorgroup, "%s/%s", monitorgroup_p, mongrp);
  462. ret = create_grp(mongrp, monitorgroup, monitorgroup_p);
  463. if (ret)
  464. goto out;
  465. sprintf(tasks, "%s/mon_groups/%s/tasks",
  466. controlgroup, mongrp);
  467. ret = write_pid_to_tasks(tasks, bm_pid);
  468. if (ret)
  469. goto out;
  470. }
  471. out:
  472. ksft_print_msg("Writing benchmark parameters to resctrl FS\n");
  473. if (ret)
  474. ksft_print_msg("Failed writing to resctrlfs\n");
  475. return ret;
  476. }
  477. /*
  478. * write_schemata - Update schemata of a con_mon grp
  479. * @ctrlgrp: Name of the con_mon grp
  480. * @schemata: Schemata that should be updated to
  481. * @cpu_no: CPU number that the benchmark PID is binded to
  482. * @resource: Resctrl resource (Eg: MB, L3, L2, etc.)
  483. *
  484. * Update schemata of a con_mon grp *only* if requested resctrl resource is
  485. * allocation type
  486. *
  487. * Return: 0 on success, < 0 on error.
  488. */
  489. int write_schemata(const char *ctrlgrp, char *schemata, int cpu_no,
  490. const char *resource)
  491. {
  492. char controlgroup[1024], reason[128], schema[1024] = {};
  493. int domain_id, fd, schema_len, ret = 0;
  494. if (!schemata) {
  495. ksft_print_msg("Skipping empty schemata update\n");
  496. return -1;
  497. }
  498. if (get_domain_id(resource, cpu_no, &domain_id) < 0) {
  499. sprintf(reason, "Failed to get domain ID");
  500. ret = -1;
  501. goto out;
  502. }
  503. if (ctrlgrp)
  504. sprintf(controlgroup, "%s/%s/schemata", RESCTRL_PATH, ctrlgrp);
  505. else
  506. sprintf(controlgroup, "%s/schemata", RESCTRL_PATH);
  507. schema_len = snprintf(schema, sizeof(schema), "%s:%d=%s\n",
  508. resource, domain_id, schemata);
  509. if (schema_len < 0 || schema_len >= sizeof(schema)) {
  510. snprintf(reason, sizeof(reason),
  511. "snprintf() failed with return value : %d", schema_len);
  512. ret = -1;
  513. goto out;
  514. }
  515. fd = open(controlgroup, O_WRONLY);
  516. if (fd < 0) {
  517. snprintf(reason, sizeof(reason),
  518. "open() failed : %s", strerror(errno));
  519. ret = -1;
  520. goto err_schema_not_empty;
  521. }
  522. if (write(fd, schema, schema_len) < 0) {
  523. snprintf(reason, sizeof(reason),
  524. "write() failed : %s", strerror(errno));
  525. close(fd);
  526. ret = -1;
  527. goto err_schema_not_empty;
  528. }
  529. close(fd);
  530. err_schema_not_empty:
  531. schema[schema_len - 1] = 0;
  532. out:
  533. ksft_print_msg("Write schema \"%s\" to resctrl FS%s%s\n",
  534. schema, ret ? " # " : "",
  535. ret ? reason : "");
  536. return ret;
  537. }
  538. bool check_resctrlfs_support(void)
  539. {
  540. FILE *inf = fopen("/proc/filesystems", "r");
  541. DIR *dp;
  542. char *res;
  543. bool ret = false;
  544. if (!inf)
  545. return false;
  546. res = fgrep(inf, "nodev\tresctrl\n");
  547. if (res) {
  548. ret = true;
  549. free(res);
  550. }
  551. fclose(inf);
  552. ksft_print_msg("%s Check kernel supports resctrl filesystem\n",
  553. ret ? "Pass:" : "Fail:");
  554. if (!ret)
  555. return ret;
  556. dp = opendir(RESCTRL_PATH);
  557. ksft_print_msg("%s Check resctrl mountpoint \"%s\" exists\n",
  558. dp ? "Pass:" : "Fail:", RESCTRL_PATH);
  559. if (dp)
  560. closedir(dp);
  561. ksft_print_msg("resctrl filesystem %s mounted\n",
  562. find_resctrl_mount(NULL) ? "not" : "is");
  563. return ret;
  564. }
  565. char *fgrep(FILE *inf, const char *str)
  566. {
  567. char line[256];
  568. int slen = strlen(str);
  569. while (!feof(inf)) {
  570. if (!fgets(line, 256, inf))
  571. break;
  572. if (strncmp(line, str, slen))
  573. continue;
  574. return strdup(line);
  575. }
  576. return NULL;
  577. }
  578. /*
  579. * resctrl_resource_exists - Check if a resource is supported.
  580. * @resource: Resctrl resource (e.g., MB, L3, L2, L3_MON, etc.)
  581. *
  582. * Return: True if the resource is supported, else false. False is
  583. * also returned if resctrl FS is not mounted.
  584. */
  585. bool resctrl_resource_exists(const char *resource)
  586. {
  587. char res_path[PATH_MAX];
  588. struct stat statbuf;
  589. int ret;
  590. if (!resource)
  591. return false;
  592. ret = find_resctrl_mount(NULL);
  593. if (ret)
  594. return false;
  595. snprintf(res_path, sizeof(res_path), "%s/%s", INFO_PATH, resource);
  596. if (stat(res_path, &statbuf))
  597. return false;
  598. return true;
  599. }
  600. /*
  601. * resctrl_mon_feature_exists - Check if requested monitoring feature is valid.
  602. * @resource: Resource that uses the mon_features file. Currently only L3_MON
  603. * is valid.
  604. * @feature: Required monitor feature (in mon_features file).
  605. *
  606. * Return: True if the feature is supported, else false.
  607. */
  608. bool resctrl_mon_feature_exists(const char *resource, const char *feature)
  609. {
  610. char res_path[PATH_MAX];
  611. char *res;
  612. FILE *inf;
  613. if (!feature || !resource)
  614. return false;
  615. snprintf(res_path, sizeof(res_path), "%s/%s/mon_features", INFO_PATH, resource);
  616. inf = fopen(res_path, "r");
  617. if (!inf)
  618. return false;
  619. res = fgrep(inf, feature);
  620. free(res);
  621. fclose(inf);
  622. return !!res;
  623. }
  624. /*
  625. * resource_info_file_exists - Check if a file is present inside
  626. * /sys/fs/resctrl/info/@resource.
  627. * @resource: Required resource (Eg: MB, L3, L2, etc.)
  628. * @file: Required file.
  629. *
  630. * Return: True if the /sys/fs/resctrl/info/@resource/@file exists, else false.
  631. */
  632. bool resource_info_file_exists(const char *resource, const char *file)
  633. {
  634. char res_path[PATH_MAX];
  635. struct stat statbuf;
  636. if (!file || !resource)
  637. return false;
  638. snprintf(res_path, sizeof(res_path), "%s/%s/%s", INFO_PATH, resource,
  639. file);
  640. if (stat(res_path, &statbuf))
  641. return false;
  642. return true;
  643. }
  644. bool test_resource_feature_check(const struct resctrl_test *test)
  645. {
  646. return resctrl_resource_exists(test->resource);
  647. }
  648. int filter_dmesg(void)
  649. {
  650. char line[1024];
  651. FILE *fp;
  652. int pipefds[2];
  653. pid_t pid;
  654. int ret;
  655. ret = pipe(pipefds);
  656. if (ret) {
  657. ksft_perror("pipe");
  658. return ret;
  659. }
  660. fflush(stdout);
  661. pid = fork();
  662. if (pid == 0) {
  663. close(pipefds[0]);
  664. dup2(pipefds[1], STDOUT_FILENO);
  665. execlp("dmesg", "dmesg", NULL);
  666. ksft_perror("Executing dmesg");
  667. exit(1);
  668. }
  669. close(pipefds[1]);
  670. fp = fdopen(pipefds[0], "r");
  671. if (!fp) {
  672. ksft_perror("fdopen(pipe)");
  673. kill(pid, SIGTERM);
  674. return -1;
  675. }
  676. while (fgets(line, 1024, fp)) {
  677. if (strstr(line, "intel_rdt:"))
  678. ksft_print_msg("dmesg: %s", line);
  679. if (strstr(line, "resctrl:"))
  680. ksft_print_msg("dmesg: %s", line);
  681. }
  682. fclose(fp);
  683. waitpid(pid, NULL, 0);
  684. return 0;
  685. }
  686. const char *get_bw_report_type(const char *bw_report)
  687. {
  688. if (strcmp(bw_report, "reads") == 0)
  689. return bw_report;
  690. if (strcmp(bw_report, "writes") == 0)
  691. return bw_report;
  692. if (strcmp(bw_report, "nt-writes") == 0) {
  693. return "writes";
  694. }
  695. if (strcmp(bw_report, "total") == 0)
  696. return bw_report;
  697. fprintf(stderr, "Requested iMC bandwidth report type unavailable\n");
  698. return NULL;
  699. }
  700. int perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu,
  701. int group_fd, unsigned long flags)
  702. {
  703. int ret;
  704. ret = syscall(__NR_perf_event_open, hw_event, pid, cpu,
  705. group_fd, flags);
  706. return ret;
  707. }
  708. unsigned int count_bits(unsigned long n)
  709. {
  710. unsigned int count = 0;
  711. while (n) {
  712. count += n & 1;
  713. n >>= 1;
  714. }
  715. return count;
  716. }