|
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * |
|
3 * This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 #ifndef tmreader_h___ |
|
7 #define tmreader_h___ |
|
8 |
|
9 #include "plhash.h" |
|
10 #include "nsTraceMalloc.h" |
|
11 #include "plarena.h" |
|
12 |
|
13 #ifdef __cplusplus |
|
14 extern "C" { |
|
15 #endif |
|
16 |
|
17 typedef struct tmreader tmreader; |
|
18 typedef struct tmevent tmevent; |
|
19 typedef struct tmcounts tmcounts; |
|
20 typedef struct tmallcounts tmallcounts; |
|
21 typedef struct tmgraphlink tmgraphlink; |
|
22 typedef struct tmgraphedge tmgraphedge; |
|
23 typedef struct tmgraphnode tmgraphnode; |
|
24 typedef struct tmcallsite tmcallsite; |
|
25 typedef struct tmmethodnode tmmethodnode; |
|
26 |
|
27 struct tmevent { |
|
28 char type; |
|
29 uint32_t serial; |
|
30 union { |
|
31 char *libname; |
|
32 char *srcname; |
|
33 struct { |
|
34 uint32_t library; |
|
35 uint32_t filename; |
|
36 uint32_t linenumber; |
|
37 char *name; |
|
38 } method; |
|
39 struct { |
|
40 uint32_t parent; |
|
41 uint32_t method; |
|
42 uint32_t offset; |
|
43 } site; |
|
44 struct { |
|
45 uint32_t interval; /* in ticks */ |
|
46 uint32_t ptr; |
|
47 uint32_t size; |
|
48 uint32_t oldserial; |
|
49 uint32_t oldptr; |
|
50 uint32_t oldsize; |
|
51 uint32_t cost; /* in ticks */ |
|
52 } alloc; |
|
53 struct { |
|
54 nsTMStats tmstats; |
|
55 uint32_t calltree_maxkids_parent; |
|
56 uint32_t calltree_maxstack_top; |
|
57 } stats; |
|
58 } u; |
|
59 }; |
|
60 |
|
61 struct tmcounts { |
|
62 uint32_t direct; /* things allocated by this node's code */ |
|
63 uint32_t total; /* direct + things from all descendents */ |
|
64 }; |
|
65 |
|
66 struct tmallcounts { |
|
67 tmcounts bytes; |
|
68 tmcounts calls; |
|
69 }; |
|
70 |
|
71 struct tmgraphnode { |
|
72 PLHashEntry entry; /* key is serial or name, value must be name */ |
|
73 tmgraphlink *in; |
|
74 tmgraphlink *out; |
|
75 tmgraphnode *up; /* parent in supergraph, e.g., JS for JS_*() */ |
|
76 tmgraphnode *down; /* subgraph kids, declining bytes.total order */ |
|
77 tmgraphnode *next; /* next kid in supergraph node's down list */ |
|
78 int low; /* 0 or lowest current tree walk level */ |
|
79 tmallcounts allocs; |
|
80 tmallcounts frees; |
|
81 double sqsum; /* sum of squared bytes.direct */ |
|
82 int sort; /* sorted index in node table, -1 if no table */ |
|
83 }; |
|
84 |
|
85 struct tmmethodnode { |
|
86 tmgraphnode graphnode; |
|
87 char *sourcefile; |
|
88 uint32_t linenumber; |
|
89 }; |
|
90 |
|
91 #define tmgraphnode_name(node) ((char*) (node)->entry.value) |
|
92 #define tmmethodnode_name(node) ((char*) (node)->graphnode.entry.value) |
|
93 |
|
94 #define tmlibrary_serial(lib) ((uint32_t) (lib)->entry.key) |
|
95 #define tmcomponent_name(comp) ((const char*) (comp)->entry.key) |
|
96 #define filename_name(hashentry) ((char*)hashentry->value) |
|
97 |
|
98 /* Half a graphedge, not including per-edge allocation stats. */ |
|
99 struct tmgraphlink { |
|
100 tmgraphlink *next; /* next fanning out from or into a node */ |
|
101 tmgraphnode *node; /* the other node (to if OUT, from if IN) */ |
|
102 }; |
|
103 |
|
104 /* |
|
105 * It's safe to downcast a "from" tmgraphlink (one linked from a node's out |
|
106 * pointer) to tmgraphedge. To go from an "out" (linked via tmgraphedge.from) |
|
107 * or "in" (linked via tmgraphedge.to) list link to its containing edge, use |
|
108 * TM_LINK_TO_EDGE(link, which). |
|
109 */ |
|
110 struct tmgraphedge { |
|
111 tmgraphlink links[2]; |
|
112 tmallcounts allocs; |
|
113 tmallcounts frees; |
|
114 }; |
|
115 |
|
116 /* Indices into tmgraphedge.links -- out must come first. */ |
|
117 #define TM_EDGE_OUT_LINK 0 |
|
118 #define TM_EDGE_IN_LINK 1 |
|
119 |
|
120 #define TM_LINK_TO_EDGE(link,which) ((tmgraphedge*) &(link)[-(which)]) |
|
121 |
|
122 struct tmcallsite { |
|
123 PLHashEntry entry; /* key is site serial number */ |
|
124 tmcallsite *parent; /* calling site */ |
|
125 tmcallsite *siblings; /* other sites reached from parent */ |
|
126 tmcallsite *kids; /* sites reached from here */ |
|
127 tmmethodnode *method; /* method node in tmr->methods graph */ |
|
128 uint32_t offset; /* pc offset from start of method */ |
|
129 tmallcounts allocs; |
|
130 tmallcounts frees; |
|
131 void *data; /* tmreader clients can stick arbitrary |
|
132 * data onto a callsite. |
|
133 */ |
|
134 }; |
|
135 |
|
136 struct tmreader { |
|
137 const char *program; |
|
138 void *data; |
|
139 PLHashTable *libraries; |
|
140 PLHashTable *filenames; |
|
141 PLHashTable *components; |
|
142 PLHashTable *methods; |
|
143 PLHashTable *callsites; |
|
144 PLArenaPool arena; |
|
145 tmcallsite calltree_root; |
|
146 uint32_t ticksPerSec; |
|
147 }; |
|
148 |
|
149 typedef void (*tmeventhandler)(tmreader *tmr, tmevent *event); |
|
150 |
|
151 /* The tmreader constructor and destructor. */ |
|
152 extern tmreader *tmreader_new(const char *program, void *data); |
|
153 extern void tmreader_destroy(tmreader *tmr); |
|
154 |
|
155 /* |
|
156 * Return -1 on permanent fatal error, 0 if filename can't be opened or is not |
|
157 * a trace-malloc logfile, and 1 on success. |
|
158 */ |
|
159 extern int tmreader_eventloop(tmreader *tmr, const char *filename, |
|
160 tmeventhandler eventhandler); |
|
161 |
|
162 /* Map serial number or name to graphnode or callsite. */ |
|
163 extern tmgraphnode *tmreader_library(tmreader *tmr, uint32_t serial); |
|
164 extern tmgraphnode *tmreader_filename(tmreader *tmr, uint32_t serial); |
|
165 extern tmgraphnode *tmreader_component(tmreader *tmr, const char *name); |
|
166 extern tmmethodnode *tmreader_method(tmreader *tmr, uint32_t serial); |
|
167 extern tmcallsite *tmreader_callsite(tmreader *tmr, uint32_t serial); |
|
168 |
|
169 /* |
|
170 * Connect node 'from' to node 'to' with an edge, if there isn't one already |
|
171 * connecting the nodes. Add site's allocation stats to the edge only if we |
|
172 * create the edge, or if we find that it exists, but that to->low is zero or |
|
173 * less than from->low. |
|
174 * |
|
175 * If the callsite tree already totals allocation costs (tmcounts.total for |
|
176 * each site includes tmcounts.direct for that site, plus tmcounts.total for |
|
177 * all kid sites), then the node->low watermarks should be set from the tree |
|
178 * level when walking the callsite tree, and should be set to non-zero values |
|
179 * only if zero (the root is at level 0). A low watermark should be cleared |
|
180 * when the tree walk unwinds past the level at which it was set non-zero. |
|
181 * |
|
182 * Return 0 on error (malloc failure) and 1 on success. |
|
183 */ |
|
184 extern int tmgraphnode_connect(tmgraphnode *from, tmgraphnode *to, |
|
185 tmcallsite *site); |
|
186 |
|
187 #ifdef __cplusplus |
|
188 } |
|
189 #endif |
|
190 |
|
191 #endif /* tmreader_h___ */ |