[Bug293101] Context menu fix: removed the unimplemented menu choices and enabled...
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf / src / org / eclipse / linuxtools / tmf / experiment / TmfExperiment.java
CommitLineData
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
13package org.eclipse.linuxtools.tmf.experiment;
14
8c8bf09f
ASL
15import java.util.Vector;
16
e31e01e8
FC
17import org.eclipse.core.runtime.IProgressMonitor;
18import org.eclipse.core.runtime.IStatus;
19import org.eclipse.core.runtime.Status;
20import org.eclipse.core.runtime.jobs.Job;
21import org.eclipse.linuxtools.tmf.component.ITmfContext;
22import org.eclipse.linuxtools.tmf.component.TmfProvider;
8c8bf09f
ASL
23import org.eclipse.linuxtools.tmf.event.TmfEvent;
24import org.eclipse.linuxtools.tmf.event.TmfTimeRange;
25import org.eclipse.linuxtools.tmf.event.TmfTimestamp;
9aae0442
ASL
26import org.eclipse.linuxtools.tmf.request.TmfDataRequest;
27import org.eclipse.linuxtools.tmf.request.TmfEventRequest;
8c8bf09f 28import org.eclipse.linuxtools.tmf.signal.TmfSignalHandler;
8c8bf09f 29import org.eclipse.linuxtools.tmf.trace.ITmfTrace;
e31e01e8
FC
30import org.eclipse.linuxtools.tmf.trace.TmfTraceContext;
31import org.eclipse.linuxtools.tmf.trace.TmfTraceUpdatedSignal;
8c8bf09f
ASL
32
33/**
34 * <b><u>TmfExperiment</u></b>
35 * <p>
36 * TmfExperiment presents a time-ordered, unified view of a set of TmfTraces
37 * that are part of a tracing experiment.
38 * <p>
39 */
e31e01e8
FC
40public class TmfExperiment<T extends TmfEvent> extends TmfProvider<T> {
41
42// TODO: Complete multi-trace experiment
43// TODO: Add support for dynamic addition/removal of traces
44// TODO: Add support for live streaming (notifications, incremental indexing, ...)
45// TODO: Implement indexing-on-demand
8c8bf09f
ASL
46
47 // ------------------------------------------------------------------------
48 // Attributes
49 // ------------------------------------------------------------------------
50
51 // The currently selected experiment
e31e01e8
FC
52 private static TmfExperiment<?> fCurrentExperiment;
53
54 // The experiment ID
55 private String fExperimentId;
8c8bf09f 56
e31e01e8
FC
57 // The set of trace sthat constitute the experiment
58 private Vector<ITmfTrace> fTraces;
8c8bf09f
ASL
59
60 // The total number of events
e31e01e8 61 private int fNbEvents;
8c8bf09f
ASL
62
63 // The experiment time range
64 private TmfTimeRange fTimeRange;
65
66 // The experiment reference timestamp (default: BigBang)
67 private TmfTimestamp fEpoch;
68
8c8bf09f
ASL
69 // ------------------------------------------------------------------------
70 // Constructors
71 // ------------------------------------------------------------------------
72
73 /**
74 * @param type
75 * @param id
76 * @param traces
77 * @param epoch
78 * @param indexPageSize
79 */
80 public TmfExperiment(Class<T> type, String id, ITmfTrace[] traces, TmfTimestamp epoch, int indexPageSize) {
e31e01e8 81 super(type);
8c8bf09f 82
e31e01e8
FC
83 fExperimentId = id;
84 fTraces = new Vector<ITmfTrace>();
85 for (ITmfTrace trace : traces) {
86 fTraces.add(trace);
87 }
8c8bf09f
ASL
88 fEpoch = epoch;
89 fIndexPageSize = indexPageSize;
90
91 updateNbEvents();
92 updateTimeRange();
e31e01e8 93 }
8c8bf09f
ASL
94
95 /**
96 * @param type
97 * @param id
98 * @param traces
99 */
100 public TmfExperiment(Class<T> type, String id, ITmfTrace[] traces) {
101 this(type, id, traces, TmfTimestamp.Zero, DEFAULT_INDEX_PAGE_SIZE);
102 }
103
104 /**
105 * @param type
106 * @param id
107 * @param traces
108 * @param indexPageSize
109 */
110 public TmfExperiment(Class<T> type, String id, ITmfTrace[] traces, int indexPageSize) {
111 this(type, id, traces, TmfTimestamp.Zero, indexPageSize);
112 }
e31e01e8 113
8c8bf09f 114 /**
e31e01e8 115 *
8c8bf09f
ASL
116 */
117 @Override
e31e01e8
FC
118 public void deregister() {
119 fTraces.clear();
120 fCurrentExperiment= null;
121 super.deregister();
8c8bf09f
ASL
122 }
123
124 // ------------------------------------------------------------------------
e31e01e8 125 // Accessors
8c8bf09f
ASL
126 // ------------------------------------------------------------------------
127
e31e01e8
FC
128 public static TmfExperiment<?> getCurrentExperiment() {
129 return fCurrentExperiment;
8c8bf09f
ASL
130 }
131
e31e01e8
FC
132 public String getExperimentId() {
133 return fExperimentId;
8c8bf09f
ASL
134 }
135
e31e01e8
FC
136 public ITmfTrace[] getTraces() {
137 ITmfTrace[] result = new ITmfTrace[fTraces.size()];
138 return fTraces.toArray(result);
8c8bf09f
ASL
139 }
140
141 public TmfTimestamp getEpoch() {
142 return fEpoch;
143 }
144
e31e01e8
FC
145 public TmfTimeRange getTimeRange() {
146 return fTimeRange;
147 }
148
149 public int getNbEvents() {
150 return fNbEvents;
8c8bf09f
ASL
151 }
152
153 /**
154 * Returns the rank of the first event with the requested timestamp.
155 * If none, returns the index of the next event (if any).
156 *
e31e01e8 157 * @param ts
8c8bf09f
ASL
158 * @return
159 */
e31e01e8
FC
160 public long getRank(TmfTimestamp ts) {
161 // FIXME: Go over all the traces
162 ITmfTrace trace = fTraces.firstElement();
163 TmfTraceContext context = trace.seekEvent(ts);
8c8bf09f
ASL
164 return context.getRank();
165 }
166
167 /**
168 * Returns the timestamp of the event at the requested index.
169 * If none, returns null.
170 *
171 * @param index
172 * @return
173 */
174 public TmfTimestamp getTimestamp(int index) {
e31e01e8
FC
175 // FIXME: Go over all the traces
176 ITmfTrace trace = fTraces.firstElement();
177 TmfTraceContext context = trace.seekEvent(index);
178 TmfEvent event = trace.getNextEvent(context);
179 TmfTimestamp ts = (event != null) ? event.getTimestamp() : null;
180 return ts;
8c8bf09f
ASL
181 }
182
183 // ------------------------------------------------------------------------
184 // Operators
185 // ------------------------------------------------------------------------
186
e31e01e8
FC
187 /**
188 * Add a trace to the experiment trace set
189 *
190 * @param trace
191 */
192 public void addTrace(ITmfTrace trace) {
193 fTraces.add(trace);
194 synchronized(this) {
195 updateNbEvents();
196 updateTimeRange();
197 }
198 }
199
8c8bf09f
ASL
200 /**
201 * Update the total number of events
202 */
203 private void updateNbEvents() {
204 int nbEvents = 0;
205 for (ITmfTrace trace : fTraces) {
206 nbEvents += trace.getNbEvents();
207 }
208 fNbEvents = nbEvents;
209 }
210
211 /**
212 * Update the global time range
213 */
214 private void updateTimeRange() {
215 TmfTimestamp startTime = fTimeRange != null ? fTimeRange.getStartTime() : TmfTimestamp.BigCrunch;
216 TmfTimestamp endTime = fTimeRange != null ? fTimeRange.getEndTime() : TmfTimestamp.BigBang;
217
218 for (ITmfTrace trace : fTraces) {
e31e01e8
FC
219 TmfTimestamp traceStartTime = trace.getStartTime();
220 if (traceStartTime.compareTo(startTime, true) < 0)
221 startTime = traceStartTime;
222
223 TmfTimestamp traceEndTime = trace.getEndTime();
224 if (traceEndTime.compareTo(endTime, true) > 0)
225 endTime = traceEndTime;
8c8bf09f
ASL
226 }
227 fTimeRange = new TmfTimeRange(startTime, endTime);
228 }
229
230 // ------------------------------------------------------------------------
231 // TmfProvider
232 // ------------------------------------------------------------------------
233
234 @Override
e31e01e8
FC
235 public ITmfContext setContext(TmfDataRequest<T> request) {
236 TmfExperimentContext context = new TmfExperimentContext(fTraces);
237 positionTraces(request.getIndex(), context);
8c8bf09f
ASL
238 return context;
239 }
240
241 @SuppressWarnings("unchecked")
242 @Override
243 public T getNext(ITmfContext context) {
244 if (context instanceof TmfExperimentContext) {
245 return (T) getNextEvent((TmfExperimentContext) context);
246 }
247 return null;
248 }
249
e31e01e8
FC
250 @Override
251 public boolean isCompleted(TmfDataRequest<T> request, T data) {
252 if (request instanceof TmfEventRequest<?> && data != null) {
253 return data.getTimestamp().compareTo(((TmfEventRequest<T>) request).getRange().getEndTime(), false) > 0;
8c8bf09f 254 }
e31e01e8 255 return false;
8c8bf09f
ASL
256 }
257
e31e01e8
FC
258 /**
259 * Given an experiment event index, position the set of traces so a call
260 * to getNextEvent() will retrieve the corresponding event.
261 *
262 * @param index
263 * @param context
8c8bf09f 264 */
e31e01e8 265 private synchronized void positionTraces(long index, TmfExperimentContext context) {
8c8bf09f 266
e31e01e8
FC
267 // Extract the relevant information
268 ITmfTrace[] traces = context.getTraces();
269 TmfEvent[] events = context.getEvents();
270 TmfTraceContext[] contexts = context.getContexts();
8c8bf09f 271
e31e01e8
FC
272 int page = 0; // The checkpoint page
273 int current = 0; // The current event index (rank)
8c8bf09f 274
e31e01e8
FC
275 // If there is no checkpoint created yet, start from the beginning
276 if (fExperimentIndex.size() == 0) {
277 for (int i = 0; i < contexts.length; i++) {
278 contexts[i] = traces[i].seekLocation(null).clone();
279 events[i] = traces[i].parseEvent(contexts[i]);
280 }
281 }
282 else {
283 page = (int) index / fIndexPageSize;
284 if (page >= fExperimentIndex.size()) {
285 page = fExperimentIndex.size() - 1;
286 }
287
288 TmfTraceContext[] checkpoint = fExperimentIndex.elementAt(page).getContexts();
289 for (int i = 0; i < contexts.length; i++) {
290 contexts[i] = checkpoint[i].clone();
291 events[i] = traces[i].parseEvent(contexts[i]);
292 }
293 current = page * fIndexPageSize;
294 }
295
296 // Position the traces at the requested index
297 while (current++ < index) {
298 getNextEvent(context);
299 }
8c8bf09f
ASL
300 }
301
302 /**
303 * Scan the next events from all traces and return the next one
304 * in chronological order.
305 *
306 * @param context
307 * @return
308 */
e31e01e8
FC
309 private TmfEvent getNextEvent(TmfExperimentContext context) {
310 // TODO: Consider the time adjustment
311 int trace = 0;
8c8bf09f 312 TmfTimestamp timestamp = TmfTimestamp.BigCrunch;
e31e01e8
FC
313 if (context.getEvents()[trace] != null) {
314 timestamp = context.getEvents()[trace].getTimestamp();
315 }
316 for (int i = 1; i < context.getTraces().length; i++) {
317 if (context.getEvents()[i].getTimestamp() != null) {
318 TmfTimestamp otherTS = context.getEvents()[i].getTimestamp();
8c8bf09f
ASL
319 if (otherTS.compareTo(timestamp, true) < 0) {
320 trace = i;
321 timestamp = otherTS;
322 }
323 }
324 }
e31e01e8
FC
325 TmfEvent event = context.getTraces()[trace].getNextEvent(context.getContexts()[trace]);
326 context.getEvents()[trace] = context.getTraces()[trace].parseEvent(context.getContexts()[trace]);
8c8bf09f
ASL
327 return event;
328 }
329
e31e01e8
FC
330 /**
331 * Scan the next events from all traces and return the next one
332 * in chronological order.
333 *
334 * @param context
335 * @return
8c8bf09f 336 */
e31e01e8
FC
337 private TmfTimestamp getNextEventTimestamp(TmfExperimentContext context) {
338 // TODO: Consider the time adjustment
339 int trace = 0;
340 TmfTimestamp timestamp = TmfTimestamp.BigCrunch;
341 if (context.getEvents()[trace] != null) {
342 timestamp = context.getEvents()[trace].getTimestamp();
343 }
344 for (int i = 1; i < context.getTraces().length; i++) {
345 if (context.getEvents()[i].getTimestamp() != null) {
346 TmfTimestamp otherTS = context.getEvents()[i].getTimestamp();
347 if (otherTS.compareTo(timestamp, true) < 0) {
348 trace = i;
349 timestamp = otherTS;
8c8bf09f
ASL
350 }
351 }
8c8bf09f 352 }
e31e01e8 353 return timestamp;
8c8bf09f
ASL
354 }
355
356 /* (non-Javadoc)
357 * @see java.lang.Object#toString()
358 */
359 @Override
360 public String toString() {
e31e01e8 361 return "[TmfExperiment (" + fExperimentId + ")]";
8c8bf09f
ASL
362 }
363
364 // ------------------------------------------------------------------------
365 // Indexing
366 // ------------------------------------------------------------------------
367
368 /*
369 * The experiment holds the globally ordered events of its set of traces.
370 * It is expected to provide access to each individual event by index i.e.
e31e01e8 371 * it must be possible to request the nth event of the experiment.
8c8bf09f
ASL
372 *
373 * The purpose of the index is to keep the information needed to rapidly
374 * restore the traces contexts at regular intervals (every INDEX_PAGE_SIZE
375 * event).
376 */
377
378 // The index page size
379 private static final int DEFAULT_INDEX_PAGE_SIZE = 1000;
e31e01e8 380 private final int fIndexPageSize;
8c8bf09f 381
e31e01e8
FC
382 // The experiment index
383 private Vector<TmfExperimentCheckpoint> fExperimentIndex = new Vector<TmfExperimentCheckpoint>();
8c8bf09f 384
e31e01e8
FC
385 // Indicates that an indexing job is already running
386 private Boolean fIndexing = false;
387 private Boolean fIndexed = false;
8c8bf09f 388
e31e01e8
FC
389 // The indexing job
390 private IndexingJob job;
391
392 /**
393 * indexExperiment
394 *
395 * Creates the experiment index.
396 */
397 public void indexExperiment(boolean waitForCompletion) {
398
399 synchronized(fIndexing) {
400 if (fIndexed || fIndexing) {
401 // An indexing job is already running but a new request came
402 // in (probably due to a change in the trace set). The index
403 // being currently built is therefore already invalid.
404 // TODO: Cancel and restart the job
405 // TODO: Add support for dynamically adding/removing traces
406 return;
9aae0442 407 }
e31e01e8
FC
408 fIndexing = true;
409 }
8c8bf09f 410
e31e01e8
FC
411 job = new IndexingJob(fExperimentId);
412 job.schedule();
413
414 if (waitForCompletion) {
415 try {
416 job.join();
417 } catch (InterruptedException e) {
418 e.printStackTrace();
419 }
420 }
8c8bf09f 421 }
e31e01e8
FC
422
423 private class IndexingJob extends Job {
424
425 public IndexingJob(String name) {
426 super(name);
427 }
428
429 /* (non-Javadoc)
430 * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
431 */
432 @Override
433 protected IStatus run(IProgressMonitor monitor) {
434
435 // Minimal check
436 if (fTraces.size() == 0) {
437 fIndexing = false;
438 return Status.OK_STATUS;
439 }
440
441 monitor.beginTask("Indexing " + fExperimentId, IProgressMonitor.UNKNOWN);
442
443 int nbEvents = 0;
444 TmfTimestamp startTime = null;
445 TmfTimestamp lastTime = null;
446
447 fExperimentIndex = new Vector<TmfExperimentCheckpoint>();
448
449 try {
450 // Reset the traces
451 TmfExperimentContext context = new TmfExperimentContext(fTraces);
452 positionTraces(0, context);
453 TmfTraceContext[] traces = context.cloneContexts();
454
455 TmfTimestamp timestamp = getNextEventTimestamp(context);
456 startTime = new TmfTimestamp(timestamp);
457 lastTime = new TmfTimestamp(timestamp);
458 TmfEvent event = getNextEvent(context);
459 while (event != null) {
460 if ((nbEvents++ % fIndexPageSize) == 0) {
461 fExperimentIndex.add(new TmfExperimentCheckpoint(lastTime, traces));
462 fNbEvents = nbEvents;
463 fTimeRange = new TmfTimeRange(startTime, lastTime);
464
465 monitor.worked(1);
466
467 // Check monitor *after* fCheckpoints has been updated
468 if (monitor.isCanceled()) {
469 monitor.done();
470 return Status.CANCEL_STATUS;
471 }
472 }
473
474 // We will need the contexts at the next iteration
475 if ((nbEvents % fIndexPageSize) == 0) {
476 traces = context.cloneContexts();
477 lastTime = new TmfTimestamp(event.getTimestamp());
478 }
479
480 event = getNextEvent(context);
481 }
482
483 }
484 finally {
485 synchronized(this) {
486 fNbEvents = nbEvents;
487 fTimeRange = new TmfTimeRange(startTime, lastTime);
488 fIndexing = false;
489 fIndexed = true;
490 }
491 monitor.done();
492 }
493
494// dumpExperimentCheckpoints();
495
496 return Status.OK_STATUS;
497 }
498 }
499
500// // ------------------------------------------------------------------------
501// // Toubleshooting code
502// // ------------------------------------------------------------------------
503//
504// private void dumpExperimentCheckpoints() {
505// System.out.println("-----");
506// System.out.println("Checkpoints of " + fExperimentId);
507// for (int i = 0; i < fExperimentIndex.size(); i++) {
508// System.out.println("Entry:" + i);
509// TmfExperimentCheckpoint checkpoint = fExperimentIndex.get(i);
510// TmfTraceContext[] contexts = checkpoint.getContexts();
511// for (int j = 0; j < contexts.length; j++) {
512// ITmfTrace trace = fTraces.get(j);
513// TmfTraceContext context = trace.seekLocation(contexts[j].getLocation());
514// TmfEvent event = fTraces.get(j).getNextEvent(new TmfTraceContext(context));
515// System.out.println(" [" + trace.getName() + "] rank: " + context.getRank() + ", timestamp: " + event.getTimestamp());
516// assert (checkpoint.getTimestamp().compareTo(event.getTimestamp(), false) == 0);
517// }
518// }
519// }
520
8c8bf09f
ASL
521 // ------------------------------------------------------------------------
522 // Signal handlers
523 // ------------------------------------------------------------------------
524
525 @TmfSignalHandler
e31e01e8
FC
526 public void experimentSelected(TmfExperimentSelectedSignal signal) {
527 fCurrentExperiment = signal.getExperiment();
528// if (signal.getExperiment() == this) {
529// indexExperiment(true);
530// }
8c8bf09f
ASL
531 }
532
533 @TmfSignalHandler
534 public void experimentUpdated(TmfExperimentUpdatedSignal signal) {
e31e01e8 535// indexExperiment(true);
8c8bf09f
ASL
536 }
537
538 @TmfSignalHandler
539 public void traceUpdated(TmfTraceUpdatedSignal signal) {
540 // TODO: Incremental index update
541 synchronized(this) {
542 updateNbEvents();
543 updateTimeRange();
544 }
545 broadcast(new TmfExperimentUpdatedSignal(this, this, signal.getTrace()));
546 }
547
548}
This page took 0.048994 seconds and 5 git commands to generate.