pmu.c 14 KB

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