pmu.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  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 0; /* no error if 'events' does not exist */
  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_aliases(name, &aliases))
  240. return NULL;
  241. if (pmu_type(name, &type))
  242. return NULL;
  243. pmu = zalloc(sizeof(*pmu));
  244. if (!pmu)
  245. return NULL;
  246. pmu->cpus = pmu_cpumask(name);
  247. INIT_LIST_HEAD(&pmu->format);
  248. INIT_LIST_HEAD(&pmu->aliases);
  249. list_splice(&format, &pmu->format);
  250. list_splice(&aliases, &pmu->aliases);
  251. pmu->name = strdup(name);
  252. pmu->type = type;
  253. list_add_tail(&pmu->list, &pmus);
  254. return pmu;
  255. }
  256. static struct perf_pmu *pmu_find(char *name)
  257. {
  258. struct perf_pmu *pmu;
  259. list_for_each_entry(pmu, &pmus, list)
  260. if (!strcmp(pmu->name, name))
  261. return pmu;
  262. return NULL;
  263. }
  264. struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu)
  265. {
  266. /*
  267. * pmu iterator: If pmu is NULL, we start at the begin,
  268. * otherwise return the next pmu. Returns NULL on end.
  269. */
  270. if (!pmu) {
  271. pmu_read_sysfs();
  272. pmu = list_prepare_entry(pmu, &pmus, list);
  273. }
  274. list_for_each_entry_continue(pmu, &pmus, list)
  275. return pmu;
  276. return NULL;
  277. }
  278. struct perf_pmu *perf_pmu__find(char *name)
  279. {
  280. struct perf_pmu *pmu;
  281. /*
  282. * Once PMU is loaded it stays in the list,
  283. * so we keep us from multiple reading/parsing
  284. * the pmu format definitions.
  285. */
  286. pmu = pmu_find(name);
  287. if (pmu)
  288. return pmu;
  289. return pmu_lookup(name);
  290. }
  291. static struct perf_pmu__format*
  292. pmu_find_format(struct list_head *formats, char *name)
  293. {
  294. struct perf_pmu__format *format;
  295. list_for_each_entry(format, formats, list)
  296. if (!strcmp(format->name, name))
  297. return format;
  298. return NULL;
  299. }
  300. /*
  301. * Returns value based on the format definition (format parameter)
  302. * and unformated value (value parameter).
  303. *
  304. * TODO maybe optimize a little ;)
  305. */
  306. static __u64 pmu_format_value(unsigned long *format, __u64 value)
  307. {
  308. unsigned long fbit, vbit;
  309. __u64 v = 0;
  310. for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
  311. if (!test_bit(fbit, format))
  312. continue;
  313. if (!(value & (1llu << vbit++)))
  314. continue;
  315. v |= (1llu << fbit);
  316. }
  317. return v;
  318. }
  319. /*
  320. * Setup one of config[12] attr members based on the
  321. * user input data - temr parameter.
  322. */
  323. static int pmu_config_term(struct list_head *formats,
  324. struct perf_event_attr *attr,
  325. struct parse_events__term *term)
  326. {
  327. struct perf_pmu__format *format;
  328. __u64 *vp;
  329. /*
  330. * Support only for hardcoded and numnerial terms.
  331. * Hardcoded terms should be already in, so nothing
  332. * to be done for them.
  333. */
  334. if (parse_events__is_hardcoded_term(term))
  335. return 0;
  336. if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM)
  337. return -EINVAL;
  338. format = pmu_find_format(formats, term->config);
  339. if (!format)
  340. return -EINVAL;
  341. switch (format->value) {
  342. case PERF_PMU_FORMAT_VALUE_CONFIG:
  343. vp = &attr->config;
  344. break;
  345. case PERF_PMU_FORMAT_VALUE_CONFIG1:
  346. vp = &attr->config1;
  347. break;
  348. case PERF_PMU_FORMAT_VALUE_CONFIG2:
  349. vp = &attr->config2;
  350. break;
  351. default:
  352. return -EINVAL;
  353. }
  354. /*
  355. * XXX If we ever decide to go with string values for
  356. * non-hardcoded terms, here's the place to translate
  357. * them into value.
  358. */
  359. *vp |= pmu_format_value(format->bits, term->val.num);
  360. return 0;
  361. }
  362. static int pmu_config(struct list_head *formats, struct perf_event_attr *attr,
  363. struct list_head *head_terms)
  364. {
  365. struct parse_events__term *term;
  366. list_for_each_entry(term, head_terms, list)
  367. if (pmu_config_term(formats, attr, term))
  368. return -EINVAL;
  369. return 0;
  370. }
  371. /*
  372. * Configures event's 'attr' parameter based on the:
  373. * 1) users input - specified in terms parameter
  374. * 2) pmu format definitions - specified by pmu parameter
  375. */
  376. int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
  377. struct list_head *head_terms)
  378. {
  379. attr->type = pmu->type;
  380. return pmu_config(&pmu->format, attr, head_terms);
  381. }
  382. static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu,
  383. struct parse_events__term *term)
  384. {
  385. struct perf_pmu__alias *alias;
  386. char *name;
  387. if (parse_events__is_hardcoded_term(term))
  388. return NULL;
  389. if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) {
  390. if (term->val.num != 1)
  391. return NULL;
  392. if (pmu_find_format(&pmu->format, term->config))
  393. return NULL;
  394. name = term->config;
  395. } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) {
  396. if (strcasecmp(term->config, "event"))
  397. return NULL;
  398. name = term->val.str;
  399. } else {
  400. return NULL;
  401. }
  402. list_for_each_entry(alias, &pmu->aliases, list) {
  403. if (!strcasecmp(alias->name, name))
  404. return alias;
  405. }
  406. return NULL;
  407. }
  408. /*
  409. * Find alias in the terms list and replace it with the terms
  410. * defined for the alias
  411. */
  412. int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms)
  413. {
  414. struct parse_events__term *term, *h;
  415. struct perf_pmu__alias *alias;
  416. int ret;
  417. list_for_each_entry_safe(term, h, head_terms, list) {
  418. alias = pmu_find_alias(pmu, term);
  419. if (!alias)
  420. continue;
  421. ret = pmu_alias_terms(alias, &term->list);
  422. if (ret)
  423. return ret;
  424. list_del(&term->list);
  425. free(term);
  426. }
  427. return 0;
  428. }
  429. int perf_pmu__new_format(struct list_head *list, char *name,
  430. int config, unsigned long *bits)
  431. {
  432. struct perf_pmu__format *format;
  433. format = zalloc(sizeof(*format));
  434. if (!format)
  435. return -ENOMEM;
  436. format->name = strdup(name);
  437. format->value = config;
  438. memcpy(format->bits, bits, sizeof(format->bits));
  439. list_add_tail(&format->list, list);
  440. return 0;
  441. }
  442. void perf_pmu__set_format(unsigned long *bits, long from, long to)
  443. {
  444. long b;
  445. if (!to)
  446. to = from;
  447. memset(bits, 0, BITS_TO_LONGS(PERF_PMU_FORMAT_BITS));
  448. for (b = from; b <= to; b++)
  449. set_bit(b, bits);
  450. }
  451. /* Simulated format definitions. */
  452. static struct test_format {
  453. const char *name;
  454. const char *value;
  455. } test_formats[] = {
  456. { "krava01", "config:0-1,62-63\n", },
  457. { "krava02", "config:10-17\n", },
  458. { "krava03", "config:5\n", },
  459. { "krava11", "config1:0,2,4,6,8,20-28\n", },
  460. { "krava12", "config1:63\n", },
  461. { "krava13", "config1:45-47\n", },
  462. { "krava21", "config2:0-3,10-13,20-23,30-33,40-43,50-53,60-63\n", },
  463. { "krava22", "config2:8,18,48,58\n", },
  464. { "krava23", "config2:28-29,38\n", },
  465. };
  466. #define TEST_FORMATS_CNT (sizeof(test_formats) / sizeof(struct test_format))
  467. /* Simulated users input. */
  468. static struct parse_events__term test_terms[] = {
  469. {
  470. .config = (char *) "krava01",
  471. .val.num = 15,
  472. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  473. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  474. },
  475. {
  476. .config = (char *) "krava02",
  477. .val.num = 170,
  478. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  479. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  480. },
  481. {
  482. .config = (char *) "krava03",
  483. .val.num = 1,
  484. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  485. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  486. },
  487. {
  488. .config = (char *) "krava11",
  489. .val.num = 27,
  490. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  491. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  492. },
  493. {
  494. .config = (char *) "krava12",
  495. .val.num = 1,
  496. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  497. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  498. },
  499. {
  500. .config = (char *) "krava13",
  501. .val.num = 2,
  502. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  503. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  504. },
  505. {
  506. .config = (char *) "krava21",
  507. .val.num = 119,
  508. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  509. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  510. },
  511. {
  512. .config = (char *) "krava22",
  513. .val.num = 11,
  514. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  515. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  516. },
  517. {
  518. .config = (char *) "krava23",
  519. .val.num = 2,
  520. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  521. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  522. },
  523. };
  524. #define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
  525. /*
  526. * Prepare format directory data, exported by kernel
  527. * at /sys/bus/event_source/devices/<dev>/format.
  528. */
  529. static char *test_format_dir_get(void)
  530. {
  531. static char dir[PATH_MAX];
  532. unsigned int i;
  533. snprintf(dir, PATH_MAX, "/tmp/perf-pmu-test-format-XXXXXX");
  534. if (!mkdtemp(dir))
  535. return NULL;
  536. for (i = 0; i < TEST_FORMATS_CNT; i++) {
  537. static char name[PATH_MAX];
  538. struct test_format *format = &test_formats[i];
  539. FILE *file;
  540. snprintf(name, PATH_MAX, "%s/%s", dir, format->name);
  541. file = fopen(name, "w");
  542. if (!file)
  543. return NULL;
  544. if (1 != fwrite(format->value, strlen(format->value), 1, file))
  545. break;
  546. fclose(file);
  547. }
  548. return dir;
  549. }
  550. /* Cleanup format directory. */
  551. static int test_format_dir_put(char *dir)
  552. {
  553. char buf[PATH_MAX];
  554. snprintf(buf, PATH_MAX, "rm -f %s/*\n", dir);
  555. if (system(buf))
  556. return -1;
  557. snprintf(buf, PATH_MAX, "rmdir %s\n", dir);
  558. return system(buf);
  559. }
  560. static struct list_head *test_terms_list(void)
  561. {
  562. static LIST_HEAD(terms);
  563. unsigned int i;
  564. for (i = 0; i < TERMS_CNT; i++)
  565. list_add_tail(&test_terms[i].list, &terms);
  566. return &terms;
  567. }
  568. #undef TERMS_CNT
  569. int perf_pmu__test(void)
  570. {
  571. char *format = test_format_dir_get();
  572. LIST_HEAD(formats);
  573. struct list_head *terms = test_terms_list();
  574. int ret;
  575. if (!format)
  576. return -EINVAL;
  577. do {
  578. struct perf_event_attr attr;
  579. memset(&attr, 0, sizeof(attr));
  580. ret = pmu_format_parse(format, &formats);
  581. if (ret)
  582. break;
  583. ret = pmu_config(&formats, &attr, terms);
  584. if (ret)
  585. break;
  586. ret = -EINVAL;
  587. if (attr.config != 0xc00000000002a823)
  588. break;
  589. if (attr.config1 != 0x8000400000000145)
  590. break;
  591. if (attr.config2 != 0x0400000020041d07)
  592. break;
  593. ret = 0;
  594. } while (0);
  595. test_format_dir_put(format);
  596. return ret;
  597. }