hists_link.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. #include "perf.h"
  2. #include "tests.h"
  3. #include "debug.h"
  4. #include "symbol.h"
  5. #include "sort.h"
  6. #include "evsel.h"
  7. #include "evlist.h"
  8. #include "machine.h"
  9. #include "thread.h"
  10. #include "parse-events.h"
  11. #include "hists_common.h"
  12. struct sample {
  13. u32 pid;
  14. u64 ip;
  15. struct thread *thread;
  16. struct map *map;
  17. struct symbol *sym;
  18. };
  19. /* For the numbers, see hists_common.c */
  20. static struct sample fake_common_samples[] = {
  21. /* perf [kernel] schedule() */
  22. { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, },
  23. /* perf [perf] main() */
  24. { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, },
  25. /* perf [perf] cmd_record() */
  26. { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_CMD_RECORD, },
  27. /* bash [bash] xmalloc() */
  28. { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XMALLOC, },
  29. /* bash [libc] malloc() */
  30. { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_MALLOC, },
  31. };
  32. static struct sample fake_samples[][5] = {
  33. {
  34. /* perf [perf] run_command() */
  35. { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_RUN_COMMAND, },
  36. /* perf [libc] malloc() */
  37. { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, },
  38. /* perf [kernel] page_fault() */
  39. { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
  40. /* perf [kernel] sys_perf_event_open() */
  41. { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_SYS_PERF_EVENT_OPEN, },
  42. /* bash [libc] free() */
  43. { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_FREE, },
  44. },
  45. {
  46. /* perf [libc] free() */
  47. { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_LIBC_FREE, },
  48. /* bash [libc] malloc() */
  49. { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_MALLOC, }, /* will be merged */
  50. /* bash [bash] xfee() */
  51. { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XFREE, },
  52. /* bash [libc] realloc() */
  53. { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_REALLOC, },
  54. /* bash [kernel] page_fault() */
  55. { .pid = FAKE_PID_BASH, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
  56. },
  57. };
  58. static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
  59. {
  60. struct perf_evsel *evsel;
  61. struct addr_location al;
  62. struct hist_entry *he;
  63. struct perf_sample sample = { .period = 1, };
  64. size_t i = 0, k;
  65. /*
  66. * each evsel will have 10 samples - 5 common and 5 distinct.
  67. * However the second evsel also has a collapsed entry for
  68. * "bash [libc] malloc" so total 9 entries will be in the tree.
  69. */
  70. evlist__for_each(evlist, evsel) {
  71. for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) {
  72. const union perf_event event = {
  73. .header = {
  74. .misc = PERF_RECORD_MISC_USER,
  75. },
  76. };
  77. sample.pid = fake_common_samples[k].pid;
  78. sample.tid = fake_common_samples[k].pid;
  79. sample.ip = fake_common_samples[k].ip;
  80. if (perf_event__preprocess_sample(&event, machine, &al,
  81. &sample) < 0)
  82. goto out;
  83. he = __hists__add_entry(&evsel->hists, &al, NULL,
  84. NULL, NULL, 1, 1, 0, true);
  85. if (he == NULL)
  86. goto out;
  87. fake_common_samples[k].thread = al.thread;
  88. fake_common_samples[k].map = al.map;
  89. fake_common_samples[k].sym = al.sym;
  90. }
  91. for (k = 0; k < ARRAY_SIZE(fake_samples[i]); k++) {
  92. const union perf_event event = {
  93. .header = {
  94. .misc = PERF_RECORD_MISC_USER,
  95. },
  96. };
  97. sample.pid = fake_samples[i][k].pid;
  98. sample.tid = fake_samples[i][k].pid;
  99. sample.ip = fake_samples[i][k].ip;
  100. if (perf_event__preprocess_sample(&event, machine, &al,
  101. &sample) < 0)
  102. goto out;
  103. he = __hists__add_entry(&evsel->hists, &al, NULL,
  104. NULL, NULL, 1, 1, 0, true);
  105. if (he == NULL)
  106. goto out;
  107. fake_samples[i][k].thread = al.thread;
  108. fake_samples[i][k].map = al.map;
  109. fake_samples[i][k].sym = al.sym;
  110. }
  111. i++;
  112. }
  113. return 0;
  114. out:
  115. pr_debug("Not enough memory for adding a hist entry\n");
  116. return -1;
  117. }
  118. static int find_sample(struct sample *samples, size_t nr_samples,
  119. struct thread *t, struct map *m, struct symbol *s)
  120. {
  121. while (nr_samples--) {
  122. if (samples->thread == t && samples->map == m &&
  123. samples->sym == s)
  124. return 1;
  125. samples++;
  126. }
  127. return 0;
  128. }
  129. static int __validate_match(struct hists *hists)
  130. {
  131. size_t count = 0;
  132. struct rb_root *root;
  133. struct rb_node *node;
  134. /*
  135. * Only entries from fake_common_samples should have a pair.
  136. */
  137. if (sort__need_collapse)
  138. root = &hists->entries_collapsed;
  139. else
  140. root = hists->entries_in;
  141. node = rb_first(root);
  142. while (node) {
  143. struct hist_entry *he;
  144. he = rb_entry(node, struct hist_entry, rb_node_in);
  145. if (hist_entry__has_pairs(he)) {
  146. if (find_sample(fake_common_samples,
  147. ARRAY_SIZE(fake_common_samples),
  148. he->thread, he->ms.map, he->ms.sym)) {
  149. count++;
  150. } else {
  151. pr_debug("Can't find the matched entry\n");
  152. return -1;
  153. }
  154. }
  155. node = rb_next(node);
  156. }
  157. if (count != ARRAY_SIZE(fake_common_samples)) {
  158. pr_debug("Invalid count for matched entries: %zd of %zd\n",
  159. count, ARRAY_SIZE(fake_common_samples));
  160. return -1;
  161. }
  162. return 0;
  163. }
  164. static int validate_match(struct hists *leader, struct hists *other)
  165. {
  166. return __validate_match(leader) || __validate_match(other);
  167. }
  168. static int __validate_link(struct hists *hists, int idx)
  169. {
  170. size_t count = 0;
  171. size_t count_pair = 0;
  172. size_t count_dummy = 0;
  173. struct rb_root *root;
  174. struct rb_node *node;
  175. /*
  176. * Leader hists (idx = 0) will have dummy entries from other,
  177. * and some entries will have no pair. However every entry
  178. * in other hists should have (dummy) pair.
  179. */
  180. if (sort__need_collapse)
  181. root = &hists->entries_collapsed;
  182. else
  183. root = hists->entries_in;
  184. node = rb_first(root);
  185. while (node) {
  186. struct hist_entry *he;
  187. he = rb_entry(node, struct hist_entry, rb_node_in);
  188. if (hist_entry__has_pairs(he)) {
  189. if (!find_sample(fake_common_samples,
  190. ARRAY_SIZE(fake_common_samples),
  191. he->thread, he->ms.map, he->ms.sym) &&
  192. !find_sample(fake_samples[idx],
  193. ARRAY_SIZE(fake_samples[idx]),
  194. he->thread, he->ms.map, he->ms.sym)) {
  195. count_dummy++;
  196. }
  197. count_pair++;
  198. } else if (idx) {
  199. pr_debug("A entry from the other hists should have pair\n");
  200. return -1;
  201. }
  202. count++;
  203. node = rb_next(node);
  204. }
  205. /*
  206. * Note that we have a entry collapsed in the other (idx = 1) hists.
  207. */
  208. if (idx == 0) {
  209. if (count_dummy != ARRAY_SIZE(fake_samples[1]) - 1) {
  210. pr_debug("Invalid count of dummy entries: %zd of %zd\n",
  211. count_dummy, ARRAY_SIZE(fake_samples[1]) - 1);
  212. return -1;
  213. }
  214. if (count != count_pair + ARRAY_SIZE(fake_samples[0])) {
  215. pr_debug("Invalid count of total leader entries: %zd of %zd\n",
  216. count, count_pair + ARRAY_SIZE(fake_samples[0]));
  217. return -1;
  218. }
  219. } else {
  220. if (count != count_pair) {
  221. pr_debug("Invalid count of total other entries: %zd of %zd\n",
  222. count, count_pair);
  223. return -1;
  224. }
  225. if (count_dummy > 0) {
  226. pr_debug("Other hists should not have dummy entries: %zd\n",
  227. count_dummy);
  228. return -1;
  229. }
  230. }
  231. return 0;
  232. }
  233. static int validate_link(struct hists *leader, struct hists *other)
  234. {
  235. return __validate_link(leader, 0) || __validate_link(other, 1);
  236. }
  237. int test__hists_link(void)
  238. {
  239. int err = -1;
  240. struct machines machines;
  241. struct machine *machine = NULL;
  242. struct perf_evsel *evsel, *first;
  243. struct perf_evlist *evlist = perf_evlist__new();
  244. if (evlist == NULL)
  245. return -ENOMEM;
  246. err = parse_events(evlist, "cpu-clock");
  247. if (err)
  248. goto out;
  249. err = parse_events(evlist, "task-clock");
  250. if (err)
  251. goto out;
  252. /* default sort order (comm,dso,sym) will be used */
  253. if (setup_sorting() < 0)
  254. goto out;
  255. machines__init(&machines);
  256. /* setup threads/dso/map/symbols also */
  257. machine = setup_fake_machine(&machines);
  258. if (!machine)
  259. goto out;
  260. if (verbose > 1)
  261. machine__fprintf(machine, stderr);
  262. /* process sample events */
  263. err = add_hist_entries(evlist, machine);
  264. if (err < 0)
  265. goto out;
  266. evlist__for_each(evlist, evsel) {
  267. hists__collapse_resort(&evsel->hists, NULL);
  268. if (verbose > 2)
  269. print_hists_in(&evsel->hists);
  270. }
  271. first = perf_evlist__first(evlist);
  272. evsel = perf_evlist__last(evlist);
  273. /* match common entries */
  274. hists__match(&first->hists, &evsel->hists);
  275. err = validate_match(&first->hists, &evsel->hists);
  276. if (err)
  277. goto out;
  278. /* link common and/or dummy entries */
  279. hists__link(&first->hists, &evsel->hists);
  280. err = validate_link(&first->hists, &evsel->hists);
  281. if (err)
  282. goto out;
  283. err = 0;
  284. out:
  285. /* tear down everything */
  286. perf_evlist__delete(evlist);
  287. reset_output_field();
  288. machines__exit(&machines);
  289. return err;
  290. }