metricgroup.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  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. free(metric_events);
  158. continue;
  159. }
  160. for (i = 0; i < eg->idnum; i++)
  161. metric_events[i]->collect_stat = true;
  162. me = metricgroup__lookup(metric_events_list, evsel, true);
  163. if (!me) {
  164. ret = -ENOMEM;
  165. free(metric_events);
  166. break;
  167. }
  168. expr = malloc(sizeof(struct metric_expr));
  169. if (!expr) {
  170. ret = -ENOMEM;
  171. free(metric_events);
  172. break;
  173. }
  174. expr->metric_expr = eg->metric_expr;
  175. expr->metric_name = eg->metric_name;
  176. expr->metric_events = metric_events;
  177. list_add(&expr->nd, &me->head);
  178. }
  179. return ret;
  180. }
  181. static bool match_metric(const char *n, const char *list)
  182. {
  183. int len;
  184. char *m;
  185. if (!list)
  186. return false;
  187. if (!strcmp(list, "all"))
  188. return true;
  189. if (!n)
  190. return !strcasecmp(list, "No_group");
  191. len = strlen(list);
  192. m = strcasestr(n, list);
  193. if (!m)
  194. return false;
  195. if ((m == n || m[-1] == ';' || m[-1] == ' ') &&
  196. (m[len] == 0 || m[len] == ';'))
  197. return true;
  198. return false;
  199. }
  200. struct mep {
  201. struct rb_node nd;
  202. const char *name;
  203. struct strlist *metrics;
  204. };
  205. static int mep_cmp(struct rb_node *rb_node, const void *entry)
  206. {
  207. struct mep *a = container_of(rb_node, struct mep, nd);
  208. struct mep *b = (struct mep *)entry;
  209. return strcmp(a->name, b->name);
  210. }
  211. static struct rb_node *mep_new(struct rblist *rl __maybe_unused,
  212. const void *entry)
  213. {
  214. struct mep *me = malloc(sizeof(struct mep));
  215. if (!me)
  216. return NULL;
  217. memcpy(me, entry, sizeof(struct mep));
  218. me->name = strdup(me->name);
  219. if (!me->name)
  220. goto out_me;
  221. me->metrics = strlist__new(NULL, NULL);
  222. if (!me->metrics)
  223. goto out_name;
  224. return &me->nd;
  225. out_name:
  226. free((char *)me->name);
  227. out_me:
  228. free(me);
  229. return NULL;
  230. }
  231. static struct mep *mep_lookup(struct rblist *groups, const char *name)
  232. {
  233. struct rb_node *nd;
  234. struct mep me = {
  235. .name = name
  236. };
  237. nd = rblist__find(groups, &me);
  238. if (nd)
  239. return container_of(nd, struct mep, nd);
  240. rblist__add_node(groups, &me);
  241. nd = rblist__find(groups, &me);
  242. if (nd)
  243. return container_of(nd, struct mep, nd);
  244. return NULL;
  245. }
  246. static void mep_delete(struct rblist *rl __maybe_unused,
  247. struct rb_node *nd)
  248. {
  249. struct mep *me = container_of(nd, struct mep, nd);
  250. strlist__delete(me->metrics);
  251. free((void *)me->name);
  252. free(me);
  253. }
  254. static void metricgroup__print_strlist(struct strlist *metrics, bool raw)
  255. {
  256. struct str_node *sn;
  257. int n = 0;
  258. strlist__for_each_entry (sn, metrics) {
  259. if (raw)
  260. printf("%s%s", n > 0 ? " " : "", sn->s);
  261. else
  262. printf(" %s\n", sn->s);
  263. n++;
  264. }
  265. if (raw)
  266. putchar('\n');
  267. }
  268. void metricgroup__print(bool metrics, bool metricgroups, char *filter,
  269. bool raw)
  270. {
  271. struct pmu_events_map *map = perf_pmu__find_map(NULL);
  272. struct pmu_event *pe;
  273. int i;
  274. struct rblist groups;
  275. struct rb_node *node, *next;
  276. struct strlist *metriclist = NULL;
  277. if (!map)
  278. return;
  279. if (!metricgroups) {
  280. metriclist = strlist__new(NULL, NULL);
  281. if (!metriclist)
  282. return;
  283. }
  284. rblist__init(&groups);
  285. groups.node_new = mep_new;
  286. groups.node_cmp = mep_cmp;
  287. groups.node_delete = mep_delete;
  288. for (i = 0; ; i++) {
  289. const char *g;
  290. pe = &map->table[i];
  291. if (!pe->name && !pe->metric_group && !pe->metric_name)
  292. break;
  293. if (!pe->metric_expr)
  294. continue;
  295. g = pe->metric_group;
  296. if (!g && pe->metric_name) {
  297. if (pe->name)
  298. continue;
  299. g = "No_group";
  300. }
  301. if (g) {
  302. char *omg;
  303. char *mg = strdup(g);
  304. if (!mg)
  305. return;
  306. omg = mg;
  307. while ((g = strsep(&mg, ";")) != NULL) {
  308. struct mep *me;
  309. char *s;
  310. if (*g == 0)
  311. g = "No_group";
  312. while (isspace(*g))
  313. g++;
  314. if (filter && !strstr(g, filter))
  315. continue;
  316. if (raw)
  317. s = (char *)pe->metric_name;
  318. else {
  319. if (asprintf(&s, "%s\n%*s%s]",
  320. pe->metric_name, 8, "[", pe->desc) < 0)
  321. return;
  322. }
  323. if (!s)
  324. continue;
  325. if (!metricgroups) {
  326. strlist__add(metriclist, s);
  327. } else {
  328. me = mep_lookup(&groups, g);
  329. if (!me)
  330. continue;
  331. strlist__add(me->metrics, s);
  332. }
  333. }
  334. free(omg);
  335. }
  336. }
  337. if (metricgroups && !raw)
  338. printf("\nMetric Groups:\n\n");
  339. else if (metrics && !raw)
  340. printf("\nMetrics:\n\n");
  341. for (node = rb_first(&groups.entries); node; node = next) {
  342. struct mep *me = container_of(node, struct mep, nd);
  343. if (metricgroups)
  344. printf("%s%s%s", me->name, metrics ? ":" : "", raw ? " " : "\n");
  345. if (metrics)
  346. metricgroup__print_strlist(me->metrics, raw);
  347. next = rb_next(node);
  348. rblist__remove_node(&groups, node);
  349. }
  350. if (!metricgroups)
  351. metricgroup__print_strlist(metriclist, raw);
  352. strlist__delete(metriclist);
  353. }
  354. static int metricgroup__add_metric(const char *metric, struct strbuf *events,
  355. struct list_head *group_list)
  356. {
  357. struct pmu_events_map *map = perf_pmu__find_map(NULL);
  358. struct pmu_event *pe;
  359. int ret = -EINVAL;
  360. int i, j;
  361. if (!map)
  362. return 0;
  363. for (i = 0; ; i++) {
  364. pe = &map->table[i];
  365. if (!pe->name && !pe->metric_group && !pe->metric_name)
  366. break;
  367. if (!pe->metric_expr)
  368. continue;
  369. if (match_metric(pe->metric_group, metric) ||
  370. match_metric(pe->metric_name, metric)) {
  371. const char **ids;
  372. int idnum;
  373. struct egroup *eg;
  374. pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
  375. if (expr__find_other(pe->metric_expr,
  376. NULL, &ids, &idnum) < 0)
  377. continue;
  378. if (events->len > 0)
  379. strbuf_addf(events, ",");
  380. for (j = 0; j < idnum; j++) {
  381. pr_debug("found event %s\n", ids[j]);
  382. strbuf_addf(events, "%s%s",
  383. j == 0 ? "{" : ",",
  384. ids[j]);
  385. }
  386. strbuf_addf(events, "}:W");
  387. eg = malloc(sizeof(struct egroup));
  388. if (!eg) {
  389. ret = -ENOMEM;
  390. break;
  391. }
  392. eg->ids = ids;
  393. eg->idnum = idnum;
  394. eg->metric_name = pe->metric_name;
  395. eg->metric_expr = pe->metric_expr;
  396. list_add_tail(&eg->nd, group_list);
  397. ret = 0;
  398. }
  399. }
  400. return ret;
  401. }
  402. static int metricgroup__add_metric_list(const char *list, struct strbuf *events,
  403. struct list_head *group_list)
  404. {
  405. char *llist, *nlist, *p;
  406. int ret = -EINVAL;
  407. nlist = strdup(list);
  408. if (!nlist)
  409. return -ENOMEM;
  410. llist = nlist;
  411. strbuf_init(events, 100);
  412. strbuf_addf(events, "%s", "");
  413. while ((p = strsep(&llist, ",")) != NULL) {
  414. ret = metricgroup__add_metric(p, events, group_list);
  415. if (ret == -EINVAL) {
  416. fprintf(stderr, "Cannot find metric or group `%s'\n",
  417. p);
  418. break;
  419. }
  420. }
  421. free(nlist);
  422. return ret;
  423. }
  424. static void metricgroup__free_egroups(struct list_head *group_list)
  425. {
  426. struct egroup *eg, *egtmp;
  427. int i;
  428. list_for_each_entry_safe (eg, egtmp, group_list, nd) {
  429. for (i = 0; i < eg->idnum; i++)
  430. free((char *)eg->ids[i]);
  431. free(eg->ids);
  432. free(eg);
  433. }
  434. }
  435. int metricgroup__parse_groups(const struct option *opt,
  436. const char *str,
  437. struct rblist *metric_events)
  438. {
  439. struct parse_events_error parse_error;
  440. struct perf_evlist *perf_evlist = *(struct perf_evlist **)opt->value;
  441. struct strbuf extra_events;
  442. LIST_HEAD(group_list);
  443. int ret;
  444. if (metric_events->nr_entries == 0)
  445. metricgroup__rblist_init(metric_events);
  446. ret = metricgroup__add_metric_list(str, &extra_events, &group_list);
  447. if (ret)
  448. return ret;
  449. pr_debug("adding %s\n", extra_events.buf);
  450. memset(&parse_error, 0, sizeof(struct parse_events_error));
  451. ret = parse_events(perf_evlist, extra_events.buf, &parse_error);
  452. if (ret) {
  453. parse_events_print_error(&parse_error, extra_events.buf);
  454. goto out;
  455. }
  456. strbuf_release(&extra_events);
  457. ret = metricgroup__setup_events(&group_list, perf_evlist,
  458. metric_events);
  459. out:
  460. metricgroup__free_egroups(&group_list);
  461. return ret;
  462. }
  463. bool metricgroup__has_metric(const char *metric)
  464. {
  465. struct pmu_events_map *map = perf_pmu__find_map(NULL);
  466. struct pmu_event *pe;
  467. int i;
  468. if (!map)
  469. return false;
  470. for (i = 0; ; i++) {
  471. pe = &map->table[i];
  472. if (!pe->name && !pe->metric_group && !pe->metric_name)
  473. break;
  474. if (!pe->metric_expr)
  475. continue;
  476. if (match_metric(pe->metric_name, metric))
  477. return true;
  478. }
  479. return false;
  480. }