rb_resort.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. #ifndef _PERF_RESORT_RB_H_
  2. #define _PERF_RESORT_RB_H_
  3. /*
  4. * Template for creating a class to resort an existing rb_tree according to
  5. * a new sort criteria, that must be present in the entries of the source
  6. * rb_tree.
  7. *
  8. * (c) 2016 Arnaldo Carvalho de Melo <acme@redhat.com>
  9. *
  10. * Quick example, resorting threads by its shortname:
  11. *
  12. * First define the prefix (threads) to be used for the functions and data
  13. * structures created, and provide an expression for the sorting, then the
  14. * fields to be present in each of the entries in the new, sorted, rb_tree.
  15. *
  16. * The body of the init function should collect the fields, maybe
  17. * pre-calculating them from multiple entries in the original 'entry' from
  18. * the rb_tree used as a source for the entries to be sorted:
  19. DEFINE_RB_RESORT_RB(threads, strcmp(a->thread->shortname,
  20. b->thread->shortname) < 0,
  21. struct thread *thread;
  22. )
  23. {
  24. entry->thread = rb_entry(nd, struct thread, rb_node);
  25. }
  26. * After this it is just a matter of instantiating it and iterating it,
  27. * for a few data structures with existing rb_trees, such as 'struct machine',
  28. * helpers are available to get the rb_root and the nr_entries:
  29. DECLARE_RESORT_RB_MACHINE_THREADS(threads, machine_ptr);
  30. * This will instantiate the new rb_tree and a cursor for it, that can be used as:
  31. struct rb_node *nd;
  32. resort_rb__for_each_entry(nd, threads) {
  33. struct thread *t = threads_entry;
  34. printf("%s: %d\n", t->shortname, t->tid);
  35. }
  36. * Then delete it:
  37. resort_rb__delete(threads);
  38. * The name of the data structures and functions will have a _sorted suffix
  39. * right before the method names, i.e. will look like:
  40. *
  41. * struct threads_sorted_entry {}
  42. * threads_sorted__insert()
  43. */
  44. #define DEFINE_RESORT_RB(__name, __comp, ...) \
  45. struct __name##_sorted_entry { \
  46. struct rb_node rb_node; \
  47. __VA_ARGS__ \
  48. }; \
  49. static void __name##_sorted__init_entry(struct rb_node *nd, \
  50. struct __name##_sorted_entry *entry); \
  51. \
  52. static int __name##_sorted__cmp(struct rb_node *nda, struct rb_node *ndb) \
  53. { \
  54. struct __name##_sorted_entry *a, *b; \
  55. a = rb_entry(nda, struct __name##_sorted_entry, rb_node); \
  56. b = rb_entry(ndb, struct __name##_sorted_entry, rb_node); \
  57. return __comp; \
  58. } \
  59. \
  60. struct __name##_sorted { \
  61. struct rb_root entries; \
  62. struct __name##_sorted_entry nd[0]; \
  63. }; \
  64. \
  65. static void __name##_sorted__insert(struct __name##_sorted *sorted, \
  66. struct rb_node *sorted_nd) \
  67. { \
  68. struct rb_node **p = &sorted->entries.rb_node, *parent = NULL; \
  69. while (*p != NULL) { \
  70. parent = *p; \
  71. if (__name##_sorted__cmp(sorted_nd, parent)) \
  72. p = &(*p)->rb_left; \
  73. else \
  74. p = &(*p)->rb_right; \
  75. } \
  76. rb_link_node(sorted_nd, parent, p); \
  77. rb_insert_color(sorted_nd, &sorted->entries); \
  78. } \
  79. \
  80. static void __name##_sorted__sort(struct __name##_sorted *sorted, \
  81. struct rb_root *entries) \
  82. { \
  83. struct rb_node *nd; \
  84. unsigned int i = 0; \
  85. for (nd = rb_first(entries); nd; nd = rb_next(nd)) { \
  86. struct __name##_sorted_entry *snd = &sorted->nd[i++]; \
  87. __name##_sorted__init_entry(nd, snd); \
  88. __name##_sorted__insert(sorted, &snd->rb_node); \
  89. } \
  90. } \
  91. \
  92. static struct __name##_sorted *__name##_sorted__new(struct rb_root *entries, \
  93. int nr_entries) \
  94. { \
  95. struct __name##_sorted *sorted; \
  96. sorted = malloc(sizeof(*sorted) + sizeof(sorted->nd[0]) * nr_entries); \
  97. if (sorted) { \
  98. sorted->entries = RB_ROOT; \
  99. __name##_sorted__sort(sorted, entries); \
  100. } \
  101. return sorted; \
  102. } \
  103. \
  104. static void __name##_sorted__delete(struct __name##_sorted *sorted) \
  105. { \
  106. free(sorted); \
  107. } \
  108. \
  109. static void __name##_sorted__init_entry(struct rb_node *nd, \
  110. struct __name##_sorted_entry *entry)
  111. #define DECLARE_RESORT_RB(__name) \
  112. struct __name##_sorted_entry *__name##_entry; \
  113. struct __name##_sorted *__name = __name##_sorted__new
  114. #define resort_rb__for_each_entry(__nd, __name) \
  115. for (__nd = rb_first(&__name->entries); \
  116. __name##_entry = rb_entry(__nd, struct __name##_sorted_entry, \
  117. rb_node), __nd; \
  118. __nd = rb_next(__nd))
  119. #define resort_rb__delete(__name) \
  120. __name##_sorted__delete(__name), __name = NULL
  121. /*
  122. * Helpers for other classes that contains both an rbtree and the
  123. * number of entries in it:
  124. */
  125. /* For 'struct intlist' */
  126. #define DECLARE_RESORT_RB_INTLIST(__name, __ilist) \
  127. DECLARE_RESORT_RB(__name)(&__ilist->rblist.entries, \
  128. __ilist->rblist.nr_entries)
  129. /* For 'struct machine->threads' */
  130. #define DECLARE_RESORT_RB_MACHINE_THREADS(__name, __machine) \
  131. DECLARE_RESORT_RB(__name)(&__machine->threads, __machine->nr_threads)
  132. #endif /* _PERF_RESORT_RB_H_ */