callchain.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /*
  2. * Copyright (C) 2009, Frederic Weisbecker <fweisbec@gmail.com>
  3. *
  4. * Handle the callchains from the stream in an ad-hoc radix tree and then
  5. * sort them in an rbtree.
  6. *
  7. */
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <stdbool.h>
  11. #include <errno.h>
  12. #include "callchain.h"
  13. static void rb_insert_callchain(struct rb_root *root, struct callchain_node *chain)
  14. {
  15. struct rb_node **p = &root->rb_node;
  16. struct rb_node *parent = NULL;
  17. struct callchain_node *rnode;
  18. while (*p) {
  19. parent = *p;
  20. rnode = rb_entry(parent, struct callchain_node, rb_node);
  21. if (rnode->hit < chain->hit)
  22. p = &(*p)->rb_left;
  23. else
  24. p = &(*p)->rb_right;
  25. }
  26. rb_link_node(&chain->rb_node, parent, p);
  27. rb_insert_color(&chain->rb_node, root);
  28. }
  29. /*
  30. * Once we get every callchains from the stream, we can now
  31. * sort them by hit
  32. */
  33. void sort_chain_to_rbtree(struct rb_root *rb_root, struct callchain_node *node)
  34. {
  35. struct callchain_node *child;
  36. list_for_each_entry(child, &node->children, brothers)
  37. sort_chain_to_rbtree(rb_root, child);
  38. if (node->hit)
  39. rb_insert_callchain(rb_root, node);
  40. }
  41. static struct callchain_node *create_child(struct callchain_node *parent)
  42. {
  43. struct callchain_node *new;
  44. new = malloc(sizeof(*new));
  45. if (!new) {
  46. perror("not enough memory to create child for code path tree");
  47. return NULL;
  48. }
  49. new->parent = parent;
  50. INIT_LIST_HEAD(&new->children);
  51. INIT_LIST_HEAD(&new->val);
  52. list_add_tail(&new->brothers, &parent->children);
  53. return new;
  54. }
  55. static void
  56. fill_node(struct callchain_node *node, struct ip_callchain *chain, int start)
  57. {
  58. int i;
  59. for (i = start; i < chain->nr; i++) {
  60. struct callchain_list *call;
  61. call = malloc(sizeof(*chain));
  62. if (!call) {
  63. perror("not enough memory for the code path tree");
  64. return;
  65. }
  66. call->ip = chain->ips[i];
  67. list_add_tail(&call->list, &node->val);
  68. }
  69. node->val_nr = i - start;
  70. }
  71. static void add_child(struct callchain_node *parent, struct ip_callchain *chain)
  72. {
  73. struct callchain_node *new;
  74. new = create_child(parent);
  75. fill_node(new, chain, parent->val_nr);
  76. new->hit = 1;
  77. }
  78. static void
  79. split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
  80. struct callchain_list *to_split, int idx)
  81. {
  82. struct callchain_node *new;
  83. /* split */
  84. new = create_child(parent);
  85. list_move_tail(&to_split->list, &new->val);
  86. new->hit = parent->hit;
  87. parent->hit = 0;
  88. parent->val_nr = idx;
  89. /* create the new one */
  90. add_child(parent, chain);
  91. }
  92. static int
  93. __append_chain(struct callchain_node *root, struct ip_callchain *chain,
  94. int start);
  95. static int
  96. __append_chain_children(struct callchain_node *root, struct ip_callchain *chain)
  97. {
  98. struct callchain_node *rnode;
  99. /* lookup in childrens */
  100. list_for_each_entry(rnode, &root->children, brothers) {
  101. int ret = __append_chain(rnode, chain, root->val_nr);
  102. if (!ret)
  103. return 0;
  104. }
  105. return -1;
  106. }
  107. static int
  108. __append_chain(struct callchain_node *root, struct ip_callchain *chain,
  109. int start)
  110. {
  111. struct callchain_list *cnode;
  112. int i = start;
  113. bool found = false;
  114. /* lookup in the current node */
  115. list_for_each_entry(cnode, &root->val, list) {
  116. if (cnode->ip != chain->ips[i++])
  117. break;
  118. if (!found)
  119. found = true;
  120. if (i == chain->nr)
  121. break;
  122. }
  123. /* matches not, relay on the parent */
  124. if (!found)
  125. return -1;
  126. /* we match only a part of the node. Split it and add the new chain */
  127. if (i < root->val_nr) {
  128. split_add_child(root, chain, cnode, i);
  129. return 0;
  130. }
  131. /* we match 100% of the path, increment the hit */
  132. if (i == root->val_nr) {
  133. root->hit++;
  134. return 0;
  135. }
  136. return __append_chain_children(root, chain);
  137. }
  138. void append_chain(struct callchain_node *root, struct ip_callchain *chain)
  139. {
  140. if (__append_chain_children(root, chain) == -1)
  141. add_child(root, chain);
  142. }