pmu.c 13 KB

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