hists_link.c 8.2 KB

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