48f6f3c2 |
1 | /* The countEvents module accumulates data for various basic reports |
2 | |
3 | Not only does it count the events for each event type, it also tracks |
4 | the current state (current process and user/system mode) in order to |
5 | categorize accordingly the event counts. */ |
6 | |
7 | void init(int argc, char **argv) |
8 | { |
9 | lttv_attributes *a; |
10 | lttv_hooks *before, *after; |
11 | |
12 | a = lttv_global_attributes(); |
13 | before = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, |
14 | "hooks/trace_set/before"); |
15 | after = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, |
16 | "hooks/trace_set/after"); |
17 | lttv_hooks_add(before, countEvents_trace_set_before, NULL); |
18 | lttv_hooks_add(after, countEvents_trace_set_after, NULL); |
19 | } |
20 | |
21 | |
22 | void destroy() |
23 | { |
24 | lttv_attributes *a; |
25 | lttv_hooks *before, *after; |
26 | |
27 | a = lttv_global_attributes(); |
28 | before = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, |
29 | "hooks/trace_set/before"); |
30 | after = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, |
31 | "hooks/trace_set/after"); |
32 | lttv_hooks_remove(before, countEvents_trace_set_before, NULL); |
33 | lttv_hooks_remove(after, countEvents_trace_set_after, NULL); |
34 | } |
35 | |
36 | |
37 | /* Insert the hooks before and after each trace and tracefile */ |
38 | |
39 | typedef struct _trace_context { |
40 | unsigned nb_cpu; |
41 | struct cpu_context *cpus; |
42 | lttv_attributes *processes; |
43 | lttv_key *key; |
44 | lttv_attributes *event_counts; |
45 | lttv_attributes *trace_attributes; |
46 | } trace_context; |
47 | |
48 | static bool countEvents_trace_set_before(void *hook_data, void *call_data) |
49 | { |
50 | int i, j, nb, nbtf; |
51 | lttv_trace_set *s; |
52 | lttv_attributes *a; |
53 | trace_context *c; |
54 | |
55 | s = (lttv_trace_set *)call_data; |
56 | |
57 | /* For each trace prepare the contexts and insert the hooks */ |
58 | |
59 | nb = lttv_trace_set_number(s); |
60 | for(i = 0 ; i < nb ; i++) { |
61 | c = g_new(trace_context); |
62 | a = lttv_trace_set_trace_attributes(s, i); |
63 | |
64 | if(lttv_attributes_get_pointer_pathname(a, "countEvents/context") != NULL){ |
65 | g_error("Recursive call to TextDump"); |
66 | } |
67 | |
68 | lttv_attributes_set_pointer_pathname(a, "countEvents/context", c); |
69 | |
70 | h = lttv_attributes_get_hooks(a, "hooks/before"); |
71 | lttv_hooks_add(h, countEvents_trace_before, c); |
72 | h = lttv_attributes_get_hooks(a, "hooks/after"); |
73 | lttv_hooks_add(h, countEvents_trace_after, c); |
74 | h = lttv_attributes_get_hooks(a, "hooks/tacefile/before"); |
75 | lttv_hooks_add(h, countEvents_tracefile_before, c); |
76 | h = lttv_attributes_get_hooks(a, "hooks/tracefile/after"); |
77 | lttv_hooks_add(h, countEvents_tracefile_after, c); |
78 | h = lttv_attributes_get_hooks(a, "hooks/event/selected"); |
79 | lttv_hooks_add(h, couneEvents_event, c); |
80 | } |
81 | |
82 | return TRUE; |
83 | } |
84 | |
85 | |
86 | /* Remove the hooks before and after each trace and tracefile, and for each |
87 | event. Print trace set level statistics. */ |
88 | |
89 | static bool countEvents_trace_set_after(void *hook_data, void *call_data) |
90 | { |
91 | int i, j, nb, nbtf; |
92 | lttv_trace_set *s; |
93 | lttv_attributes *a; |
94 | trace_context *c; |
95 | |
96 | s = (lttv_trace_set *)call_data; |
97 | |
98 | /* Get the file pointer */ |
99 | |
100 | fp = (FILE *)lttv_attributes_get_pointer_pathname(ga, "textDump/file"); |
101 | |
102 | /* For each trace remove the hooks */ |
103 | |
104 | nb = lttv_trace_set_number(s); |
105 | for(i = 0 ; i < nb ; i++) { |
106 | a = lttv_trace_set_trace_attributes(s, i); |
107 | c = (trace_context *)lttv_attributes_get_pointer_pathname(a, |
108 | "textDump/context"); |
109 | lttv_attributes_set_pointer_pathname(a, "textDump/context", NULL); |
110 | |
111 | h = lttv_attributes_get_hooks(a, "hooks/before"); |
112 | lttv_hooks_remove(h, countEvents_trace_before, c); |
113 | h = lttv_attributes_get_hooks(a, "hooks/after"); |
114 | lttv_hooks_remove(h, countEvents_trace_after, c); |
115 | h = lttv_attributes_get_hooks(a, "hooks/tacefile/before"); |
116 | lttv_hooks_remove(h, countEvents_tracefile_before, c); |
117 | h = lttv_attributes_get_hooks(a, "hooks/tracefile/after"); |
118 | lttv_hooks_remove(h, countEvents_tracefile_after, c); |
119 | h = lttv_attributes_get_hooks(a, "hooks/event/selected"); |
120 | lttv_hooks_remove(h, countEvents_event, c); |
121 | g_free(c); |
122 | } |
123 | |
124 | /* Compute statistics for the complete trace set */ |
125 | |
126 | return TRUE; |
127 | } |
128 | |
129 | |
130 | static bool countEvents_trace_before(void *hook_data, void *call_data) |
131 | { |
132 | ltt_trace *t; |
133 | trace_context *c; |
134 | |
135 | c = (trace_context *)hook_data; |
136 | t = (ltt_trace *)call_data; |
137 | |
138 | /* Initialize the context */ |
139 | |
140 | return TRUE; |
141 | } |
142 | |
143 | |
144 | /* Print trace level statistics */ |
145 | |
146 | static bool countEvents_trace_after(void *hook_data, void *call_data) |
147 | { |
148 | ltt_trace *t; |
149 | trace_context *c; |
150 | |
151 | c = (trace_context *)hook_data; |
152 | t = (ltt_trace *)call_data; |
153 | |
154 | /* Sum events in different ways for the whole trace */ |
155 | |
156 | return TRUE; |
157 | } |
158 | |
159 | |
160 | static bool countEvents_tracefile_before(void *hook_data, void *call_data) |
161 | { |
162 | ltt_tracefile *tf; |
163 | trace_context *c; |
164 | |
165 | c = (trace_context *)hook_data; |
166 | tf = (ltt_tracefile *)call_data; |
167 | |
168 | /* Nothing special to do for now */ |
169 | |
170 | return TRUE; |
171 | } |
172 | |
173 | |
174 | static bool countEvents_tracefile_after(void *hook_data, void *call_data) |
175 | { |
176 | ltt_tracefile *tf; |
177 | trace_context *c; |
178 | |
179 | c = (trace_context *)hook_data; |
180 | tf = (ltt_tracefile *)call_data; |
181 | |
182 | /* Nothing special to do for now */ |
183 | |
184 | return TRUE; |
185 | } |
186 | |
187 | |
188 | static bool countEvents_event(void *hook_data, void *call_data) |
189 | { |
190 | ltt_event *e; |
191 | trace_context *c; |
192 | unsigned cpu; |
193 | unsigned eventtype; |
194 | ltt_time t; |
195 | |
196 | e = (ltt_event *)call_data; |
197 | c = (event_context *)hook_data; |
198 | |
199 | eventtype = ltt_event_eventtype_id(e); |
200 | cpu = ltt_event_cpu_id(e); |
201 | time = ltt_event_time(e); |
202 | |
203 | /* Accumulate the CPU time spent in that state */ |
204 | |
205 | key = c->cpu[cpu].key; |
206 | last_time = c->cpu[cpu].last_time; |
207 | c->cpu[cpu].last_time; = time; |
208 | lttv_key_index(key,LTTV_KEY_TYPE) = KEY_CPU; |
209 | total_time = lttv_attributes_time_get(c->main_attributes, key); |
210 | |
211 | lttv_sub_time_value(delta_time, last_time, time); |
212 | lttv_add_time_valie(*total_time, *total_time, delta_time); |
213 | |
214 | /* Some events indicate a state change to remember (syscall goes from user to |
215 | system mode, open assigns a new file to a file descriptor, exec changes |
216 | the memory map for the text section...) or have additional statistics |
217 | gathered. */ |
218 | |
219 | switch(c->eventtype_class[eventtype]) { |
220 | |
221 | case LTTV_EVENT_SYSCALL_ENTRY: |
222 | n = ltt_event_get_unsigned(e,c->syscall_field) |
223 | push_state(c, cpu, KEY_SYSCALL, n, time); |
224 | /* For page faults it may be interesting to note waiting on which file */ |
225 | break; |
226 | |
227 | case LTTV_EVENT_SYSCALL_EXIT: |
228 | pop_state(c->cpu, cpu, KEY_SYSCALL, time); |
229 | break; |
230 | |
231 | case LTTV_EVENT_TRAP_ENTRY: |
232 | n = ltt_event_get_unsigned(e,c->trap_field) |
233 | push_state(c, cpu, KEY_TRAP, n, time); |
234 | break; |
235 | |
236 | case LTTV_EVENT_TRAP_EXIT: |
237 | pop_state(c->cpu, cpu, KEY_TRAP, time); |
238 | break; |
239 | |
240 | case LTTV_EVENT_IRQ_ENTRY: |
241 | n = ltt_event_get_unsigned(e,c->irq_field) |
242 | push_state(c, cpu, KEY_IRQ, n, time); |
243 | break; |
244 | |
245 | case LTTV_EVENT_IRQ_EXIT: |
246 | pop_state(c->cpu, cpu, KEY_IRQ, time); |
247 | break; |
248 | |
249 | |
250 | default: |
251 | } |
252 | |
253 | /* The key already specifies the host, cpu, process and state, add the |
254 | event type and simply count one for the current event. */ |
255 | |
256 | lttv_key_index(key,LTTV_KEY_TYPE) = c->eventtype_key[eventtype]; |
257 | count = lttv_attributes_get_integer(c->main_attributes, key); |
258 | (*count)++; |
259 | |
260 | return TRUE; |
261 | } |