Home | History | Annotate | Download | only in util
      1 #ifndef __PERF_CALLCHAIN_H
      2 #define __PERF_CALLCHAIN_H
      3 
      4 #include "../perf.h"
      5 /* ANDROID_CHANGE_BEGIN */
      6 #if 0
      7 #include <linux/list.h>
      8 #include <linux/rbtree.h>
      9 #else
     10 #include "include/linux/list.h"
     11 #include "include/linux/rbtree.h"
     12 #endif
     13 /* ANDROID_CHANGE_END */
     14 #include "event.h"
     15 #include "symbol.h"
     16 
     17 enum chain_mode {
     18 	CHAIN_NONE,
     19 	CHAIN_FLAT,
     20 	CHAIN_GRAPH_ABS,
     21 	CHAIN_GRAPH_REL
     22 };
     23 
     24 struct callchain_node {
     25 	struct callchain_node	*parent;
     26 	struct list_head	siblings;
     27 	struct list_head	children;
     28 	struct list_head	val;
     29 	struct rb_node		rb_node; /* to sort nodes in an rbtree */
     30 	struct rb_root		rb_root; /* sorted tree of children */
     31 	unsigned int		val_nr;
     32 	u64			hit;
     33 	u64			children_hit;
     34 };
     35 
     36 struct callchain_root {
     37 	u64			max_depth;
     38 	struct callchain_node	node;
     39 };
     40 
     41 struct callchain_param;
     42 
     43 typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_root *,
     44 				 u64, struct callchain_param *);
     45 
     46 struct callchain_param {
     47 	enum chain_mode 	mode;
     48 	u32			print_limit;
     49 	double			min_percent;
     50 	sort_chain_func_t	sort;
     51 };
     52 
     53 struct callchain_list {
     54 	u64			ip;
     55 	struct map_symbol	ms;
     56 	struct list_head	list;
     57 };
     58 
     59 /*
     60  * A callchain cursor is a single linked list that
     61  * let one feed a callchain progressively.
     62  * It keeps persitent allocated entries to minimize
     63  * allocations.
     64  */
     65 struct callchain_cursor_node {
     66 	u64				ip;
     67 	struct map			*map;
     68 	struct symbol			*sym;
     69 	struct callchain_cursor_node	*next;
     70 };
     71 
     72 struct callchain_cursor {
     73 	u64				nr;
     74 	struct callchain_cursor_node	*first;
     75 	struct callchain_cursor_node	**last;
     76 	u64				pos;
     77 	struct callchain_cursor_node	*curr;
     78 };
     79 
     80 static inline void callchain_init(struct callchain_root *root)
     81 {
     82 	INIT_LIST_HEAD(&root->node.siblings);
     83 	INIT_LIST_HEAD(&root->node.children);
     84 	INIT_LIST_HEAD(&root->node.val);
     85 
     86 	root->node.parent = NULL;
     87 	root->node.hit = 0;
     88 	root->node.children_hit = 0;
     89 	root->max_depth = 0;
     90 }
     91 
     92 static inline u64 callchain_cumul_hits(struct callchain_node *node)
     93 {
     94 	return node->hit + node->children_hit;
     95 }
     96 
     97 int callchain_register_param(struct callchain_param *param);
     98 int callchain_append(struct callchain_root *root,
     99 		     struct callchain_cursor *cursor,
    100 		     u64 period);
    101 
    102 int callchain_merge(struct callchain_cursor *cursor,
    103 		    struct callchain_root *dst, struct callchain_root *src);
    104 
    105 bool ip_callchain__valid(struct ip_callchain *chain,
    106 			 const union perf_event *event);
    107 /*
    108  * Initialize a cursor before adding entries inside, but keep
    109  * the previously allocated entries as a cache.
    110  */
    111 static inline void callchain_cursor_reset(struct callchain_cursor *cursor)
    112 {
    113 	cursor->nr = 0;
    114 	cursor->last = &cursor->first;
    115 }
    116 
    117 int callchain_cursor_append(struct callchain_cursor *cursor, u64 ip,
    118 			    struct map *map, struct symbol *sym);
    119 
    120 /* Close a cursor writing session. Initialize for the reader */
    121 static inline void callchain_cursor_commit(struct callchain_cursor *cursor)
    122 {
    123 	cursor->curr = cursor->first;
    124 	cursor->pos = 0;
    125 }
    126 
    127 /* Cursor reading iteration helpers */
    128 static inline struct callchain_cursor_node *
    129 callchain_cursor_current(struct callchain_cursor *cursor)
    130 {
    131 	if (cursor->pos == cursor->nr)
    132 		return NULL;
    133 
    134 	return cursor->curr;
    135 }
    136 
    137 static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
    138 {
    139 	cursor->curr = cursor->curr->next;
    140 	cursor->pos++;
    141 }
    142 #endif	/* __PERF_CALLCHAIN_H */
    143