hists_link.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  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. struct hists *hists = evsel__hists(evsel);
  72. for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) {
  73. const union perf_event event = {
  74. .header = {
  75. .misc = PERF_RECORD_MISC_USER,
  76. },
  77. };
  78. sample.pid = fake_common_samples[k].pid;
  79. sample.tid = fake_common_samples[k].pid;
  80. sample.ip = fake_common_samples[k].ip;
  81. if (perf_event__preprocess_sample(&event, machine, &al,
  82. &sample) < 0)
  83. goto out;
  84. he = __hists__add_entry(hists, &al, NULL,
  85. NULL, NULL, 1, 1, 0, true);
  86. if (he == NULL)
  87. goto out;
  88. fake_common_samples[k].thread = al.thread;
  89. fake_common_samples[k].map = al.map;
  90. fake_common_samples[k].sym = al.sym;
  91. }
  92. for (k = 0; k < ARRAY_SIZE(fake_samples[i]); k++) {
  93. const union perf_event event = {
  94. .header = {
  95. .misc = PERF_RECORD_MISC_USER,
  96. },
  97. };
  98. sample.pid = fake_samples[i][k].pid;
  99. sample.tid = fake_samples[i][k].pid;
  100. sample.ip = fake_samples[i][k].ip;
  101. if (perf_event__preprocess_sample(&event, machine, &al,
  102. &sample) < 0)
  103. goto out;
  104. he = __hists__add_entry(hists, &al, NULL,
  105. NULL, NULL, 1, 1, 0, true);
  106. if (he == NULL)
  107. goto out;
  108. fake_samples[i][k].thread = al.thread;
  109. fake_samples[i][k].map = al.map;
  110. fake_samples[i][k].sym = al.sym;
  111. }
  112. i++;
  113. }
  114. return 0;
  115. out:
  116. pr_debug("Not enough memory for adding a hist entry\n");
  117. return -1;
  118. }
  119. static int find_sample(struct sample *samples, size_t nr_samples,
  120. struct thread *t, struct map *m, struct symbol *s)
  121. {
  122. while (nr_samples--) {
  123. if (samples->thread == t && samples->map == m &&
  124. samples->sym == s)
  125. return 1;
  126. samples++;
  127. }
  128. return 0;
  129. }
  130. static int __validate_match(struct hists *hists)
  131. {
  132. size_t count = 0;
  133. struct rb_root *root;
  134. struct rb_node *node;
  135. /*
  136. * Only entries from fake_common_samples should have a pair.
  137. */
  138. if (sort__need_collapse)
  139. root = &hists->entries_collapsed;
  140. else
  141. root = hists->entries_in;
  142. node = rb_first(root);
  143. while (node) {
  144. struct hist_entry *he;
  145. he = rb_entry(node, struct hist_entry, rb_node_in);
  146. if (hist_entry__has_pairs(he)) {
  147. if (find_sample(fake_common_samples,
  148. ARRAY_SIZE(fake_common_samples),
  149. he->thread, he->ms.map, he->ms.sym)) {
  150. count++;
  151. } else {
  152. pr_debug("Can't find the matched entry\n");
  153. return -1;
  154. }
  155. }
  156. node = rb_next(node);
  157. }
  158. if (count != ARRAY_SIZE(fake_common_samples)) {
  159. pr_debug("Invalid count for matched entries: %zd of %zd\n",
  160. count, ARRAY_SIZE(fake_common_samples));
  161. return -1;
  162. }
  163. return 0;
  164. }
  165. static int validate_match(struct hists *leader, struct hists *other)
  166. {
  167. return __validate_match(leader) || __validate_match(other);
  168. }
  169. static int __validate_link(struct hists *hists, int idx)
  170. {
  171. size_t count = 0;
  172. size_t count_pair = 0;
  173. size_t count_dummy = 0;
  174. struct rb_root *root;
  175. struct rb_node *node;
  176. /*
  177. * Leader hists (idx = 0) will have dummy entries from other,
  178. * and some entries will have no pair. However every entry
  179. * in other hists should have (dummy) pair.
  180. */
  181. if (sort__need_collapse)
  182. root = &hists->entries_collapsed;
  183. else
  184. root = hists->entries_in;
  185. node = rb_first(root);
  186. while (node) {
  187. struct hist_entry *he;
  188. he = rb_entry(node, struct hist_entry, rb_node_in);
  189. if (hist_entry__has_pairs(he)) {
  190. if (!find_sample(fake_common_samples,
  191. ARRAY_SIZE(fake_common_samples),
  192. he->thread, he->ms.map, he->ms.sym) &&
  193. !find_sample(fake_samples[idx],
  194. ARRAY_SIZE(fake_samples[idx]),
  195. he->thread, he->ms.map, he->ms.sym)) {
  196. count_dummy++;
  197. }
  198. count_pair++;
  199. } else if (idx) {
  200. pr_debug("A entry from the other hists should have pair\n");
  201. return -1;
  202. }
  203. count++;
  204. node = rb_next(node);
  205. }
  206. /*
  207. * Note that we have a entry collapsed in the other (idx = 1) hists.
  208. */
  209. if (idx == 0) {
  210. if (count_dummy != ARRAY_SIZE(fake_samples[1]) - 1) {
  211. pr_debug("Invalid count of dummy entries: %zd of %zd\n",
  212. count_dummy, ARRAY_SIZE(fake_samples[1]) - 1);
  213. return -1;
  214. }
  215. if (count != count_pair + ARRAY_SIZE(fake_samples[0])) {
  216. pr_debug("Invalid count of total leader entries: %zd of %zd\n",
  217. count, count_pair + ARRAY_SIZE(fake_samples[0]));
  218. return -1;
  219. }
  220. } else {
  221. if (count != count_pair) {
  222. pr_debug("Invalid count of total other entries: %zd of %zd\n",
  223. count, count_pair);
  224. return -1;
  225. }
  226. if (count_dummy > 0) {
  227. pr_debug("Other hists should not have dummy entries: %zd\n",
  228. count_dummy);
  229. return -1;
  230. }
  231. }
  232. return 0;
  233. }
  234. static int validate_link(struct hists *leader, struct hists *other)
  235. {
  236. return __validate_link(leader, 0) || __validate_link(other, 1);
  237. }
  238. int test__hists_link(void)
  239. {
  240. int err = -1;
  241. struct hists *hists, *first_hists;
  242. struct machines machines;
  243. struct machine *machine = NULL;
  244. struct perf_evsel *evsel, *first;
  245. struct perf_evlist *evlist = perf_evlist__new();
  246. if (evlist == NULL)
  247. return -ENOMEM;
  248. err = parse_events(evlist, "cpu-clock");
  249. if (err)
  250. goto out;
  251. err = parse_events(evlist, "task-clock");
  252. if (err)
  253. goto out;
  254. /* default sort order (comm,dso,sym) will be used */
  255. if (setup_sorting() < 0)
  256. goto out;
  257. machines__init(&machines);
  258. /* setup threads/dso/map/symbols also */
  259. machine = setup_fake_machine(&machines);
  260. if (!machine)
  261. goto out;
  262. if (verbose > 1)
  263. machine__fprintf(machine, stderr);
  264. /* process sample events */
  265. err = add_hist_entries(evlist, machine);
  266. if (err < 0)
  267. goto out;
  268. evlist__for_each(evlist, evsel) {
  269. hists = evsel__hists(evsel);
  270. hists__collapse_resort(hists, NULL);
  271. if (verbose > 2)
  272. print_hists_in(hists);
  273. }
  274. first = perf_evlist__first(evlist);
  275. evsel = perf_evlist__last(evlist);
  276. first_hists = evsel__hists(first);
  277. hists = evsel__hists(evsel);
  278. /* match common entries */
  279. hists__match(first_hists, hists);
  280. err = validate_match(first_hists, hists);
  281. if (err)
  282. goto out;
  283. /* link common and/or dummy entries */
  284. hists__link(first_hists, hists);
  285. err = validate_link(first_hists, hists);
  286. if (err)
  287. goto out;
  288. err = 0;
  289. out:
  290. /* tear down everything */
  291. perf_evlist__delete(evlist);
  292. reset_output_field();
  293. machines__exit(&machines);
  294. return err;
  295. }