pmu.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  1. #include <linux/list.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <unistd.h>
  5. #include <stdio.h>
  6. #include <dirent.h>
  7. #include "sysfs.h"
  8. #include "util.h"
  9. #include "pmu.h"
  10. #include "parse-events.h"
  11. #include "cpumap.h"
  12. #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
  13. int perf_pmu_parse(struct list_head *list, char *name);
  14. extern FILE *perf_pmu_in;
  15. static LIST_HEAD(pmus);
  16. /*
  17. * Parse & process all the sysfs attributes located under
  18. * the directory specified in 'dir' parameter.
  19. */
  20. static int pmu_format_parse(char *dir, struct list_head *head)
  21. {
  22. struct dirent *evt_ent;
  23. DIR *format_dir;
  24. int ret = 0;
  25. format_dir = opendir(dir);
  26. if (!format_dir)
  27. return -EINVAL;
  28. while (!ret && (evt_ent = readdir(format_dir))) {
  29. char path[PATH_MAX];
  30. char *name = evt_ent->d_name;
  31. FILE *file;
  32. if (!strcmp(name, ".") || !strcmp(name, ".."))
  33. continue;
  34. snprintf(path, PATH_MAX, "%s/%s", dir, name);
  35. ret = -EINVAL;
  36. file = fopen(path, "r");
  37. if (!file)
  38. break;
  39. perf_pmu_in = file;
  40. ret = perf_pmu_parse(head, name);
  41. fclose(file);
  42. }
  43. closedir(format_dir);
  44. return ret;
  45. }
  46. /*
  47. * Reading/parsing the default pmu format definition, which should be
  48. * located at:
  49. * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes.
  50. */
  51. static int pmu_format(char *name, struct list_head *format)
  52. {
  53. struct stat st;
  54. char path[PATH_MAX];
  55. const char *sysfs;
  56. sysfs = sysfs_find_mountpoint();
  57. if (!sysfs)
  58. return -1;
  59. snprintf(path, PATH_MAX,
  60. "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name);
  61. if (stat(path, &st) < 0)
  62. return 0; /* no error if format does not exist */
  63. if (pmu_format_parse(path, format))
  64. return -1;
  65. return 0;
  66. }
  67. static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file)
  68. {
  69. struct perf_pmu__alias *alias;
  70. char buf[256];
  71. int ret;
  72. ret = fread(buf, 1, sizeof(buf), file);
  73. if (ret == 0)
  74. return -EINVAL;
  75. buf[ret] = 0;
  76. alias = malloc(sizeof(*alias));
  77. if (!alias)
  78. return -ENOMEM;
  79. INIT_LIST_HEAD(&alias->terms);
  80. ret = parse_events_terms(&alias->terms, buf);
  81. if (ret) {
  82. free(alias);
  83. return ret;
  84. }
  85. alias->name = strdup(name);
  86. list_add_tail(&alias->list, list);
  87. return 0;
  88. }
  89. /*
  90. * Process all the sysfs attributes located under the directory
  91. * specified in 'dir' parameter.
  92. */
  93. static int pmu_aliases_parse(char *dir, struct list_head *head)
  94. {
  95. struct dirent *evt_ent;
  96. DIR *event_dir;
  97. int ret = 0;
  98. event_dir = opendir(dir);
  99. if (!event_dir)
  100. return -EINVAL;
  101. while (!ret && (evt_ent = readdir(event_dir))) {
  102. char path[PATH_MAX];
  103. char *name = evt_ent->d_name;
  104. FILE *file;
  105. if (!strcmp(name, ".") || !strcmp(name, ".."))
  106. continue;
  107. snprintf(path, PATH_MAX, "%s/%s", dir, name);
  108. ret = -EINVAL;
  109. file = fopen(path, "r");
  110. if (!file)
  111. break;
  112. ret = perf_pmu__new_alias(head, name, file);
  113. fclose(file);
  114. }
  115. closedir(event_dir);
  116. return ret;
  117. }
  118. /*
  119. * Reading the pmu event aliases definition, which should be located at:
  120. * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes.
  121. */
  122. static int pmu_aliases(char *name, struct list_head *head)
  123. {
  124. struct stat st;
  125. char path[PATH_MAX];
  126. const char *sysfs;
  127. sysfs = sysfs_find_mountpoint();
  128. if (!sysfs)
  129. return -1;
  130. snprintf(path, PATH_MAX,
  131. "%s/bus/event_source/devices/%s/events", sysfs, name);
  132. if (stat(path, &st) < 0)
  133. return -1;
  134. if (pmu_aliases_parse(path, head))
  135. return -1;
  136. return 0;
  137. }
  138. static int pmu_alias_terms(struct perf_pmu__alias *alias,
  139. struct list_head *terms)
  140. {
  141. struct parse_events__term *term, *clone;
  142. LIST_HEAD(list);
  143. int ret;
  144. list_for_each_entry(term, &alias->terms, list) {
  145. ret = parse_events__term_clone(&clone, term);
  146. if (ret) {
  147. parse_events__free_terms(&list);
  148. return ret;
  149. }
  150. list_add_tail(&clone->list, &list);
  151. }
  152. list_splice(&list, terms);
  153. return 0;
  154. }
  155. /*
  156. * Reading/parsing the default pmu type value, which should be
  157. * located at:
  158. * /sys/bus/event_source/devices/<dev>/type as sysfs attribute.
  159. */
  160. static int pmu_type(char *name, __u32 *type)
  161. {
  162. struct stat st;
  163. char path[PATH_MAX];
  164. const char *sysfs;
  165. FILE *file;
  166. int ret = 0;
  167. sysfs = sysfs_find_mountpoint();
  168. if (!sysfs)
  169. return -1;
  170. snprintf(path, PATH_MAX,
  171. "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name);
  172. if (stat(path, &st) < 0)
  173. return -1;
  174. file = fopen(path, "r");
  175. if (!file)
  176. return -EINVAL;
  177. if (1 != fscanf(file, "%u", type))
  178. ret = -1;
  179. fclose(file);
  180. return ret;
  181. }
  182. /* Add all pmus in sysfs to pmu list: */
  183. static void pmu_read_sysfs(void)
  184. {
  185. char path[PATH_MAX];
  186. const char *sysfs;
  187. DIR *dir;
  188. struct dirent *dent;
  189. sysfs = sysfs_find_mountpoint();
  190. if (!sysfs)
  191. return;
  192. snprintf(path, PATH_MAX,
  193. "%s" EVENT_SOURCE_DEVICE_PATH, sysfs);
  194. dir = opendir(path);
  195. if (!dir)
  196. return;
  197. while ((dent = readdir(dir))) {
  198. if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
  199. continue;
  200. /* add to static LIST_HEAD(pmus): */
  201. perf_pmu__find(dent->d_name);
  202. }
  203. closedir(dir);
  204. }
  205. static struct cpu_map *pmu_cpumask(char *name)
  206. {
  207. struct stat st;
  208. char path[PATH_MAX];
  209. const char *sysfs;
  210. FILE *file;
  211. struct cpu_map *cpus;
  212. sysfs = sysfs_find_mountpoint();
  213. if (!sysfs)
  214. return NULL;
  215. snprintf(path, PATH_MAX,
  216. "%s/bus/event_source/devices/%s/cpumask", sysfs, name);
  217. if (stat(path, &st) < 0)
  218. return NULL;
  219. file = fopen(path, "r");
  220. if (!file)
  221. return NULL;
  222. cpus = cpu_map__read(file);
  223. fclose(file);
  224. return cpus;
  225. }
  226. static struct perf_pmu *pmu_lookup(char *name)
  227. {
  228. struct perf_pmu *pmu;
  229. LIST_HEAD(format);
  230. LIST_HEAD(aliases);
  231. __u32 type;
  232. /*
  233. * The pmu data we store & need consists of the pmu
  234. * type value and format definitions. Load both right
  235. * now.
  236. */
  237. if (pmu_format(name, &format))
  238. return NULL;
  239. if (pmu_type(name, &type))
  240. return NULL;
  241. pmu = zalloc(sizeof(*pmu));
  242. if (!pmu)
  243. return NULL;
  244. pmu->cpus = pmu_cpumask(name);
  245. pmu_aliases(name, &aliases);
  246. INIT_LIST_HEAD(&pmu->format);
  247. INIT_LIST_HEAD(&pmu->aliases);
  248. list_splice(&format, &pmu->format);
  249. list_splice(&aliases, &pmu->aliases);
  250. pmu->name = strdup(name);
  251. pmu->type = type;
  252. list_add_tail(&pmu->list, &pmus);
  253. return pmu;
  254. }
  255. static struct perf_pmu *pmu_find(char *name)
  256. {
  257. struct perf_pmu *pmu;
  258. list_for_each_entry(pmu, &pmus, list)
  259. if (!strcmp(pmu->name, name))
  260. return pmu;
  261. return NULL;
  262. }
  263. struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu)
  264. {
  265. /*
  266. * pmu iterator: If pmu is NULL, we start at the begin,
  267. * otherwise return the next pmu. Returns NULL on end.
  268. */
  269. if (!pmu) {
  270. pmu_read_sysfs();
  271. pmu = list_prepare_entry(pmu, &pmus, list);
  272. }
  273. list_for_each_entry_continue(pmu, &pmus, list)
  274. return pmu;
  275. return NULL;
  276. }
  277. struct perf_pmu *perf_pmu__find(char *name)
  278. {
  279. struct perf_pmu *pmu;
  280. /*
  281. * Once PMU is loaded it stays in the list,
  282. * so we keep us from multiple reading/parsing
  283. * the pmu format definitions.
  284. */
  285. pmu = pmu_find(name);
  286. if (pmu)
  287. return pmu;
  288. return pmu_lookup(name);
  289. }
  290. static struct perf_pmu__format*
  291. pmu_find_format(struct list_head *formats, char *name)
  292. {
  293. struct perf_pmu__format *format;
  294. list_for_each_entry(format, formats, list)
  295. if (!strcmp(format->name, name))
  296. return format;
  297. return NULL;
  298. }
  299. /*
  300. * Returns value based on the format definition (format parameter)
  301. * and unformated value (value parameter).
  302. *
  303. * TODO maybe optimize a little ;)
  304. */
  305. static __u64 pmu_format_value(unsigned long *format, __u64 value)
  306. {
  307. unsigned long fbit, vbit;
  308. __u64 v = 0;
  309. for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
  310. if (!test_bit(fbit, format))
  311. continue;
  312. if (!(value & (1llu << vbit++)))
  313. continue;
  314. v |= (1llu << fbit);
  315. }
  316. return v;
  317. }
  318. /*
  319. * Setup one of config[12] attr members based on the
  320. * user input data - temr parameter.
  321. */
  322. static int pmu_config_term(struct list_head *formats,
  323. struct perf_event_attr *attr,
  324. struct parse_events__term *term)
  325. {
  326. struct perf_pmu__format *format;
  327. __u64 *vp;
  328. /*
  329. * Support only for hardcoded and numnerial terms.
  330. * Hardcoded terms should be already in, so nothing
  331. * to be done for them.
  332. */
  333. if (parse_events__is_hardcoded_term(term))
  334. return 0;
  335. if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM)
  336. return -EINVAL;
  337. format = pmu_find_format(formats, term->config);
  338. if (!format)
  339. return -EINVAL;
  340. switch (format->value) {
  341. case PERF_PMU_FORMAT_VALUE_CONFIG:
  342. vp = &attr->config;
  343. break;
  344. case PERF_PMU_FORMAT_VALUE_CONFIG1:
  345. vp = &attr->config1;
  346. break;
  347. case PERF_PMU_FORMAT_VALUE_CONFIG2:
  348. vp = &attr->config2;
  349. break;
  350. default:
  351. return -EINVAL;
  352. }
  353. /*
  354. * XXX If we ever decide to go with string values for
  355. * non-hardcoded terms, here's the place to translate
  356. * them into value.
  357. */
  358. *vp |= pmu_format_value(format->bits, term->val.num);
  359. return 0;
  360. }
  361. static int pmu_config(struct list_head *formats, struct perf_event_attr *attr,
  362. struct list_head *head_terms)
  363. {
  364. struct parse_events__term *term;
  365. list_for_each_entry(term, head_terms, list)
  366. if (pmu_config_term(formats, attr, term))
  367. return -EINVAL;
  368. return 0;
  369. }
  370. /*
  371. * Configures event's 'attr' parameter based on the:
  372. * 1) users input - specified in terms parameter
  373. * 2) pmu format definitions - specified by pmu parameter
  374. */
  375. int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
  376. struct list_head *head_terms)
  377. {
  378. attr->type = pmu->type;
  379. return pmu_config(&pmu->format, attr, head_terms);
  380. }
  381. static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu,
  382. struct parse_events__term *term)
  383. {
  384. struct perf_pmu__alias *alias;
  385. char *name;
  386. if (parse_events__is_hardcoded_term(term))
  387. return NULL;
  388. if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) {
  389. if (term->val.num != 1)
  390. return NULL;
  391. if (pmu_find_format(&pmu->format, term->config))
  392. return NULL;
  393. name = term->config;
  394. } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) {
  395. if (strcasecmp(term->config, "event"))
  396. return NULL;
  397. name = term->val.str;
  398. } else {
  399. return NULL;
  400. }
  401. list_for_each_entry(alias, &pmu->aliases, list) {
  402. if (!strcasecmp(alias->name, name))
  403. return alias;
  404. }
  405. return NULL;
  406. }
  407. /*
  408. * Find alias in the terms list and replace it with the terms
  409. * defined for the alias
  410. */
  411. int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms)
  412. {
  413. struct parse_events__term *term, *h;
  414. struct perf_pmu__alias *alias;
  415. int ret;
  416. list_for_each_entry_safe(term, h, head_terms, list) {
  417. alias = pmu_find_alias(pmu, term);
  418. if (!alias)
  419. continue;
  420. ret = pmu_alias_terms(alias, &term->list);
  421. if (ret)
  422. return ret;
  423. list_del(&term->list);
  424. free(term);
  425. }
  426. return 0;
  427. }
  428. int perf_pmu__new_format(struct list_head *list, char *name,
  429. int config, unsigned long *bits)
  430. {
  431. struct perf_pmu__format *format;
  432. format = zalloc(sizeof(*format));
  433. if (!format)
  434. return -ENOMEM;
  435. format->name = strdup(name);
  436. format->value = config;
  437. memcpy(format->bits, bits, sizeof(format->bits));
  438. list_add_tail(&format->list, list);
  439. return 0;
  440. }
  441. void perf_pmu__set_format(unsigned long *bits, long from, long to)
  442. {
  443. long b;
  444. if (!to)
  445. to = from;
  446. memset(bits, 0, BITS_TO_LONGS(PERF_PMU_FORMAT_BITS));
  447. for (b = from; b <= to; b++)
  448. set_bit(b, bits);
  449. }
  450. /* Simulated format definitions. */
  451. static struct test_format {
  452. const char *name;
  453. const char *value;
  454. } test_formats[] = {
  455. { "krava01", "config:0-1,62-63\n", },
  456. { "krava02", "config:10-17\n", },
  457. { "krava03", "config:5\n", },
  458. { "krava11", "config1:0,2,4,6,8,20-28\n", },
  459. { "krava12", "config1:63\n", },
  460. { "krava13", "config1:45-47\n", },
  461. { "krava21", "config2:0-3,10-13,20-23,30-33,40-43,50-53,60-63\n", },
  462. { "krava22", "config2:8,18,48,58\n", },
  463. { "krava23", "config2:28-29,38\n", },
  464. };
  465. #define TEST_FORMATS_CNT (sizeof(test_formats) / sizeof(struct test_format))
  466. /* Simulated users input. */
  467. static struct parse_events__term test_terms[] = {
  468. {
  469. .config = (char *) "krava01",
  470. .val.num = 15,
  471. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  472. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  473. },
  474. {
  475. .config = (char *) "krava02",
  476. .val.num = 170,
  477. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  478. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  479. },
  480. {
  481. .config = (char *) "krava03",
  482. .val.num = 1,
  483. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  484. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  485. },
  486. {
  487. .config = (char *) "krava11",
  488. .val.num = 27,
  489. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  490. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  491. },
  492. {
  493. .config = (char *) "krava12",
  494. .val.num = 1,
  495. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  496. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  497. },
  498. {
  499. .config = (char *) "krava13",
  500. .val.num = 2,
  501. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  502. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  503. },
  504. {
  505. .config = (char *) "krava21",
  506. .val.num = 119,
  507. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  508. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  509. },
  510. {
  511. .config = (char *) "krava22",
  512. .val.num = 11,
  513. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  514. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  515. },
  516. {
  517. .config = (char *) "krava23",
  518. .val.num = 2,
  519. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  520. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  521. },
  522. };
  523. #define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
  524. /*
  525. * Prepare format directory data, exported by kernel
  526. * at /sys/bus/event_source/devices/<dev>/format.
  527. */
  528. static char *test_format_dir_get(void)
  529. {
  530. static char dir[PATH_MAX];
  531. unsigned int i;
  532. snprintf(dir, PATH_MAX, "/tmp/perf-pmu-test-format-XXXXXX");
  533. if (!mkdtemp(dir))
  534. return NULL;
  535. for (i = 0; i < TEST_FORMATS_CNT; i++) {
  536. static char name[PATH_MAX];
  537. struct test_format *format = &test_formats[i];
  538. FILE *file;
  539. snprintf(name, PATH_MAX, "%s/%s", dir, format->name);
  540. file = fopen(name, "w");
  541. if (!file)
  542. return NULL;
  543. if (1 != fwrite(format->value, strlen(format->value), 1, file))
  544. break;
  545. fclose(file);
  546. }
  547. return dir;
  548. }
  549. /* Cleanup format directory. */
  550. static int test_format_dir_put(char *dir)
  551. {
  552. char buf[PATH_MAX];
  553. snprintf(buf, PATH_MAX, "rm -f %s/*\n", dir);
  554. if (system(buf))
  555. return -1;
  556. snprintf(buf, PATH_MAX, "rmdir %s\n", dir);
  557. return system(buf);
  558. }
  559. static struct list_head *test_terms_list(void)
  560. {
  561. static LIST_HEAD(terms);
  562. unsigned int i;
  563. for (i = 0; i < TERMS_CNT; i++)
  564. list_add_tail(&test_terms[i].list, &terms);
  565. return &terms;
  566. }
  567. #undef TERMS_CNT
  568. int perf_pmu__test(void)
  569. {
  570. char *format = test_format_dir_get();
  571. LIST_HEAD(formats);
  572. struct list_head *terms = test_terms_list();
  573. int ret;
  574. if (!format)
  575. return -EINVAL;
  576. do {
  577. struct perf_event_attr attr;
  578. memset(&attr, 0, sizeof(attr));
  579. ret = pmu_format_parse(format, &formats);
  580. if (ret)
  581. break;
  582. ret = pmu_config(&formats, &attr, terms);
  583. if (ret)
  584. break;
  585. ret = -EINVAL;
  586. if (attr.config != 0xc00000000002a823)
  587. break;
  588. if (attr.config1 != 0x8000400000000145)
  589. break;
  590. if (attr.config2 != 0x0400000020041d07)
  591. break;
  592. ret = 0;
  593. } while (0);
  594. test_format_dir_put(format);
  595. return ret;
  596. }