pmu.c 13 KB

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