Commit | Line | Data |
---|---|---|
5d10d135 ASL |
1 | /******************************************************************************* |
2 | * Copyright (c) 2009 Ericsson | |
3 | * | |
4 | * All rights reserved. This program and the accompanying materials are | |
5 | * made available under the terms of the Eclipse Public License v1.0 which | |
6 | * accompanies this distribution, and is available at | |
7 | * http://www.eclipse.org/legal/epl-v10.html | |
8 | * | |
9 | * Contributors: | |
10 | * Alvaro Sanchez-Leon (alvsan09@gmail.com) - Initial API and implementation | |
11 | *******************************************************************************/ | |
12 | package org.eclipse.linuxtools.lttng.state.evProcessor.state; | |
13 | ||
58c60db3 | 14 | import java.util.List; |
5d10d135 ASL |
15 | |
16 | import org.eclipse.linuxtools.lttng.TraceDebug; | |
17 | import org.eclipse.linuxtools.lttng.event.LttngEvent; | |
58c60db3 | 18 | import org.eclipse.linuxtools.lttng.event.LttngEventField; |
5d10d135 | 19 | import org.eclipse.linuxtools.lttng.state.StateStrings; |
58c60db3 | 20 | import org.eclipse.linuxtools.lttng.state.StateStrings.Fields; |
5d10d135 ASL |
21 | import org.eclipse.linuxtools.lttng.state.StateStrings.IRQMode; |
22 | import org.eclipse.linuxtools.lttng.state.StateStrings.ProcessStatus; | |
88144d4a | 23 | import org.eclipse.linuxtools.lttng.state.evProcessor.IEventProcessing; |
5d10d135 ASL |
24 | import org.eclipse.linuxtools.lttng.state.model.LTTngCPUState; |
25 | import org.eclipse.linuxtools.lttng.state.model.LttngBdevState; | |
26 | import org.eclipse.linuxtools.lttng.state.model.LttngExecutionState; | |
27 | import org.eclipse.linuxtools.lttng.state.model.LttngIRQState; | |
28 | import org.eclipse.linuxtools.lttng.state.model.LttngProcessState; | |
29 | import org.eclipse.linuxtools.lttng.state.model.LttngTraceState; | |
58c60db3 | 30 | import org.eclipse.linuxtools.tmf.event.TmfEventField; |
5d10d135 ASL |
31 | import org.eclipse.linuxtools.tmf.event.TmfTimestamp; |
32 | ||
58c60db3 | 33 | public abstract class AbsStateUpdate implements IEventProcessing { |
5d10d135 ASL |
34 | |
35 | // ======================================================================== | |
36 | // Data | |
37 | // ======================================================================= | |
38 | protected static final Long ANY_CPU = 0L; | |
39 | ||
40 | // ======================================================================== | |
41 | // push and pop from stack | |
42 | // ======================================================================= | |
43 | protected void push_state(Long cpu, StateStrings.ExecutionMode execMode, | |
44 | String submode, TmfTimestamp eventTime, LttngTraceState traceSt) { | |
45 | ||
46 | LttngProcessState process = traceSt.getRunning_process().get(cpu); | |
47 | LttngExecutionState exe_state = new LttngExecutionState(); | |
48 | exe_state.setExec_mode(execMode); | |
49 | exe_state.setExec_submode(submode); | |
58c60db3 FC |
50 | exe_state.setEntry_Time(eventTime); |
51 | exe_state.setChange_Time(eventTime); | |
5d10d135 | 52 | exe_state.setCum_cpu_time(0L); |
88144d4a | 53 | exe_state.setProc_status(process.getState().getProc_status()); |
58c60db3 | 54 | process.setState(exe_state); |
5d10d135 ASL |
55 | process.pushToExecutionStack(exe_state); |
56 | } | |
57 | ||
58 | protected void pop_state(Long cpu, StateStrings.ExecutionMode execMode, | |
59 | LttngTraceState traceSt, TmfTimestamp eventTime) { | |
60 | ||
61 | LttngProcessState process = traceSt.getRunning_process().get(cpu); | |
62 | ||
63 | if (!process.getState().getExec_mode().equals(execMode)) { | |
64 | // Different execution mode | |
65 | TraceDebug.debug("Different Execution Mode type \n\tTime:" | |
66 | + eventTime.toString() + "\n\tprocess state has: \n\t" | |
67 | + process.getState().getExec_mode().toString() | |
68 | + "\n\twhen pop_int is:\n\t" + execMode.toString()); | |
69 | return; | |
70 | } | |
71 | ||
5d10d135 | 72 | process.popFromExecutionStack(); |
58c60db3 FC |
73 | process.setState(process.peekFromExecutionStack()); |
74 | process.getState().setChange_Time(eventTime); | |
5d10d135 ASL |
75 | } |
76 | ||
77 | protected void irq_push_mode(LttngIRQState irqst, IRQMode state) { | |
78 | irqst.pushToIrqStack(state); | |
79 | } | |
80 | ||
81 | protected void irq_set_base_mode(LttngIRQState irqst, IRQMode state) { | |
82 | irqst.clearAndSetBaseToIrqStack(state); | |
83 | } | |
84 | ||
85 | protected void irq_pop_mode(LttngIRQState irqst) { | |
86 | irqst.popFromIrqStack(); | |
87 | } | |
88 | ||
89 | protected void cpu_push_mode(LTTngCPUState cpust, StateStrings.CpuMode state) { | |
90 | // The initialization (init) creates a LttngCPUState instance per | |
91 | // available cpu in the system | |
92 | cpust.pushToCpuStack(state); | |
93 | } | |
94 | ||
95 | protected void cpu_pop_mode(LTTngCPUState cpust) { | |
96 | cpust.popFromCpuStack(); | |
97 | } | |
98 | ||
99 | /* clears the stack and sets the state passed as argument */ | |
100 | protected void cpu_set_base_mode(LTTngCPUState cpust, | |
101 | StateStrings.CpuMode state) { | |
102 | cpust.clearAndSetBaseToCpuStack(state); | |
103 | } | |
104 | ||
105 | protected void bdev_pop_mode(LttngBdevState bdevst) { | |
106 | bdevst.popFromBdevStack(); | |
107 | } | |
108 | ||
109 | /** | |
110 | * Push a new received function pointer to the user_stack | |
111 | * | |
112 | * @param traceSt | |
113 | * @param funcptr | |
114 | * @param cpu | |
115 | */ | |
116 | protected void push_function(LttngTraceState traceSt, Long funcptr, Long cpu) { | |
117 | // Get the related process | |
118 | LttngProcessState process = traceSt.getRunning_process().get(cpu); | |
119 | ||
120 | // update stack | |
121 | process.pushToUserStack(funcptr); | |
122 | ||
123 | // update the pointer to the current function on the corresponding | |
124 | // process | |
125 | process.setCurrent_function(funcptr); | |
126 | } | |
127 | ||
128 | protected void pop_function(LttngTraceState traceSt, LttngEvent trcEvent, | |
129 | Long funcptr) { | |
130 | Long cpu = trcEvent.getCpuId(); | |
131 | LttngProcessState process = traceSt.getRunning_process().get(cpu); | |
132 | Long curr_function = process.getCurrent_function(); | |
133 | ||
134 | if (curr_function != null && curr_function != funcptr) { | |
135 | TraceDebug.debug("Different functions: " + funcptr + " current: " | |
136 | + curr_function + " time stamp: " | |
137 | + trcEvent.getTimestamp().toString()); | |
138 | ||
139 | // g_info("Different functions (%lu.%09lu): ignore it\n", | |
140 | // tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec); | |
141 | // g_info("process state has %" PRIu64 " when pop_function is %" | |
142 | // PRIu64 | |
143 | // "\n", | |
144 | // process->current_function, funcptr); | |
145 | // g_info("{ %u, %u, %s, %s, %s }\n", | |
146 | // process->pid, | |
147 | // process->ppid, | |
148 | // g_quark_to_string(process->name), | |
149 | // g_quark_to_string(process->brand), | |
150 | // g_quark_to_string(process->state->s)); | |
151 | return; | |
152 | } | |
153 | ||
154 | process.popFromUserStack(); | |
155 | process.setCurrent_function(process.peekFromUserStack()); | |
156 | } | |
157 | ||
158 | // ======================================================================== | |
159 | // General methods | |
160 | // ======================================================================= | |
58c60db3 FC |
161 | /** |
162 | * protected method used when only one Field is expected with Type "Long" if | |
163 | * the number of fields is greater, the first field is returned and a | |
164 | * tracing message is sent Null is returned if the value could not be | |
165 | * extracted. | |
166 | * | |
167 | * @param trcEvent | |
168 | * @param traceSt | |
169 | * @param expectedNumFields | |
170 | * @return | |
171 | */ | |
172 | protected Long getDField(LttngEvent trcEvent, LttngTraceState traceSt, | |
173 | Fields expectedField) { | |
174 | Long fieldVal = null; | |
175 | TmfEventField[] fields = trcEvent.getContent().getFields(); | |
176 | String[] fieldLabels = trcEvent.getContent().getFormat().getLabels(); | |
177 | ||
178 | // Only one field expected | |
179 | if (fields.length != 1 || fieldLabels.length != 1) { | |
180 | StringBuilder sb = new StringBuilder( | |
181 | "Unexpected number of fields received: " + fields.length | |
182 | + " for Event: " + trcEvent.getMarkerName() + "\n\t\tFields: "); | |
183 | ||
184 | for (TmfEventField field : fields) { | |
185 | sb.append(((LttngEventField)field).getName() + " "); | |
186 | } | |
187 | ||
188 | TraceDebug.debug(sb.toString()); | |
189 | if (fields.length == 0) { | |
190 | return null; | |
191 | } | |
192 | } | |
193 | ||
194 | LttngEventField field = (LttngEventField) fields[0]; | |
195 | String fieldname = field.getName(); | |
196 | String expectedFieldName = expectedField.getInName(); | |
197 | if (fieldname.equals(expectedFieldName)) { | |
198 | Object fieldObj = field.getValue(); | |
199 | if (fieldObj instanceof Long) { | |
200 | // Expected value found | |
201 | fieldVal = (Long) field.getValue(); | |
202 | } else { | |
203 | if (TraceDebug.isDEBUG()) { | |
204 | TraceDebug | |
205 | .debug("Unexpected field Type. Expected: Long, Received: " | |
206 | + fieldObj.getClass().getSimpleName()); | |
207 | } | |
208 | return null; | |
209 | } | |
210 | } else { | |
211 | TraceDebug.debug("Unexpected field received: " + fieldname | |
212 | + " Expected: " + expectedFieldName); | |
213 | return null; | |
214 | } | |
215 | ||
216 | return fieldVal; | |
217 | } | |
218 | ||
219 | /** | |
220 | * protected method used when a Field is requested among several available | |
221 | * fields and the expected type is Long | |
222 | * | |
223 | * @param trcEvent | |
224 | * @param traceSt | |
225 | * @param expectedNumFields | |
226 | * @return | |
227 | */ | |
228 | protected Long getAFieldLong(LttngEvent trcEvent, LttngTraceState traceSt, | |
229 | Fields expectedField) { | |
230 | Long fieldVal = null; | |
231 | TmfEventField[] fields = trcEvent.getContent().getFields(); | |
232 | ||
233 | // At least one field expected | |
234 | if (fields.length == 0) { | |
235 | TraceDebug.debug("Unexpected number of fields received: " | |
236 | + fields.length); | |
237 | return null; | |
238 | } | |
239 | ||
240 | LttngEventField field; | |
241 | String fieldname; | |
242 | String expectedFieldName = expectedField.getInName(); | |
243 | for (int i = 0; i < fields.length; i++) { | |
244 | field = (LttngEventField) fields[i]; | |
245 | fieldname = field.getName(); | |
246 | if (fieldname.equals(expectedFieldName)) { | |
247 | Object fieldObj = field.getValue(); | |
248 | if (fieldObj instanceof Long) { | |
249 | // Expected value found | |
250 | fieldVal = (Long) field.getValue(); | |
251 | // if (expectedField == Fields.LTT_FIELD_TYPE) { | |
252 | // TraceDebug.debug("Field Type value is: " + fieldVal); | |
253 | // } | |
254 | break; | |
255 | } else { | |
256 | if (TraceDebug.isDEBUG()) { | |
257 | TraceDebug | |
258 | .debug("Unexpected field Type. Expected: Long, Received: " | |
259 | + fieldObj.getClass().getSimpleName()); | |
260 | } | |
261 | return null; | |
262 | } | |
263 | } | |
264 | } | |
265 | ||
266 | if (fieldVal == null) { | |
267 | if (TraceDebug.isDEBUG()) { | |
268 | sendNoFieldFoundMsg(fields, expectedFieldName); | |
269 | } | |
270 | } | |
271 | return fieldVal; | |
272 | } | |
273 | ||
274 | /** | |
275 | * protected method used when a Field is requested among several available | |
276 | * fields and the expected type is String | |
277 | * | |
278 | * @param trcEvent | |
279 | * @param traceSt | |
280 | * @param expectedNumFields | |
281 | * @return | |
282 | */ | |
283 | protected String getAFieldString(LttngEvent trcEvent, | |
284 | LttngTraceState traceSt, Fields expectedField) { | |
285 | String fieldVal = null; | |
286 | TmfEventField[] fields = trcEvent.getContent().getFields(); | |
287 | ||
288 | // Only one field expected | |
289 | if (fields.length == 0) { | |
290 | TraceDebug.debug("Unexpected number of fields received: " | |
291 | + fields.length); | |
292 | return null; | |
293 | } | |
294 | ||
295 | LttngEventField field; | |
296 | String fieldname; | |
297 | String expectedFieldName = expectedField.getInName(); | |
298 | for (int i = 0; i < fields.length; i++) { | |
299 | field = (LttngEventField) fields[i]; | |
300 | fieldname = field.getName(); | |
301 | if (fieldname.equals(expectedFieldName)) { | |
302 | Object fieldObj = field.getValue(); | |
303 | if (fieldObj instanceof String) { | |
304 | // Expected value found | |
305 | fieldVal = (String) field.getValue(); | |
306 | break; | |
307 | } else { | |
308 | if (TraceDebug.isDEBUG()) { | |
309 | TraceDebug | |
310 | .debug("Unexpected field Type. Expected: String, Received: " | |
311 | + fieldObj.getClass().getSimpleName()); | |
312 | } | |
313 | return null; | |
314 | } | |
315 | } | |
316 | } | |
317 | ||
318 | if (fieldVal == null) { | |
319 | if (TraceDebug.isDEBUG()) { | |
320 | sendNoFieldFoundMsg(fields, expectedFieldName); | |
321 | } | |
322 | } | |
323 | return fieldVal; | |
324 | } | |
325 | ||
326 | protected void sendNoFieldFoundMsg(TmfEventField[] fields, | |
327 | String expectedFieldName) { | |
328 | LttngEventField field; | |
329 | StringBuilder sb = new StringBuilder("Field not found, requested: " | |
330 | + expectedFieldName); | |
331 | sb.append(" number of fields: " + fields.length + "Fields: "); | |
332 | for (int i = 0; i < fields.length; i++) { | |
333 | field = (LttngEventField) fields[i]; | |
334 | sb.append(field.getName() + " "); | |
335 | } | |
336 | ||
337 | TraceDebug.debug(sb.toString(), 5); | |
338 | } | |
339 | ||
5d10d135 ASL |
340 | // Adaption from MKDEV macro |
341 | protected Long mkdev(Long major, Long minor) { | |
342 | Long result = null; | |
343 | if (major != null && minor != null) { | |
344 | result = (major << 20) | minor; | |
345 | } | |
346 | return result; | |
347 | } | |
348 | ||
349 | /* | |
350 | * FIXME : this function should be called when we receive an event telling | |
351 | * that release_task has been called in the kernel. In happens generally | |
58c60db3 | 352 | * when the parent waits for its child terminaison, but may also happen in |
5d10d135 ASL |
353 | * special cases in the child's exit : when the parent ignores its children |
354 | * SIGCCHLD or has the flag SA_NOCLDWAIT. It can also happen when the child | |
355 | * is part of a killed thread group, but isn't the leader. | |
356 | */ | |
357 | protected boolean exit_process(LttngTraceState ts, LttngProcessState process) { | |
358 | /* | |
359 | * Wait for both schedule with exit dead and process free to happen. | |
360 | * They can happen in any order. | |
361 | */ | |
362 | process.incrementFree_events(); | |
363 | if (process.getFree_events() < 2) { | |
364 | return false; | |
365 | } | |
366 | ||
367 | process.clearExecutionStack(); | |
368 | process.clearUserStack(); | |
58c60db3 | 369 | ts.getProcesses().remove(process); |
5d10d135 ASL |
370 | |
371 | return true; | |
372 | } | |
373 | ||
58c60db3 FC |
374 | /** |
375 | * Find the process matching the given pid and cpu | |
376 | * | |
377 | * If cpu is 0, the cpu value is not matched and the selection is based on | |
378 | * pid value only | |
379 | * | |
380 | * @param ts | |
381 | * @param cpu | |
382 | * @param pid | |
383 | * @return | |
384 | */ | |
385 | protected LttngProcessState lttv_state_find_process(LttngTraceState ts, | |
386 | Long cpu, Long pid) { | |
387 | // Define the return value | |
388 | LttngProcessState process = null; | |
389 | ||
390 | // Obtain the list of available processes | |
391 | List<LttngProcessState> processList = ts.getProcesses(); | |
392 | ||
393 | // find the process matching pid and cpu, | |
394 | // TODO: This may need to be improved since the pid may be re-used and | |
395 | // the creation time may need to be considered. | |
396 | // NOTE: A hash search shall be used | |
397 | for (LttngProcessState dprocess : processList) { | |
398 | if (dprocess.getPid().equals(pid)) { | |
399 | if (dprocess.getCpu().equals(cpu) || cpu.longValue() == 0L) { | |
400 | return dprocess; | |
401 | } | |
402 | } | |
403 | } | |
404 | ||
405 | return process; | |
406 | } | |
407 | ||
408 | /** | |
409 | * @param ts | |
410 | * @param cpu | |
411 | * @param pid | |
412 | * @param timestamp | |
413 | * , Used when a new process is needed | |
414 | * @return | |
415 | */ | |
416 | protected LttngProcessState lttv_state_find_process_or_create( | |
417 | LttngTraceState ts, Long cpu, Long pid, final TmfTimestamp timestamp) { | |
418 | ||
419 | LttngProcessState process = lttv_state_find_process(ts, cpu, pid); | |
420 | /* Put ltt_time_zero creation time for unexisting processes */ | |
421 | if (process == null) { | |
422 | process = create_process(ts, cpu, pid, 0L, timestamp); | |
423 | } | |
424 | return process; | |
425 | } | |
426 | ||
5d10d135 ASL |
427 | /** |
428 | * @param traceSt | |
429 | * @param cpu | |
430 | * @param pid | |
431 | * @param tgid | |
432 | * @param timestamp | |
433 | * @return | |
434 | */ | |
435 | protected LttngProcessState create_process(LttngTraceState traceSt, | |
436 | Long cpu, Long pid, Long tgid, final TmfTimestamp timestamp) { | |
437 | LttngProcessState process = create_process(traceSt, cpu, pid, tgid, | |
438 | ProcessStatus.LTTV_STATE_UNNAMED.getInName(), timestamp); | |
439 | return process; | |
440 | } | |
441 | ||
442 | /** | |
443 | * @param traceSt | |
444 | * @param cpu | |
445 | * @param pid | |
446 | * @param tgid | |
447 | * @param name | |
448 | * @param timestamp | |
449 | * @return | |
450 | */ | |
451 | protected LttngProcessState create_process(LttngTraceState traceSt, | |
452 | Long cpu, Long pid, Long tgid, String name, | |
453 | final TmfTimestamp timestamp) { | |
454 | LttngProcessState process; | |
58c60db3 FC |
455 | process = new LttngProcessState(cpu, pid, tgid, name, timestamp); |
456 | traceSt.getProcesses().add(process); | |
5d10d135 ASL |
457 | return process; |
458 | } | |
459 | ||
460 | } |