Commit | Line | Data |
---|---|---|
8c8bf09f ASL |
1 | /******************************************************************************* |
2 | * Copyright (c) 2009, 2010 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 | * Francois Chouinard - Initial API and implementation | |
11 | *******************************************************************************/ | |
12 | ||
13 | package org.eclipse.linuxtools.tmf.experiment; | |
14 | ||
9f584e4c | 15 | import java.util.Collections; |
8c8bf09f ASL |
16 | import java.util.Vector; |
17 | ||
05bd3318 FC |
18 | import org.eclipse.core.runtime.IProgressMonitor; |
19 | import org.eclipse.core.runtime.IStatus; | |
20 | import org.eclipse.core.runtime.Status; | |
21 | import org.eclipse.core.runtime.jobs.Job; | |
fc6ccf6f | 22 | import org.eclipse.linuxtools.tmf.component.TmfEventProvider; |
8c8bf09f ASL |
23 | import org.eclipse.linuxtools.tmf.event.TmfEvent; |
24 | import org.eclipse.linuxtools.tmf.event.TmfTimeRange; | |
25 | import org.eclipse.linuxtools.tmf.event.TmfTimestamp; | |
2fb2eb37 FC |
26 | import org.eclipse.linuxtools.tmf.request.ITmfDataRequest; |
27 | import org.eclipse.linuxtools.tmf.request.ITmfEventRequest; | |
550d787e FC |
28 | import org.eclipse.linuxtools.tmf.request.TmfDataRequest; |
29 | import org.eclipse.linuxtools.tmf.request.TmfEventRequest; | |
8e31f2d2 | 30 | import org.eclipse.linuxtools.tmf.signal.TmfExperimentDisposedSignal; |
ff4ed569 FC |
31 | import org.eclipse.linuxtools.tmf.signal.TmfExperimentSelectedSignal; |
32 | import org.eclipse.linuxtools.tmf.signal.TmfExperimentUpdatedSignal; | |
8c8bf09f | 33 | import org.eclipse.linuxtools.tmf.signal.TmfSignalHandler; |
550d787e | 34 | import org.eclipse.linuxtools.tmf.signal.TmfSignalManager; |
ff4ed569 | 35 | import org.eclipse.linuxtools.tmf.signal.TmfTraceUpdatedSignal; |
9f584e4c FC |
36 | import org.eclipse.linuxtools.tmf.trace.ITmfContext; |
37 | import org.eclipse.linuxtools.tmf.trace.ITmfLocation; | |
8c8bf09f | 38 | import org.eclipse.linuxtools.tmf.trace.ITmfTrace; |
9f584e4c FC |
39 | import org.eclipse.linuxtools.tmf.trace.TmfCheckpoint; |
40 | import org.eclipse.linuxtools.tmf.trace.TmfContext; | |
8c8bf09f ASL |
41 | |
42 | /** | |
43 | * <b><u>TmfExperiment</u></b> | |
44 | * <p> | |
45 | * TmfExperiment presents a time-ordered, unified view of a set of TmfTraces | |
9b635e61 | 46 | * that are part of a tracing experiment. |
8c8bf09f ASL |
47 | * <p> |
48 | */ | |
fc6ccf6f | 49 | public class TmfExperiment<T extends TmfEvent> extends TmfEventProvider<T> implements ITmfTrace { |
8c8bf09f ASL |
50 | |
51 | // ------------------------------------------------------------------------ | |
52 | // Attributes | |
53 | // ------------------------------------------------------------------------ | |
54 | ||
a79913eb | 55 | // The currently selected experiment |
82e04272 | 56 | protected static TmfExperiment<?> fCurrentExperiment = null; |
e31e01e8 | 57 | |
a79913eb | 58 | // The set of traces that constitute the experiment |
82e04272 | 59 | protected ITmfTrace[] fTraces; |
8c8bf09f ASL |
60 | |
61 | // The total number of events | |
82e04272 | 62 | protected long fNbEvents; |
8c8bf09f ASL |
63 | |
64 | // The experiment time range | |
82e04272 | 65 | protected TmfTimeRange fTimeRange; |
8c8bf09f | 66 | |
9b635e61 | 67 | // The experiment reference timestamp (default: Zero) |
82e04272 | 68 | protected TmfTimestamp fEpoch; |
8c8bf09f | 69 | |
a79913eb | 70 | // The experiment index |
82e04272 | 71 | protected Vector<TmfCheckpoint> fCheckpoints = new Vector<TmfCheckpoint>(); |
9f584e4c | 72 | |
f6b14ce2 FC |
73 | // The current experiment context |
74 | protected TmfExperimentContext fExperimentContext; | |
a79913eb | 75 | |
8c8bf09f ASL |
76 | // ------------------------------------------------------------------------ |
77 | // Constructors | |
78 | // ------------------------------------------------------------------------ | |
79 | ||
80 | /** | |
81 | * @param type | |
82 | * @param id | |
83 | * @param traces | |
84 | * @param epoch | |
85 | * @param indexPageSize | |
86 | */ | |
87 | public TmfExperiment(Class<T> type, String id, ITmfTrace[] traces, TmfTimestamp epoch, int indexPageSize) { | |
045df77d | 88 | this(type, id, traces, TmfTimestamp.Zero, indexPageSize, false); |
a79913eb | 89 | } |
cb866e08 | 90 | |
9b635e61 | 91 | public TmfExperiment(Class<T> type, String id, ITmfTrace[] traces, TmfTimestamp epoch, int indexPageSize, boolean preIndexExperiment) { |
a79913eb | 92 | super(id, type); |
8c8bf09f | 93 | |
a79913eb FC |
94 | fTraces = traces; |
95 | fEpoch = epoch; | |
96 | fIndexPageSize = indexPageSize; | |
97 | fTimeRange = TmfTimeRange.Null; | |
8c8bf09f | 98 | |
a79913eb FC |
99 | if (preIndexExperiment) { |
100 | indexExperiment(true); | |
101 | updateTimeRange(); | |
102 | } | |
cb866e08 | 103 | |
a79913eb | 104 | } |
8c8bf09f | 105 | |
82e04272 FC |
106 | protected TmfExperiment(String id, Class<T> type) { |
107 | super(id, type); | |
a79913eb | 108 | } |
82e04272 | 109 | |
8c8bf09f ASL |
110 | /** |
111 | * @param type | |
112 | * @param id | |
113 | * @param traces | |
114 | */ | |
115 | public TmfExperiment(Class<T> type, String id, ITmfTrace[] traces) { | |
116 | this(type, id, traces, TmfTimestamp.Zero, DEFAULT_INDEX_PAGE_SIZE); | |
117 | } | |
118 | ||
119 | /** | |
120 | * @param type | |
121 | * @param id | |
122 | * @param traces | |
123 | * @param indexPageSize | |
124 | */ | |
125 | public TmfExperiment(Class<T> type, String id, ITmfTrace[] traces, int indexPageSize) { | |
126 | this(type, id, traces, TmfTimestamp.Zero, indexPageSize); | |
127 | } | |
a79913eb | 128 | |
f6b14ce2 FC |
129 | /** |
130 | * Copy constructor | |
a79913eb | 131 | * |
f6b14ce2 FC |
132 | * @param other |
133 | */ | |
ce785d7d | 134 | public TmfExperiment(TmfExperiment<T> other) { |
a79913eb FC |
135 | super(other.getName() + "(clone)", other.fType); //$NON-NLS-1$ |
136 | ||
137 | fEpoch = other.fEpoch; | |
138 | fIndexPageSize = other.fIndexPageSize; | |
139 | ||
140 | fTraces = new ITmfTrace[other.fTraces.length]; | |
141 | for (int trace = 0; trace < other.fTraces.length; trace++) { | |
142 | fTraces[trace] = other.fTraces[trace].createTraceCopy(); | |
143 | } | |
144 | ||
145 | fNbEvents = other.fNbEvents; | |
146 | fTimeRange = other.fTimeRange; | |
147 | } | |
148 | ||
149 | @Override | |
150 | public TmfExperiment<T> createTraceCopy() { | |
151 | TmfExperiment<T> experiment = new TmfExperiment<T>(this); | |
152 | TmfSignalManager.deregister(experiment); | |
153 | return experiment; | |
154 | } | |
155 | ||
8c8bf09f | 156 | /** |
ff4ed569 | 157 | * Clears the experiment |
8c8bf09f ASL |
158 | */ |
159 | @Override | |
a79913eb FC |
160 | public synchronized void dispose() { |
161 | ||
162 | TmfExperimentDisposedSignal<T> signal = new TmfExperimentDisposedSignal<T>(this, this); | |
163 | broadcast(signal); | |
164 | ||
165 | if (fTraces != null) { | |
166 | for (ITmfTrace trace : fTraces) { | |
167 | trace.dispose(); | |
168 | } | |
169 | fTraces = null; | |
170 | } | |
171 | if (fCheckpoints != null) { | |
172 | fCheckpoints.clear(); | |
173 | } | |
2fb2eb37 | 174 | super.dispose(); |
8c8bf09f ASL |
175 | } |
176 | ||
9f584e4c | 177 | // ------------------------------------------------------------------------ |
cbd4ad82 | 178 | // ITmfTrace |
9f584e4c FC |
179 | // ------------------------------------------------------------------------ |
180 | ||
a79913eb FC |
181 | @Override |
182 | public String getPath() { | |
183 | return null; | |
184 | } | |
9f584e4c | 185 | |
a79913eb FC |
186 | @Override |
187 | public long getNbEvents() { | |
188 | return fNbEvents; | |
189 | } | |
9f584e4c | 190 | |
d4011df2 | 191 | @Override |
a79913eb | 192 | public int getCacheSize() { |
54d55ced FC |
193 | return fIndexPageSize; |
194 | } | |
195 | ||
a79913eb FC |
196 | @Override |
197 | public TmfTimeRange getTimeRange() { | |
198 | return fTimeRange; | |
199 | } | |
9f584e4c | 200 | |
a79913eb FC |
201 | @Override |
202 | public TmfTimestamp getStartTime() { | |
203 | return fTimeRange.getStartTime(); | |
204 | } | |
9f584e4c | 205 | |
a79913eb FC |
206 | @Override |
207 | public TmfTimestamp getEndTime() { | |
208 | return fTimeRange.getEndTime(); | |
209 | } | |
9f584e4c | 210 | |
54d55ced | 211 | public Vector<TmfCheckpoint> getCheckpoints() { |
a79913eb | 212 | return fCheckpoints; |
54d55ced FC |
213 | } |
214 | ||
8c8bf09f | 215 | // ------------------------------------------------------------------------ |
e31e01e8 | 216 | // Accessors |
8c8bf09f ASL |
217 | // ------------------------------------------------------------------------ |
218 | ||
c1c69938 | 219 | public static void setCurrentExperiment(TmfExperiment<?> experiment) { |
a79913eb | 220 | fCurrentExperiment = experiment; |
f6b14ce2 FC |
221 | } |
222 | ||
e31e01e8 | 223 | public static TmfExperiment<?> getCurrentExperiment() { |
a79913eb | 224 | return fCurrentExperiment; |
8c8bf09f ASL |
225 | } |
226 | ||
8c8bf09f | 227 | public TmfTimestamp getEpoch() { |
a79913eb | 228 | return fEpoch; |
8c8bf09f ASL |
229 | } |
230 | ||
9f584e4c | 231 | public ITmfTrace[] getTraces() { |
a79913eb | 232 | return fTraces; |
8c8bf09f ASL |
233 | } |
234 | ||
235 | /** | |
a79913eb FC |
236 | * Returns the rank of the first event with the requested timestamp. If |
237 | * none, returns the index of the next event (if any). | |
238 | * | |
85fb0e54 | 239 | * @param timestamp |
8c8bf09f ASL |
240 | * @return |
241 | */ | |
d4011df2 | 242 | @Override |
a79913eb FC |
243 | public long getRank(TmfTimestamp timestamp) { |
244 | TmfExperimentContext context = seekEvent(timestamp); | |
245 | return context.getRank(); | |
8c8bf09f ASL |
246 | } |
247 | ||
248 | /** | |
a79913eb FC |
249 | * Returns the timestamp of the event at the requested index. If none, |
250 | * returns null. | |
251 | * | |
8c8bf09f ASL |
252 | * @param index |
253 | * @return | |
254 | */ | |
255 | public TmfTimestamp getTimestamp(int index) { | |
a79913eb FC |
256 | TmfExperimentContext context = seekEvent(index); |
257 | TmfEvent event = getNextEvent(context); | |
258 | return (event != null) ? event.getTimestamp() : null; | |
8c8bf09f ASL |
259 | } |
260 | ||
261 | // ------------------------------------------------------------------------ | |
262 | // Operators | |
263 | // ------------------------------------------------------------------------ | |
264 | ||
8c8bf09f ASL |
265 | /** |
266 | * Update the global time range | |
267 | */ | |
a79913eb FC |
268 | protected void updateTimeRange() { |
269 | TmfTimestamp startTime = fTimeRange != TmfTimeRange.Null ? fTimeRange.getStartTime() : TmfTimestamp.BigCrunch; | |
270 | TmfTimestamp endTime = fTimeRange != TmfTimeRange.Null ? fTimeRange.getEndTime() : TmfTimestamp.BigBang; | |
271 | ||
272 | for (ITmfTrace trace : fTraces) { | |
273 | TmfTimestamp traceStartTime = trace.getStartTime(); | |
274 | if (traceStartTime.compareTo(startTime, true) < 0) | |
275 | startTime = traceStartTime; | |
276 | TmfTimestamp traceEndTime = trace.getEndTime(); | |
277 | if (traceEndTime.compareTo(endTime, true) > 0) | |
278 | endTime = traceEndTime; | |
279 | } | |
280 | fTimeRange = new TmfTimeRange(startTime, endTime); | |
8c8bf09f ASL |
281 | } |
282 | ||
283 | // ------------------------------------------------------------------------ | |
284 | // TmfProvider | |
285 | // ------------------------------------------------------------------------ | |
a79913eb FC |
286 | @Override |
287 | public ITmfContext armRequest(ITmfDataRequest<T> request) { | |
9b635e61 | 288 | // Tracer.trace("Ctx: Arming request - start"); |
a79913eb FC |
289 | TmfTimestamp timestamp = (request instanceof ITmfEventRequest<?>) ? ((ITmfEventRequest<T>) request).getRange().getStartTime() : null; |
290 | ||
291 | if (TmfTimestamp.BigBang.equals(timestamp) || request.getIndex() > 0) { | |
292 | timestamp = null; // use request index | |
293 | } | |
294 | ||
295 | TmfExperimentContext context = null; | |
296 | if (timestamp != null) { | |
297 | // seek by timestamp | |
298 | context = seekEvent(timestamp); | |
299 | ((ITmfEventRequest<T>) request).setStartIndex((int) context.getRank()); | |
300 | } else { | |
301 | // Seek by rank | |
302 | if ((fExperimentContext != null) && fExperimentContext.getRank() == request.getIndex()) { | |
303 | // We are already at the right context -> no need to seek | |
304 | context = fExperimentContext; | |
305 | } else { | |
306 | context = seekEvent(request.getIndex()); | |
307 | } | |
308 | } | |
9b635e61 | 309 | // Tracer.trace("Ctx: Arming request - done"); |
a79913eb FC |
310 | return context; |
311 | } | |
312 | ||
313 | @SuppressWarnings("unchecked") | |
314 | @Override | |
315 | public T getNext(ITmfContext context) { | |
316 | if (context instanceof TmfExperimentContext) { | |
317 | return (T) getNextEvent((TmfExperimentContext) context); | |
318 | } | |
319 | return null; | |
320 | } | |
321 | ||
322 | // ------------------------------------------------------------------------ | |
9f584e4c FC |
323 | // ITmfTrace trace positioning |
324 | // ------------------------------------------------------------------------ | |
325 | ||
a79913eb FC |
326 | // Returns a brand new context based on the location provided |
327 | // and initializes the event queues | |
328 | @Override | |
329 | public synchronized TmfExperimentContext seekLocation(ITmfLocation<?> location) { | |
330 | // Validate the location | |
331 | if (location != null && !(location instanceof TmfExperimentLocation)) { | |
332 | return null; // Throw an exception? | |
333 | } | |
8f50c396 | 334 | |
a79913eb FC |
335 | if (fTraces == null) { // experiment has been disposed |
336 | return null; | |
337 | } | |
8f50c396 | 338 | |
a79913eb FC |
339 | // Instantiate the location |
340 | TmfExperimentLocation expLocation = (location == null) ? new TmfExperimentLocation(new TmfLocationArray(new ITmfLocation<?>[fTraces.length]), | |
341 | new long[fTraces.length]) : (TmfExperimentLocation) location.clone(); | |
8f50c396 | 342 | |
a79913eb FC |
343 | // Create and populate the context's traces contexts |
344 | TmfExperimentContext context = new TmfExperimentContext(fTraces, new TmfContext[fTraces.length]); | |
9b635e61 FC |
345 | // Tracer.trace("Ctx: SeekLocation - start"); |
346 | ||
a79913eb FC |
347 | long rank = 0; |
348 | for (int i = 0; i < fTraces.length; i++) { | |
349 | // Get the relevant trace attributes | |
350 | ITmfLocation<?> traceLocation = expLocation.getLocation().locations[i]; | |
351 | long traceRank = expLocation.getRanks()[i]; | |
8f50c396 | 352 | |
a79913eb FC |
353 | // Set the corresponding sub-context |
354 | context.getContexts()[i] = fTraces[i].seekLocation(traceLocation); | |
355 | context.getContexts()[i].setRank(traceRank); | |
356 | rank += traceRank; | |
8f50c396 | 357 | |
a79913eb FC |
358 | // Set the trace location and read the corresponding event |
359 | expLocation.getLocation().locations[i] = context.getContexts()[i].getLocation(); | |
360 | context.getEvents()[i] = fTraces[i].getNextEvent(context.getContexts()[i]); | |
361 | } | |
8f50c396 | 362 | |
9b635e61 FC |
363 | // Tracer.trace("Ctx: SeekLocation - done"); |
364 | ||
a79913eb FC |
365 | // Finalize context |
366 | context.setLocation(expLocation); | |
367 | context.setLastTrace(TmfExperimentContext.NO_TRACE); | |
368 | context.setRank(rank); | |
9b635e61 | 369 | |
a79913eb | 370 | fExperimentContext = context; |
9b635e61 | 371 | |
a79913eb FC |
372 | return context; |
373 | } | |
9f584e4c | 374 | |
a79913eb FC |
375 | /* |
376 | * (non-Javadoc) | |
377 | * | |
378 | * @see | |
379 | * org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools | |
380 | * .tmf.event.TmfTimestamp) | |
381 | */ | |
382 | @Override | |
383 | public synchronized TmfExperimentContext seekEvent(TmfTimestamp timestamp) { | |
9b635e61 FC |
384 | |
385 | // Tracer.trace("Ctx: seekEvent(TS) - start"); | |
8c8bf09f | 386 | |
a79913eb FC |
387 | if (timestamp == null) { |
388 | timestamp = TmfTimestamp.BigBang; | |
389 | } | |
9f584e4c | 390 | |
a79913eb FC |
391 | // First, find the right checkpoint |
392 | int index = Collections.binarySearch(fCheckpoints, new TmfCheckpoint(timestamp, null)); | |
9f584e4c FC |
393 | |
394 | // In the very likely case that the checkpoint was not found, bsearch | |
395 | // returns its negated would-be location (not an offset...). From that | |
396 | // index, we can then position the stream and get the event. | |
397 | if (index < 0) { | |
398 | index = Math.max(0, -(index + 2)); | |
399 | } | |
400 | ||
401 | // Position the experiment at the checkpoint | |
452ad365 | 402 | ITmfLocation<?> location; |
9f584e4c | 403 | synchronized (fCheckpoints) { |
a79913eb FC |
404 | if (fCheckpoints.size() > 0) { |
405 | if (index >= fCheckpoints.size()) { | |
406 | index = fCheckpoints.size() - 1; | |
407 | } | |
408 | location = fCheckpoints.elementAt(index).getLocation(); | |
409 | } else { | |
410 | location = null; | |
411 | } | |
9f584e4c FC |
412 | } |
413 | ||
85fb0e54 | 414 | TmfExperimentContext context = seekLocation(location); |
cbd4ad82 | 415 | context.setRank((long) index * fIndexPageSize); |
9f584e4c | 416 | |
a79913eb | 417 | // And locate the event |
fa867360 | 418 | TmfEvent event = parseEvent(context); |
9f584e4c | 419 | while (event != null && event.getTimestamp().compareTo(timestamp, false) < 0) { |
a79913eb FC |
420 | getNextEvent(context); |
421 | event = parseEvent(context); | |
9f584e4c FC |
422 | } |
423 | ||
f6b14ce2 | 424 | if (event == null) { |
a79913eb FC |
425 | context.setLocation(null); |
426 | context.setRank(ITmfContext.UNKNOWN_RANK); | |
9b635e61 | 427 | } |
f6b14ce2 FC |
428 | |
429 | return context; | |
a79913eb | 430 | } |
8c8bf09f | 431 | |
a79913eb FC |
432 | /* |
433 | * (non-Javadoc) | |
434 | * | |
435 | * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(long) | |
436 | */ | |
437 | @Override | |
438 | public synchronized TmfExperimentContext seekEvent(long rank) { | |
9b635e61 FC |
439 | |
440 | // Tracer.trace("Ctx: seekEvent(rank) - start"); | |
9f584e4c | 441 | |
54d55ced FC |
442 | // Position the stream at the previous checkpoint |
443 | int index = (int) rank / fIndexPageSize; | |
444 | ITmfLocation<?> location; | |
445 | synchronized (fCheckpoints) { | |
a79913eb FC |
446 | if (fCheckpoints.size() == 0) { |
447 | location = null; | |
448 | } else { | |
449 | if (index >= fCheckpoints.size()) { | |
450 | index = fCheckpoints.size() - 1; | |
451 | } | |
452 | location = fCheckpoints.elementAt(index).getLocation(); | |
453 | } | |
54d55ced | 454 | } |
e31e01e8 | 455 | |
54d55ced | 456 | TmfExperimentContext context = seekLocation(location); |
9b635e61 | 457 | context.setRank((long) index * fIndexPageSize); |
54d55ced | 458 | |
a79913eb | 459 | // And locate the event |
fa867360 | 460 | TmfEvent event = parseEvent(context); |
9b635e61 | 461 | long pos = context.getRank(); |
fa867360 | 462 | while (event != null && pos++ < rank) { |
a79913eb FC |
463 | getNextEvent(context); |
464 | event = parseEvent(context); | |
54d55ced | 465 | } |
9f584e4c | 466 | |
f6b14ce2 | 467 | if (event == null) { |
a79913eb FC |
468 | context.setLocation(null); |
469 | context.setRank(ITmfContext.UNKNOWN_RANK); | |
9b635e61 | 470 | } |
f6b14ce2 | 471 | |
a79913eb FC |
472 | return context; |
473 | } | |
8c8bf09f | 474 | |
c76c54bb FC |
475 | @Override |
476 | public TmfContext seekLocation(double ratio) { | |
477 | TmfContext context = seekEvent((long) (ratio * getNbEvents())); | |
478 | return context; | |
479 | } | |
480 | ||
a79913eb | 481 | @Override |
c76c54bb | 482 | public double getLocationRatio(ITmfLocation<?> location) { |
a79913eb FC |
483 | if (location instanceof TmfExperimentLocation) { |
484 | return (double) seekLocation(location).getRank() / getNbEvents(); | |
485 | } | |
c76c54bb FC |
486 | return 0; |
487 | } | |
488 | ||
a79913eb FC |
489 | @Override |
490 | public ITmfLocation<?> getCurrentLocation() { | |
491 | if (fExperimentContext != null) { | |
492 | return fExperimentContext.getLocation(); | |
493 | } | |
494 | return null; | |
495 | } | |
c76c54bb | 496 | |
a79913eb FC |
497 | /** |
498 | * Scan the next events from all traces and return the next one in | |
499 | * chronological order. | |
500 | * | |
501 | * @param context | |
502 | * @return | |
503 | */ | |
9b635e61 FC |
504 | |
505 | // private void dumpContext(TmfExperimentContext context, boolean isBefore) { | |
506 | ||
507 | // TmfContext context0 = context.getContexts()[0]; | |
508 | // TmfEvent event0 = context.getEvents()[0]; | |
509 | // TmfExperimentLocation location0 = (TmfExperimentLocation) context.getLocation(); | |
510 | // long rank0 = context.getRank(); | |
511 | // int trace = context.getLastTrace(); | |
512 | // | |
513 | // StringBuffer result = new StringBuffer("Ctx: " + (isBefore ? "B " : "A ")); | |
514 | // | |
515 | // result.append("[Ctx: fLoc= " + context0.getLocation().toString() + ", fRnk= " + context0.getRank() + "] "); | |
516 | // result.append("[Evt: " + event0.getTimestamp().toString() + "] "); | |
517 | // result.append("[Loc: fLoc= " + location0.getLocation()[0].toString() + ", fRnk= " + location0.getRanks()[0] + "] "); | |
518 | // result.append("[Rnk: " + rank0 + "], [Trc: " + trace + "]"); | |
519 | // Tracer.trace(result.toString()); | |
520 | // } | |
54d55ced | 521 | |
a79913eb FC |
522 | @Override |
523 | public synchronized TmfEvent getNextEvent(TmfContext context) { | |
524 | ||
525 | // Validate the context | |
526 | if (!(context instanceof TmfExperimentContext)) { | |
527 | return null; // Throw an exception? | |
528 | } | |
54d55ced | 529 | |
a79913eb | 530 | if (!context.equals(fExperimentContext)) { |
9b635e61 | 531 | // Tracer.trace("Ctx: Restoring context"); |
a79913eb FC |
532 | fExperimentContext = seekLocation(context.getLocation()); |
533 | } | |
534 | ||
535 | TmfExperimentContext expContext = (TmfExperimentContext) context; | |
8f50c396 | 536 | |
9b635e61 FC |
537 | // dumpContext(expContext, true); |
538 | ||
a79913eb FC |
539 | // If an event was consumed previously, get the next one from that trace |
540 | int lastTrace = expContext.getLastTrace(); | |
541 | if (lastTrace != TmfExperimentContext.NO_TRACE) { | |
542 | TmfContext traceContext = expContext.getContexts()[lastTrace]; | |
543 | expContext.getEvents()[lastTrace] = expContext.getTraces()[lastTrace].getNextEvent(traceContext); | |
544 | expContext.setLastTrace(TmfExperimentContext.NO_TRACE); | |
545 | } | |
8f50c396 | 546 | |
a79913eb FC |
547 | // Scan the candidate events and identify the "next" trace to read from |
548 | TmfEvent eventArray[] = expContext.getEvents(); | |
1324801a FC |
549 | if (eventArray == null) { |
550 | return null; | |
551 | } | |
a79913eb FC |
552 | int trace = TmfExperimentContext.NO_TRACE; |
553 | TmfTimestamp timestamp = TmfTimestamp.BigCrunch; | |
1324801a FC |
554 | if (eventArray.length == 1) { |
555 | if (eventArray[0] != null) { | |
556 | timestamp = eventArray[0].getTimestamp(); | |
557 | trace = 0; | |
558 | } | |
559 | } else { | |
560 | for (int i = 0; i < eventArray.length; i++) { | |
561 | TmfEvent event = eventArray[i]; | |
562 | if (event != null && event.getTimestamp() != null) { | |
563 | TmfTimestamp otherTS = event.getTimestamp(); | |
564 | if (otherTS.compareTo(timestamp, true) < 0) { | |
565 | trace = i; | |
566 | timestamp = otherTS; | |
567 | } | |
568 | } | |
569 | } | |
a79913eb | 570 | } |
1324801a | 571 | // Update the experiment context and set the "next" event |
a79913eb FC |
572 | TmfEvent event = null; |
573 | if (trace != TmfExperimentContext.NO_TRACE) { | |
574 | updateIndex(expContext, timestamp); | |
82e04272 | 575 | |
a79913eb FC |
576 | TmfContext traceContext = expContext.getContexts()[trace]; |
577 | TmfExperimentLocation expLocation = (TmfExperimentLocation) expContext.getLocation(); | |
64fe8e8a | 578 | // expLocation.getLocation()[trace] = traceContext.getLocation().clone(); |
a79913eb | 579 | expLocation.getLocation().locations[trace] = traceContext.getLocation(); |
82e04272 FC |
580 | |
581 | // updateIndex(expContext, timestamp); | |
582 | ||
a79913eb FC |
583 | expLocation.getRanks()[trace] = traceContext.getRank(); |
584 | expContext.setLastTrace(trace); | |
585 | expContext.updateRank(1); | |
586 | event = expContext.getEvents()[trace]; | |
587 | fExperimentContext = expContext; | |
588 | } | |
8f50c396 | 589 | |
9b635e61 FC |
590 | // if (event != null) { |
591 | // Tracer.trace("Exp: " + (expContext.getRank() - 1) + ": " + event.getTimestamp().toString()); | |
592 | // dumpContext(expContext, false); | |
593 | // Tracer.trace("Ctx: Event returned= " + event.getTimestamp().toString()); | |
594 | // } | |
595 | ||
a79913eb FC |
596 | return event; |
597 | } | |
598 | ||
599 | public synchronized void updateIndex(ITmfContext context, TmfTimestamp timestamp) { | |
600 | // Build the index as we go along | |
601 | long rank = context.getRank(); | |
602 | if (context.isValidRank() && (rank % fIndexPageSize) == 0) { | |
603 | // Determine the table position | |
604 | long position = rank / fIndexPageSize; | |
605 | // Add new entry at proper location (if empty) | |
606 | if (fCheckpoints.size() == position) { | |
607 | ITmfLocation<?> location = context.getLocation().clone(); | |
608 | fCheckpoints.add(new TmfCheckpoint(timestamp.clone(), location)); | |
d86b9d98 | 609 | // System.out.println(this + "[" + (fCheckpoints.size() - 1) + "] " + timestamp + ", " + location.toString()); |
a79913eb FC |
610 | } |
611 | } | |
612 | } | |
613 | ||
614 | /* | |
615 | * (non-Javadoc) | |
616 | * | |
617 | * @see | |
618 | * org.eclipse.linuxtools.tmf.trace.ITmfTrace#parseEvent(org.eclipse.linuxtools | |
619 | * .tmf.trace.TmfContext) | |
620 | */ | |
621 | @Override | |
622 | public TmfEvent parseEvent(TmfContext context) { | |
623 | ||
624 | // Validate the context | |
625 | if (!(context instanceof TmfExperimentContext)) { | |
626 | return null; // Throw an exception? | |
627 | } | |
628 | ||
629 | if (!context.equals(fExperimentContext)) { | |
9b635e61 | 630 | // Tracer.trace("Ctx: Restoring context"); |
a79913eb FC |
631 | seekLocation(context.getLocation()); |
632 | } | |
633 | ||
634 | TmfExperimentContext expContext = (TmfExperimentContext) context; | |
635 | ||
636 | // If an event was consumed previously, get the next one from that trace | |
637 | int lastTrace = expContext.getLastTrace(); | |
638 | if (lastTrace != TmfExperimentContext.NO_TRACE) { | |
639 | TmfContext traceContext = expContext.getContexts()[lastTrace]; | |
640 | expContext.getEvents()[lastTrace] = expContext.getTraces()[lastTrace].getNextEvent(traceContext); | |
641 | expContext.setLastTrace(TmfExperimentContext.NO_TRACE); | |
642 | fExperimentContext = (TmfExperimentContext) context; | |
643 | } | |
644 | ||
645 | // Scan the candidate events and identify the "next" trace to read from | |
646 | int trace = TmfExperimentContext.NO_TRACE; | |
647 | TmfTimestamp timestamp = TmfTimestamp.BigCrunch; | |
648 | for (int i = 0; i < expContext.getTraces().length; i++) { | |
649 | TmfEvent event = expContext.getEvents()[i]; | |
650 | if (event != null && event.getTimestamp() != null) { | |
651 | TmfTimestamp otherTS = event.getTimestamp(); | |
652 | if (otherTS.compareTo(timestamp, true) < 0) { | |
653 | trace = i; | |
654 | timestamp = otherTS; | |
655 | } | |
656 | } | |
657 | } | |
658 | ||
659 | TmfEvent event = null; | |
660 | if (trace != TmfExperimentContext.NO_TRACE) { | |
661 | event = expContext.getEvents()[trace]; | |
662 | } | |
663 | ||
664 | return event; | |
665 | } | |
666 | ||
667 | /* | |
668 | * (non-Javadoc) | |
669 | * | |
670 | * @see java.lang.Object#toString() | |
671 | */ | |
672 | @Override | |
3b38ea61 | 673 | @SuppressWarnings("nls") |
a79913eb FC |
674 | public String toString() { |
675 | return "[TmfExperiment (" + getName() + ")]"; | |
676 | } | |
8c8bf09f ASL |
677 | |
678 | // ------------------------------------------------------------------------ | |
679 | // Indexing | |
680 | // ------------------------------------------------------------------------ | |
681 | ||
a79913eb FC |
682 | /* |
683 | * The experiment holds the globally ordered events of its set of traces. It | |
684 | * is expected to provide access to each individual event by index i.e. it | |
685 | * must be possible to request the Nth event of the experiment. | |
686 | * | |
687 | * The purpose of the index is to keep the information needed to rapidly | |
688 | * restore the traces contexts at regular intervals (every INDEX_PAGE_SIZE | |
689 | * event). | |
690 | */ | |
8c8bf09f | 691 | |
a79913eb FC |
692 | // The index page size |
693 | private static final int DEFAULT_INDEX_PAGE_SIZE = 5000; | |
694 | protected int fIndexPageSize; | |
695 | protected boolean fIndexing = false; | |
696 | protected TmfTimeRange fIndexingPendingRange = TmfTimeRange.Null; | |
e31e01e8 | 697 | |
9b635e61 FC |
698 | // private static BufferedWriter fEventLog = null; |
699 | // private static BufferedWriter openLogFile(String filename) { | |
700 | // BufferedWriter outfile = null; | |
701 | // try { | |
702 | // outfile = new BufferedWriter(new FileWriter(filename)); | |
703 | // } catch (IOException e) { | |
704 | // e.printStackTrace(); | |
705 | // } | |
706 | // return outfile; | |
707 | // } | |
708 | ||
a79913eb FC |
709 | protected boolean isIndexingBusy() { |
710 | synchronized (fCheckpoints) { | |
711 | return fIndexing; | |
712 | } | |
713 | } | |
714 | ||
715 | protected void indexExperiment(boolean waitForCompletion) { | |
716 | indexExperiment(waitForCompletion, 0, TmfTimeRange.Eternity); | |
717 | } | |
718 | ||
719 | @SuppressWarnings("unchecked") | |
720 | protected void indexExperiment(boolean waitForCompletion, final int index, final TmfTimeRange timeRange) { | |
721 | ||
722 | synchronized (fCheckpoints) { | |
723 | if (fIndexing) { | |
724 | return; | |
725 | } | |
726 | fIndexing = true; | |
727 | } | |
728 | ||
729 | final Job job = new Job("Indexing " + getName() + "...") { //$NON-NLS-1$ //$NON-NLS-2$ | |
730 | @Override | |
731 | protected IStatus run(IProgressMonitor monitor) { | |
732 | while (!monitor.isCanceled()) { | |
733 | try { | |
734 | Thread.sleep(100); | |
735 | } catch (InterruptedException e) { | |
736 | return Status.OK_STATUS; | |
737 | } | |
738 | } | |
739 | monitor.done(); | |
740 | return Status.OK_STATUS; | |
741 | } | |
742 | }; | |
743 | job.schedule(); | |
744 | ||
9b635e61 | 745 | // fEventLog = openLogFile("TraceEvent.log"); |
82e04272 | 746 | // System.out.println(System.currentTimeMillis() + ": Experiment indexing started"); |
550d787e | 747 | |
a79913eb FC |
748 | ITmfEventRequest<TmfEvent> request = new TmfEventRequest<TmfEvent>(TmfEvent.class, timeRange, index, TmfDataRequest.ALL_DATA, fIndexPageSize, |
749 | ITmfDataRequest.ExecutionType.BACKGROUND) { // PATA FOREGROUND | |
550d787e | 750 | |
cb866e08 | 751 | // long indexingStart = System.nanoTime(); |
a79913eb FC |
752 | |
753 | TmfTimestamp startTime = (fTimeRange == TmfTimeRange.Null) ? null : fTimeRange.getStartTime(); | |
754 | TmfTimestamp lastTime = (fTimeRange == TmfTimeRange.Null) ? null : fTimeRange.getEndTime(); | |
755 | long initialNbEvents = fNbEvents; | |
756 | ||
757 | @Override | |
758 | public void handleStarted() { | |
759 | super.handleStarted(); | |
760 | } | |
761 | ||
762 | @Override | |
763 | public void handleData(TmfEvent event) { | |
764 | super.handleData(event); | |
765 | if (event != null) { | |
766 | TmfTimestamp ts = event.getTimestamp(); | |
767 | if (startTime == null) | |
768 | startTime = new TmfTimestamp(ts); | |
769 | lastTime = new TmfTimestamp(ts); | |
770 | if ((getNbRead() % fIndexPageSize) == 1 && getNbRead() != 1) { | |
771 | updateExperiment(); | |
772 | } | |
773 | } | |
774 | } | |
775 | ||
776 | @Override | |
777 | public void handleSuccess() { | |
9b635e61 FC |
778 | // long indexingEnd = System.nanoTime(); |
779 | ||
a79913eb FC |
780 | if (getRange() != TmfTimeRange.Eternity) { |
781 | lastTime = getRange().getEndTime(); | |
782 | } | |
783 | updateExperiment(); | |
9b635e61 | 784 | // System.out.println(System.currentTimeMillis() + ": Experiment indexing completed"); |
f9673903 | 785 | |
9b635e61 FC |
786 | // long average = (indexingEnd - indexingStart) / fNbEvents; |
787 | // System.out.println(getName() + ": start=" + startTime + ", end=" + lastTime + ", elapsed=" + (indexingEnd * 1.0 - indexingStart) / 1000000000); | |
788 | // System.out.println(getName() + ": nbEvents=" + fNbEvents + " (" + (average / 1000) + "." + (average % 1000) + " us/evt)"); | |
a79913eb FC |
789 | super.handleSuccess(); |
790 | } | |
e31e01e8 | 791 | |
05bd3318 FC |
792 | @Override |
793 | public void handleCompleted() { | |
794 | job.cancel(); | |
a79913eb FC |
795 | super.handleCompleted(); |
796 | synchronized (fCheckpoints) { | |
797 | fIndexing = false; | |
798 | if (fIndexingPendingRange != TmfTimeRange.Null) { | |
799 | indexExperiment(false, (int) fNbEvents, fIndexingPendingRange); | |
800 | fIndexingPendingRange = TmfTimeRange.Null; | |
801 | } | |
802 | } | |
05bd3318 FC |
803 | } |
804 | ||
a79913eb FC |
805 | private void updateExperiment() { |
806 | int nbRead = getNbRead(); | |
807 | if (nbRead != 0) { | |
0c2a2e08 FC |
808 | // updateTimeRange(); |
809 | // updateNbEvents(); | |
a79913eb FC |
810 | fTimeRange = new TmfTimeRange(startTime, new TmfTimestamp(lastTime)); |
811 | fNbEvents = initialNbEvents + nbRead; | |
812 | notifyListeners(); | |
813 | } | |
814 | } | |
815 | }; | |
816 | ||
817 | sendRequest((ITmfDataRequest<T>) request); | |
818 | if (waitForCompletion) | |
819 | try { | |
820 | request.waitForCompletion(); | |
821 | } catch (InterruptedException e) { | |
822 | e.printStackTrace(); | |
823 | } | |
824 | } | |
825 | ||
826 | protected void notifyListeners() { | |
827 | broadcast(new TmfExperimentUpdatedSignal(this, this)); // , null)); | |
828 | } | |
829 | ||
8c8bf09f ASL |
830 | // ------------------------------------------------------------------------ |
831 | // Signal handlers | |
832 | // ------------------------------------------------------------------------ | |
833 | ||
834 | @TmfSignalHandler | |
951d134a | 835 | public void experimentSelected(TmfExperimentSelectedSignal<T> signal) { |
a79913eb FC |
836 | TmfExperiment<?> experiment = signal.getExperiment(); |
837 | if (experiment == this) { | |
838 | setCurrentExperiment(experiment); | |
839 | indexExperiment(false); | |
840 | } else { | |
841 | dispose(); | |
842 | } | |
8c8bf09f ASL |
843 | } |
844 | ||
845 | @TmfSignalHandler | |
846 | public void experimentUpdated(TmfExperimentUpdatedSignal signal) { | |
8c8bf09f ASL |
847 | } |
848 | ||
849 | @TmfSignalHandler | |
850 | public void traceUpdated(TmfTraceUpdatedSignal signal) { | |
a79913eb FC |
851 | for (ITmfTrace trace : fTraces) { |
852 | if (trace == signal.getTrace()) { | |
853 | synchronized (fCheckpoints) { | |
854 | if (fIndexing) { | |
855 | if (fIndexingPendingRange == TmfTimeRange.Null) { | |
856 | fIndexingPendingRange = signal.getRange(); | |
857 | } else { | |
858 | TmfTimestamp startTime = fIndexingPendingRange.getStartTime(); | |
859 | TmfTimestamp endTime = fIndexingPendingRange.getEndTime(); | |
860 | if (signal.getRange().getStartTime().compareTo(startTime) < 0) { | |
861 | startTime = signal.getRange().getStartTime(); | |
862 | } | |
863 | if (signal.getRange().getEndTime().compareTo(endTime) > 0) { | |
864 | endTime = signal.getRange().getEndTime(); | |
865 | } | |
866 | fIndexingPendingRange = new TmfTimeRange(startTime, endTime); | |
867 | } | |
868 | return; | |
869 | } | |
870 | } | |
871 | indexExperiment(false, (int) fNbEvents, signal.getRange()); | |
872 | return; | |
873 | } | |
874 | } | |
8c8bf09f ASL |
875 | } |
876 | ||
a79913eb | 877 | } |