pmu.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  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. /*
  66. * Reading/parsing the default pmu type value, which should be
  67. * located at:
  68. * /sys/bus/event_source/devices/<dev>/type as sysfs attribute.
  69. */
  70. static int pmu_type(char *name, __u32 *type)
  71. {
  72. struct stat st;
  73. char path[PATH_MAX];
  74. const char *sysfs;
  75. FILE *file;
  76. int ret = 0;
  77. sysfs = sysfs_find_mountpoint();
  78. if (!sysfs)
  79. return -1;
  80. snprintf(path, PATH_MAX,
  81. "%s/bus/event_source/devices/%s/type", sysfs, name);
  82. if (stat(path, &st) < 0)
  83. return -1;
  84. file = fopen(path, "r");
  85. if (!file)
  86. return -EINVAL;
  87. if (1 != fscanf(file, "%u", type))
  88. ret = -1;
  89. fclose(file);
  90. return ret;
  91. }
  92. static struct perf_pmu *pmu_lookup(char *name)
  93. {
  94. struct perf_pmu *pmu;
  95. LIST_HEAD(format);
  96. __u32 type;
  97. /*
  98. * The pmu data we store & need consists of the pmu
  99. * type value and format definitions. Load both right
  100. * now.
  101. */
  102. if (pmu_format(name, &format))
  103. return NULL;
  104. if (pmu_type(name, &type))
  105. return NULL;
  106. pmu = zalloc(sizeof(*pmu));
  107. if (!pmu)
  108. return NULL;
  109. INIT_LIST_HEAD(&pmu->format);
  110. list_splice(&format, &pmu->format);
  111. pmu->name = strdup(name);
  112. pmu->type = type;
  113. return pmu;
  114. }
  115. static struct perf_pmu *pmu_find(char *name)
  116. {
  117. struct perf_pmu *pmu;
  118. list_for_each_entry(pmu, &pmus, list)
  119. if (!strcmp(pmu->name, name))
  120. return pmu;
  121. return NULL;
  122. }
  123. struct perf_pmu *perf_pmu__find(char *name)
  124. {
  125. struct perf_pmu *pmu;
  126. /*
  127. * Once PMU is loaded it stays in the list,
  128. * so we keep us from multiple reading/parsing
  129. * the pmu format definitions.
  130. */
  131. pmu = pmu_find(name);
  132. if (pmu)
  133. return pmu;
  134. return pmu_lookup(name);
  135. }
  136. static struct perf_pmu__format*
  137. pmu_find_format(struct list_head *formats, char *name)
  138. {
  139. struct perf_pmu__format *format;
  140. list_for_each_entry(format, formats, list)
  141. if (!strcmp(format->name, name))
  142. return format;
  143. return NULL;
  144. }
  145. /*
  146. * Returns value based on the format definition (format parameter)
  147. * and unformated value (value parameter).
  148. *
  149. * TODO maybe optimize a little ;)
  150. */
  151. static __u64 pmu_format_value(unsigned long *format, __u64 value)
  152. {
  153. unsigned long fbit, vbit;
  154. __u64 v = 0;
  155. for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
  156. if (!test_bit(fbit, format))
  157. continue;
  158. if (!(value & (1llu << vbit++)))
  159. continue;
  160. v |= (1llu << fbit);
  161. }
  162. return v;
  163. }
  164. /*
  165. * Setup one of config[12] attr members based on the
  166. * user input data - temr parameter.
  167. */
  168. static int pmu_config_term(struct list_head *formats,
  169. struct perf_event_attr *attr,
  170. struct parse_events__term *term)
  171. {
  172. struct perf_pmu__format *format;
  173. __u64 *vp;
  174. /*
  175. * Support only for hardcoded and numnerial terms.
  176. * Hardcoded terms should be already in, so nothing
  177. * to be done for them.
  178. */
  179. if (parse_events__is_hardcoded_term(term))
  180. return 0;
  181. if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM)
  182. return -EINVAL;
  183. format = pmu_find_format(formats, term->config);
  184. if (!format)
  185. return -EINVAL;
  186. switch (format->value) {
  187. case PERF_PMU_FORMAT_VALUE_CONFIG:
  188. vp = &attr->config;
  189. break;
  190. case PERF_PMU_FORMAT_VALUE_CONFIG1:
  191. vp = &attr->config1;
  192. break;
  193. case PERF_PMU_FORMAT_VALUE_CONFIG2:
  194. vp = &attr->config2;
  195. break;
  196. default:
  197. return -EINVAL;
  198. }
  199. /*
  200. * XXX If we ever decide to go with string values for
  201. * non-hardcoded terms, here's the place to translate
  202. * them into value.
  203. */
  204. *vp |= pmu_format_value(format->bits, term->val.num);
  205. return 0;
  206. }
  207. static int pmu_config(struct list_head *formats, struct perf_event_attr *attr,
  208. struct list_head *head_terms)
  209. {
  210. struct parse_events__term *term;
  211. list_for_each_entry(term, head_terms, list)
  212. if (pmu_config_term(formats, attr, term))
  213. return -EINVAL;
  214. return 0;
  215. }
  216. /*
  217. * Configures event's 'attr' parameter based on the:
  218. * 1) users input - specified in terms parameter
  219. * 2) pmu format definitions - specified by pmu parameter
  220. */
  221. int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
  222. struct list_head *head_terms)
  223. {
  224. attr->type = pmu->type;
  225. return pmu_config(&pmu->format, attr, head_terms);
  226. }
  227. int perf_pmu__new_format(struct list_head *list, char *name,
  228. int config, unsigned long *bits)
  229. {
  230. struct perf_pmu__format *format;
  231. format = zalloc(sizeof(*format));
  232. if (!format)
  233. return -ENOMEM;
  234. format->name = strdup(name);
  235. format->value = config;
  236. memcpy(format->bits, bits, sizeof(format->bits));
  237. list_add_tail(&format->list, list);
  238. return 0;
  239. }
  240. void perf_pmu__set_format(unsigned long *bits, long from, long to)
  241. {
  242. long b;
  243. if (!to)
  244. to = from;
  245. memset(bits, 0, BITS_TO_LONGS(PERF_PMU_FORMAT_BITS));
  246. for (b = from; b <= to; b++)
  247. set_bit(b, bits);
  248. }
  249. /* Simulated format definitions. */
  250. static struct test_format {
  251. const char *name;
  252. const char *value;
  253. } test_formats[] = {
  254. { "krava01", "config:0-1,62-63\n", },
  255. { "krava02", "config:10-17\n", },
  256. { "krava03", "config:5\n", },
  257. { "krava11", "config1:0,2,4,6,8,20-28\n", },
  258. { "krava12", "config1:63\n", },
  259. { "krava13", "config1:45-47\n", },
  260. { "krava21", "config2:0-3,10-13,20-23,30-33,40-43,50-53,60-63\n", },
  261. { "krava22", "config2:8,18,48,58\n", },
  262. { "krava23", "config2:28-29,38\n", },
  263. };
  264. #define TEST_FORMATS_CNT (sizeof(test_formats) / sizeof(struct test_format))
  265. /* Simulated users input. */
  266. static struct parse_events__term test_terms[] = {
  267. {
  268. .config = (char *) "krava01",
  269. .val.num = 15,
  270. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  271. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  272. },
  273. {
  274. .config = (char *) "krava02",
  275. .val.num = 170,
  276. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  277. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  278. },
  279. {
  280. .config = (char *) "krava03",
  281. .val.num = 1,
  282. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  283. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  284. },
  285. {
  286. .config = (char *) "krava11",
  287. .val.num = 27,
  288. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  289. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  290. },
  291. {
  292. .config = (char *) "krava12",
  293. .val.num = 1,
  294. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  295. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  296. },
  297. {
  298. .config = (char *) "krava13",
  299. .val.num = 2,
  300. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  301. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  302. },
  303. {
  304. .config = (char *) "krava21",
  305. .val.num = 119,
  306. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  307. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  308. },
  309. {
  310. .config = (char *) "krava22",
  311. .val.num = 11,
  312. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  313. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  314. },
  315. {
  316. .config = (char *) "krava23",
  317. .val.num = 2,
  318. .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
  319. .type_term = PARSE_EVENTS__TERM_TYPE_USER,
  320. },
  321. };
  322. #define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
  323. /*
  324. * Prepare format directory data, exported by kernel
  325. * at /sys/bus/event_source/devices/<dev>/format.
  326. */
  327. static char *test_format_dir_get(void)
  328. {
  329. static char dir[PATH_MAX];
  330. unsigned int i;
  331. snprintf(dir, PATH_MAX, "/tmp/perf-pmu-test-format-XXXXXX");
  332. if (!mkdtemp(dir))
  333. return NULL;
  334. for (i = 0; i < TEST_FORMATS_CNT; i++) {
  335. static char name[PATH_MAX];
  336. struct test_format *format = &test_formats[i];
  337. FILE *file;
  338. snprintf(name, PATH_MAX, "%s/%s", dir, format->name);
  339. file = fopen(name, "w");
  340. if (!file)
  341. return NULL;
  342. if (1 != fwrite(format->value, strlen(format->value), 1, file))
  343. break;
  344. fclose(file);
  345. }
  346. return dir;
  347. }
  348. /* Cleanup format directory. */
  349. static int test_format_dir_put(char *dir)
  350. {
  351. char buf[PATH_MAX];
  352. snprintf(buf, PATH_MAX, "rm -f %s/*\n", dir);
  353. if (system(buf))
  354. return -1;
  355. snprintf(buf, PATH_MAX, "rmdir %s\n", dir);
  356. return system(buf);
  357. }
  358. static struct list_head *test_terms_list(void)
  359. {
  360. static LIST_HEAD(terms);
  361. unsigned int i;
  362. for (i = 0; i < TERMS_CNT; i++)
  363. list_add_tail(&test_terms[i].list, &terms);
  364. return &terms;
  365. }
  366. #undef TERMS_CNT
  367. int perf_pmu__test(void)
  368. {
  369. char *format = test_format_dir_get();
  370. LIST_HEAD(formats);
  371. struct list_head *terms = test_terms_list();
  372. int ret;
  373. if (!format)
  374. return -EINVAL;
  375. do {
  376. struct perf_event_attr attr;
  377. memset(&attr, 0, sizeof(attr));
  378. ret = pmu_format_parse(format, &formats);
  379. if (ret)
  380. break;
  381. ret = pmu_config(&formats, &attr, terms);
  382. if (ret)
  383. break;
  384. ret = -EINVAL;
  385. if (attr.config != 0xc00000000002a823)
  386. break;
  387. if (attr.config1 != 0x8000400000000145)
  388. break;
  389. if (attr.config2 != 0x0400000020041d07)
  390. break;
  391. ret = 0;
  392. } while (0);
  393. test_format_dir_put(format);
  394. return ret;
  395. }