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