hists_link.c 8.3 KB

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