hist.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. #include "hist.h"
  2. struct rb_root hist;
  3. struct rb_root collapse_hists;
  4. struct rb_root output_hists;
  5. int callchain;
  6. struct callchain_param callchain_param = {
  7. .mode = CHAIN_GRAPH_REL,
  8. .min_percent = 0.5
  9. };
  10. /*
  11. * histogram, sorted on item, collects counts
  12. */
  13. struct hist_entry *__hist_entry__add(struct thread *thread, struct map *map,
  14. struct symbol *sym,
  15. struct symbol *sym_parent,
  16. u64 ip, u64 count, char level, bool *hit)
  17. {
  18. struct rb_node **p = &hist.rb_node;
  19. struct rb_node *parent = NULL;
  20. struct hist_entry *he;
  21. struct hist_entry entry = {
  22. .thread = thread,
  23. .map = map,
  24. .sym = sym,
  25. .ip = ip,
  26. .level = level,
  27. .count = count,
  28. .parent = sym_parent,
  29. };
  30. int cmp;
  31. while (*p != NULL) {
  32. parent = *p;
  33. he = rb_entry(parent, struct hist_entry, rb_node);
  34. cmp = hist_entry__cmp(&entry, he);
  35. if (!cmp) {
  36. *hit = true;
  37. return he;
  38. }
  39. if (cmp < 0)
  40. p = &(*p)->rb_left;
  41. else
  42. p = &(*p)->rb_right;
  43. }
  44. he = malloc(sizeof(*he));
  45. if (!he)
  46. return NULL;
  47. *he = entry;
  48. rb_link_node(&he->rb_node, parent, p);
  49. rb_insert_color(&he->rb_node, &hist);
  50. *hit = false;
  51. return he;
  52. }
  53. int64_t
  54. hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
  55. {
  56. struct sort_entry *se;
  57. int64_t cmp = 0;
  58. list_for_each_entry(se, &hist_entry__sort_list, list) {
  59. cmp = se->cmp(left, right);
  60. if (cmp)
  61. break;
  62. }
  63. return cmp;
  64. }
  65. int64_t
  66. hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
  67. {
  68. struct sort_entry *se;
  69. int64_t cmp = 0;
  70. list_for_each_entry(se, &hist_entry__sort_list, list) {
  71. int64_t (*f)(struct hist_entry *, struct hist_entry *);
  72. f = se->collapse ?: se->cmp;
  73. cmp = f(left, right);
  74. if (cmp)
  75. break;
  76. }
  77. return cmp;
  78. }
  79. void hist_entry__free(struct hist_entry *he)
  80. {
  81. free(he);
  82. }
  83. /*
  84. * collapse the histogram
  85. */
  86. void collapse__insert_entry(struct hist_entry *he)
  87. {
  88. struct rb_node **p = &collapse_hists.rb_node;
  89. struct rb_node *parent = NULL;
  90. struct hist_entry *iter;
  91. int64_t cmp;
  92. while (*p != NULL) {
  93. parent = *p;
  94. iter = rb_entry(parent, struct hist_entry, rb_node);
  95. cmp = hist_entry__collapse(iter, he);
  96. if (!cmp) {
  97. iter->count += he->count;
  98. hist_entry__free(he);
  99. return;
  100. }
  101. if (cmp < 0)
  102. p = &(*p)->rb_left;
  103. else
  104. p = &(*p)->rb_right;
  105. }
  106. rb_link_node(&he->rb_node, parent, p);
  107. rb_insert_color(&he->rb_node, &collapse_hists);
  108. }
  109. void collapse__resort(void)
  110. {
  111. struct rb_node *next;
  112. struct hist_entry *n;
  113. if (!sort__need_collapse)
  114. return;
  115. next = rb_first(&hist);
  116. while (next) {
  117. n = rb_entry(next, struct hist_entry, rb_node);
  118. next = rb_next(&n->rb_node);
  119. rb_erase(&n->rb_node, &hist);
  120. collapse__insert_entry(n);
  121. }
  122. }
  123. /*
  124. * reverse the map, sort on count.
  125. */
  126. void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
  127. {
  128. struct rb_node **p = &output_hists.rb_node;
  129. struct rb_node *parent = NULL;
  130. struct hist_entry *iter;
  131. if (callchain)
  132. callchain_param.sort(&he->sorted_chain, &he->callchain,
  133. min_callchain_hits, &callchain_param);
  134. while (*p != NULL) {
  135. parent = *p;
  136. iter = rb_entry(parent, struct hist_entry, rb_node);
  137. if (he->count > iter->count)
  138. p = &(*p)->rb_left;
  139. else
  140. p = &(*p)->rb_right;
  141. }
  142. rb_link_node(&he->rb_node, parent, p);
  143. rb_insert_color(&he->rb_node, &output_hists);
  144. }
  145. void output__resort(u64 total_samples)
  146. {
  147. struct rb_node *next;
  148. struct hist_entry *n;
  149. struct rb_root *tree = &hist;
  150. u64 min_callchain_hits;
  151. min_callchain_hits =
  152. total_samples * (callchain_param.min_percent / 100);
  153. if (sort__need_collapse)
  154. tree = &collapse_hists;
  155. next = rb_first(tree);
  156. while (next) {
  157. n = rb_entry(next, struct hist_entry, rb_node);
  158. next = rb_next(&n->rb_node);
  159. rb_erase(&n->rb_node, tree);
  160. output__insert_entry(n, min_callchain_hits);
  161. }
  162. }