metricgroup.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. /*
  2. * Copyright (c) 2017, Intel Corporation.
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms and conditions of the GNU General Public License,
  6. * version 2, as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope it will be useful, but WITHOUT
  9. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  11. * more details.
  12. *
  13. */
  14. /* Manage metrics and groups of metrics from JSON files */
  15. #include "metricgroup.h"
  16. #include "evlist.h"
  17. #include "strbuf.h"
  18. #include "pmu.h"
  19. #include "expr.h"
  20. #include "rblist.h"
  21. #include <string.h>
  22. #include <stdbool.h>
  23. #include <errno.h>
  24. #include "pmu-events/pmu-events.h"
  25. #include "strlist.h"
  26. #include <assert.h>
  27. #include <ctype.h>
  28. struct metric_event *metricgroup__lookup(struct rblist *metric_events,
  29. struct perf_evsel *evsel,
  30. bool create)
  31. {
  32. struct rb_node *nd;
  33. struct metric_event me = {
  34. .evsel = evsel
  35. };
  36. if (!metric_events)
  37. return NULL;
  38. nd = rblist__find(metric_events, &me);
  39. if (nd)
  40. return container_of(nd, struct metric_event, nd);
  41. if (create) {
  42. rblist__add_node(metric_events, &me);
  43. nd = rblist__find(metric_events, &me);
  44. if (nd)
  45. return container_of(nd, struct metric_event, nd);
  46. }
  47. return NULL;
  48. }
  49. static int metric_event_cmp(struct rb_node *rb_node, const void *entry)
  50. {
  51. struct metric_event *a = container_of(rb_node,
  52. struct metric_event,
  53. nd);
  54. const struct metric_event *b = entry;
  55. if (a->evsel == b->evsel)
  56. return 0;
  57. if ((char *)a->evsel < (char *)b->evsel)
  58. return -1;
  59. return +1;
  60. }
  61. static struct rb_node *metric_event_new(struct rblist *rblist __maybe_unused,
  62. const void *entry)
  63. {
  64. struct metric_event *me = malloc(sizeof(struct metric_event));
  65. if (!me)
  66. return NULL;
  67. memcpy(me, entry, sizeof(struct metric_event));
  68. me->evsel = ((struct metric_event *)entry)->evsel;
  69. INIT_LIST_HEAD(&me->head);
  70. return &me->nd;
  71. }
  72. static void metricgroup__rblist_init(struct rblist *metric_events)
  73. {
  74. rblist__init(metric_events);
  75. metric_events->node_cmp = metric_event_cmp;
  76. metric_events->node_new = metric_event_new;
  77. }
  78. struct egroup {
  79. struct list_head nd;
  80. int idnum;
  81. const char **ids;
  82. const char *metric_name;
  83. const char *metric_expr;
  84. };
  85. static bool record_evsel(int *ind, struct perf_evsel **start,
  86. int idnum,
  87. struct perf_evsel **metric_events,
  88. struct perf_evsel *ev)
  89. {
  90. metric_events[*ind] = ev;
  91. if (*ind == 0)
  92. *start = ev;
  93. if (++*ind == idnum) {
  94. metric_events[*ind] = NULL;
  95. return true;
  96. }
  97. return false;
  98. }
  99. static struct perf_evsel *find_evsel_group(struct perf_evlist *perf_evlist,
  100. const char **ids,
  101. int idnum,
  102. struct perf_evsel **metric_events)
  103. {
  104. struct perf_evsel *ev, *start = NULL;
  105. int ind = 0;
  106. evlist__for_each_entry (perf_evlist, ev) {
  107. if (ev->collect_stat)
  108. continue;
  109. if (!strcmp(ev->name, ids[ind])) {
  110. if (record_evsel(&ind, &start, idnum,
  111. metric_events, ev))
  112. return start;
  113. } else {
  114. /*
  115. * We saw some other event that is not
  116. * in our list of events. Discard
  117. * the whole match and start again.
  118. */
  119. ind = 0;
  120. start = NULL;
  121. if (!strcmp(ev->name, ids[ind])) {
  122. if (record_evsel(&ind, &start, idnum,
  123. metric_events, ev))
  124. return start;
  125. }
  126. }
  127. }
  128. /*
  129. * This can happen when an alias expands to multiple
  130. * events, like for uncore events.
  131. * We don't support this case for now.
  132. */
  133. return NULL;
  134. }
  135. static int metricgroup__setup_events(struct list_head *groups,
  136. struct perf_evlist *perf_evlist,
  137. struct rblist *metric_events_list)
  138. {
  139. struct metric_event *me;
  140. struct metric_expr *expr;
  141. int i = 0;
  142. int ret = 0;
  143. struct egroup *eg;
  144. struct perf_evsel *evsel;
  145. list_for_each_entry (eg, groups, nd) {
  146. struct perf_evsel **metric_events;
  147. metric_events = calloc(sizeof(void *), eg->idnum + 1);
  148. if (!metric_events) {
  149. ret = -ENOMEM;
  150. break;
  151. }
  152. evsel = find_evsel_group(perf_evlist, eg->ids, eg->idnum,
  153. metric_events);
  154. if (!evsel) {
  155. pr_debug("Cannot resolve %s: %s\n",
  156. eg->metric_name, eg->metric_expr);
  157. continue;
  158. }
  159. for (i = 0; i < eg->idnum; i++)
  160. metric_events[i]->collect_stat = true;
  161. me = metricgroup__lookup(metric_events_list, evsel, true);
  162. if (!me) {
  163. ret = -ENOMEM;
  164. break;
  165. }
  166. expr = malloc(sizeof(struct metric_expr));
  167. if (!expr) {
  168. ret = -ENOMEM;
  169. break;
  170. }
  171. expr->metric_expr = eg->metric_expr;
  172. expr->metric_name = eg->metric_name;
  173. expr->metric_events = metric_events;
  174. list_add(&expr->nd, &me->head);
  175. }
  176. return ret;
  177. }
  178. static bool match_metric(const char *n, const char *list)
  179. {
  180. int len;
  181. char *m;
  182. if (!list)
  183. return false;
  184. if (!strcmp(list, "all"))
  185. return true;
  186. if (!n)
  187. return !strcasecmp(list, "No_group");
  188. len = strlen(list);
  189. m = strcasestr(n, list);
  190. if (!m)
  191. return false;
  192. if ((m == n || m[-1] == ';' || m[-1] == ' ') &&
  193. (m[len] == 0 || m[len] == ';'))
  194. return true;
  195. return false;
  196. }
  197. struct mep {
  198. struct rb_node nd;
  199. const char *name;
  200. struct strlist *metrics;
  201. };
  202. static int mep_cmp(struct rb_node *rb_node, const void *entry)
  203. {
  204. struct mep *a = container_of(rb_node, struct mep, nd);
  205. struct mep *b = (struct mep *)entry;
  206. return strcmp(a->name, b->name);
  207. }
  208. static struct rb_node *mep_new(struct rblist *rl __maybe_unused,
  209. const void *entry)
  210. {
  211. struct mep *me = malloc(sizeof(struct mep));
  212. if (!me)
  213. return NULL;
  214. memcpy(me, entry, sizeof(struct mep));
  215. me->name = strdup(me->name);
  216. if (!me->name)
  217. goto out_me;
  218. me->metrics = strlist__new(NULL, NULL);
  219. if (!me->metrics)
  220. goto out_name;
  221. return &me->nd;
  222. out_name:
  223. free((char *)me->name);
  224. out_me:
  225. free(me);
  226. return NULL;
  227. }
  228. static struct mep *mep_lookup(struct rblist *groups, const char *name)
  229. {
  230. struct rb_node *nd;
  231. struct mep me = {
  232. .name = name
  233. };
  234. nd = rblist__find(groups, &me);
  235. if (nd)
  236. return container_of(nd, struct mep, nd);
  237. rblist__add_node(groups, &me);
  238. nd = rblist__find(groups, &me);
  239. if (nd)
  240. return container_of(nd, struct mep, nd);
  241. return NULL;
  242. }
  243. static void mep_delete(struct rblist *rl __maybe_unused,
  244. struct rb_node *nd)
  245. {
  246. struct mep *me = container_of(nd, struct mep, nd);
  247. strlist__delete(me->metrics);
  248. free((void *)me->name);
  249. free(me);
  250. }
  251. static void metricgroup__print_strlist(struct strlist *metrics, bool raw)
  252. {
  253. struct str_node *sn;
  254. int n = 0;
  255. strlist__for_each_entry (sn, metrics) {
  256. if (raw)
  257. printf("%s%s", n > 0 ? " " : "", sn->s);
  258. else
  259. printf(" %s\n", sn->s);
  260. n++;
  261. }
  262. if (raw)
  263. putchar('\n');
  264. }
  265. void metricgroup__print(bool metrics, bool metricgroups, char *filter,
  266. bool raw)
  267. {
  268. struct pmu_events_map *map = perf_pmu__find_map(NULL);
  269. struct pmu_event *pe;
  270. int i;
  271. struct rblist groups;
  272. struct rb_node *node, *next;
  273. struct strlist *metriclist = NULL;
  274. if (!map)
  275. return;
  276. if (!metricgroups) {
  277. metriclist = strlist__new(NULL, NULL);
  278. if (!metriclist)
  279. return;
  280. }
  281. rblist__init(&groups);
  282. groups.node_new = mep_new;
  283. groups.node_cmp = mep_cmp;
  284. groups.node_delete = mep_delete;
  285. for (i = 0; ; i++) {
  286. const char *g;
  287. pe = &map->table[i];
  288. if (!pe->name && !pe->metric_group && !pe->metric_name)
  289. break;
  290. if (!pe->metric_expr)
  291. continue;
  292. g = pe->metric_group;
  293. if (!g && pe->metric_name) {
  294. if (pe->name)
  295. continue;
  296. g = "No_group";
  297. }
  298. if (g) {
  299. char *omg;
  300. char *mg = strdup(g);
  301. if (!mg)
  302. return;
  303. omg = mg;
  304. while ((g = strsep(&mg, ";")) != NULL) {
  305. struct mep *me;
  306. char *s;
  307. if (*g == 0)
  308. g = "No_group";
  309. while (isspace(*g))
  310. g++;
  311. if (filter && !strstr(g, filter))
  312. continue;
  313. if (raw)
  314. s = (char *)pe->metric_name;
  315. else {
  316. if (asprintf(&s, "%s\n%*s%s]",
  317. pe->metric_name, 8, "[", pe->desc) < 0)
  318. return;
  319. }
  320. if (!s)
  321. continue;
  322. if (!metricgroups) {
  323. strlist__add(metriclist, s);
  324. } else {
  325. me = mep_lookup(&groups, g);
  326. if (!me)
  327. continue;
  328. strlist__add(me->metrics, s);
  329. }
  330. }
  331. free(omg);
  332. }
  333. }
  334. if (metricgroups && !raw)
  335. printf("\nMetric Groups:\n\n");
  336. else if (metrics && !raw)
  337. printf("\nMetrics:\n\n");
  338. for (node = rb_first(&groups.entries); node; node = next) {
  339. struct mep *me = container_of(node, struct mep, nd);
  340. if (metricgroups)
  341. printf("%s%s%s", me->name, metrics ? ":" : "", raw ? " " : "\n");
  342. if (metrics)
  343. metricgroup__print_strlist(me->metrics, raw);
  344. next = rb_next(node);
  345. rblist__remove_node(&groups, node);
  346. }
  347. if (!metricgroups)
  348. metricgroup__print_strlist(metriclist, raw);
  349. strlist__delete(metriclist);
  350. }
  351. static int metricgroup__add_metric(const char *metric, struct strbuf *events,
  352. struct list_head *group_list)
  353. {
  354. struct pmu_events_map *map = perf_pmu__find_map(NULL);
  355. struct pmu_event *pe;
  356. int ret = -EINVAL;
  357. int i, j;
  358. if (!map)
  359. return 0;
  360. for (i = 0; ; i++) {
  361. pe = &map->table[i];
  362. if (!pe->name && !pe->metric_group && !pe->metric_name)
  363. break;
  364. if (!pe->metric_expr)
  365. continue;
  366. if (match_metric(pe->metric_group, metric) ||
  367. match_metric(pe->metric_name, metric)) {
  368. const char **ids;
  369. int idnum;
  370. struct egroup *eg;
  371. pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
  372. if (expr__find_other(pe->metric_expr,
  373. NULL, &ids, &idnum) < 0)
  374. continue;
  375. if (events->len > 0)
  376. strbuf_addf(events, ",");
  377. for (j = 0; j < idnum; j++) {
  378. pr_debug("found event %s\n", ids[j]);
  379. strbuf_addf(events, "%s%s",
  380. j == 0 ? "{" : ",",
  381. ids[j]);
  382. }
  383. strbuf_addf(events, "}:W");
  384. eg = malloc(sizeof(struct egroup));
  385. if (!eg) {
  386. ret = -ENOMEM;
  387. break;
  388. }
  389. eg->ids = ids;
  390. eg->idnum = idnum;
  391. eg->metric_name = pe->metric_name;
  392. eg->metric_expr = pe->metric_expr;
  393. list_add_tail(&eg->nd, group_list);
  394. ret = 0;
  395. }
  396. }
  397. return ret;
  398. }
  399. static int metricgroup__add_metric_list(const char *list, struct strbuf *events,
  400. struct list_head *group_list)
  401. {
  402. char *llist, *nlist, *p;
  403. int ret = -EINVAL;
  404. nlist = strdup(list);
  405. if (!nlist)
  406. return -ENOMEM;
  407. llist = nlist;
  408. strbuf_init(events, 100);
  409. strbuf_addf(events, "%s", "");
  410. while ((p = strsep(&llist, ",")) != NULL) {
  411. ret = metricgroup__add_metric(p, events, group_list);
  412. if (ret == -EINVAL) {
  413. fprintf(stderr, "Cannot find metric or group `%s'\n",
  414. p);
  415. break;
  416. }
  417. }
  418. free(nlist);
  419. return ret;
  420. }
  421. static void metricgroup__free_egroups(struct list_head *group_list)
  422. {
  423. struct egroup *eg, *egtmp;
  424. int i;
  425. list_for_each_entry_safe (eg, egtmp, group_list, nd) {
  426. for (i = 0; i < eg->idnum; i++)
  427. free((char *)eg->ids[i]);
  428. free(eg->ids);
  429. free(eg);
  430. }
  431. }
  432. int metricgroup__parse_groups(const struct option *opt,
  433. const char *str,
  434. struct rblist *metric_events)
  435. {
  436. struct parse_events_error parse_error;
  437. struct perf_evlist *perf_evlist = *(struct perf_evlist **)opt->value;
  438. struct strbuf extra_events;
  439. LIST_HEAD(group_list);
  440. int ret;
  441. if (metric_events->nr_entries == 0)
  442. metricgroup__rblist_init(metric_events);
  443. ret = metricgroup__add_metric_list(str, &extra_events, &group_list);
  444. if (ret)
  445. return ret;
  446. pr_debug("adding %s\n", extra_events.buf);
  447. memset(&parse_error, 0, sizeof(struct parse_events_error));
  448. ret = parse_events(perf_evlist, extra_events.buf, &parse_error);
  449. if (ret) {
  450. parse_events_print_error(&parse_error, extra_events.buf);
  451. goto out;
  452. }
  453. strbuf_release(&extra_events);
  454. ret = metricgroup__setup_events(&group_list, perf_evlist,
  455. metric_events);
  456. out:
  457. metricgroup__free_egroups(&group_list);
  458. return ret;
  459. }
  460. bool metricgroup__has_metric(const char *metric)
  461. {
  462. struct pmu_events_map *map = perf_pmu__find_map(NULL);
  463. struct pmu_event *pe;
  464. int i;
  465. if (!map)
  466. return false;
  467. for (i = 0; ; i++) {
  468. pe = &map->table[i];
  469. if (!pe->name && !pe->metric_group && !pe->metric_name)
  470. break;
  471. if (!pe->metric_expr)
  472. continue;
  473. if (match_metric(pe->metric_name, metric))
  474. return true;
  475. }
  476. return false;
  477. }