b5fdd8dea89d8713c38a067b45b1c18c63d0796d
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf / src / org / eclipse / linuxtools / tmf / trace / TmfTrace.java
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.trace;
14
15 import java.io.File;
16 import java.io.FileNotFoundException;
17 import java.util.Collections;
18 import java.util.Vector;
19
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;
24 import org.eclipse.linuxtools.tmf.component.TmfEventProvider;
25 import org.eclipse.linuxtools.tmf.event.TmfEvent;
26 import org.eclipse.linuxtools.tmf.event.TmfTimeRange;
27 import org.eclipse.linuxtools.tmf.event.TmfTimestamp;
28 import org.eclipse.linuxtools.tmf.request.ITmfDataRequest;
29 import org.eclipse.linuxtools.tmf.request.ITmfEventRequest;
30 import org.eclipse.linuxtools.tmf.signal.TmfTraceUpdatedSignal;
31
32 /**
33 * <b><u>TmfTrace</u></b>
34 * <p>
35 * Abstract implementation of ITmfTrace. It should be sufficient to extend this
36 * class and provide implementation for <code>getCurrentLocation()</code> and
37 * <code>seekLocation()</code>, as well as a proper parser, to have a working
38 * concrete implementation.
39 * <p>
40 * Note: The notion of event rank is still under heavy discussion. Although
41 * used by the Events View and probably useful in the general case, there
42 * is no easy way to implement it for LTTng (actually a strong case is being
43 * made that this is useless).
44 * <p>
45 * That it is not supported by LTTng does by no mean indicate that it is not
46 * useful for (just about) every other tracing tool. Therefore, this class
47 * provides a minimal (and partial) implementation of rank. However, the current
48 * implementation should not be relied on in the general case.
49 *
50 * TODO: Add support for live streaming (notifications, incremental indexing, ...)
51 */
52 public abstract class TmfTrace<T extends TmfEvent> extends TmfEventProvider<T> implements ITmfTrace, Cloneable {
53
54 // ------------------------------------------------------------------------
55 // Constants
56 // ------------------------------------------------------------------------
57
58 // The default number of events to cache
59 // TODO: Make the DEFAULT_CACHE_SIZE a preference
60 public static final int DEFAULT_CACHE_SIZE = 1000;
61
62 // ------------------------------------------------------------------------
63 // Attributes
64 // ------------------------------------------------------------------------
65
66 // The trace path
67 private final String fPath;
68
69 // The trace name
70 private final String fName;
71
72 // The cache page size AND checkpoints interval
73 protected int fIndexPageSize;
74
75 // The set of event stream checkpoints (for random access)
76 protected Vector<TmfCheckpoint> fCheckpoints = new Vector<TmfCheckpoint>();
77
78 // The number of events collected
79 protected long fNbEvents = 0;
80
81 // The time span of the event stream
82 private TmfTimeRange fTimeRange = new TmfTimeRange(TmfTimestamp.BigBang, TmfTimestamp.BigBang);
83
84 // ------------------------------------------------------------------------
85 // Constructors
86 // ------------------------------------------------------------------------
87
88 /**
89 * @param path
90 * @throws FileNotFoundException
91 */
92 protected TmfTrace(Class<T> type, String path) throws FileNotFoundException {
93 this(type, path, DEFAULT_CACHE_SIZE);
94 }
95
96 /**
97 * @param path
98 * @param cacheSize
99 * @throws FileNotFoundException
100 */
101 protected TmfTrace(Class<T> type, String path, int cacheSize) throws FileNotFoundException {
102 super(type);
103 int sep = path.lastIndexOf(File.separator);
104 fName = (sep >= 0) ? path.substring(sep + 1) : path;
105 fPath = path;
106 fIndexPageSize = (cacheSize > 0) ? cacheSize : DEFAULT_CACHE_SIZE;
107 }
108
109 /* (non-Javadoc)
110 * @see java.lang.Object#clone()
111 */
112 @SuppressWarnings("unchecked")
113 @Override
114 public TmfTrace<T> clone() throws CloneNotSupportedException {
115 TmfTrace<T> clone = (TmfTrace<T>) super.clone();
116 clone.fCheckpoints = (Vector<TmfCheckpoint>) fCheckpoints.clone();
117 clone.fTimeRange = new TmfTimeRange(fTimeRange);
118 return clone;
119 }
120
121 // ------------------------------------------------------------------------
122 // Accessors
123 // ------------------------------------------------------------------------
124
125 /**
126 * @return the trace path
127 */
128 public String getPath() {
129 return fPath;
130 }
131
132 /**
133 * @return the trace name
134 */
135 @Override
136 public String getName() {
137 return fName;
138 }
139
140 /* (non-Javadoc)
141 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getNbEvents()
142 */
143 public long getNbEvents() {
144 return fNbEvents;
145 }
146
147 /**
148 * @return the size of the cache
149 */
150 public int getCacheSize() {
151 return fIndexPageSize;
152 }
153
154 /* (non-Javadoc)
155 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getTimeRange()
156 */
157 public TmfTimeRange getTimeRange() {
158 return fTimeRange;
159 }
160
161 /* (non-Javadoc)
162 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStartTime()
163 */
164 public TmfTimestamp getStartTime() {
165 return fTimeRange.getStartTime();
166 }
167
168 /* (non-Javadoc)
169 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getEndTime()
170 */
171 public TmfTimestamp getEndTime() {
172 return fTimeRange.getEndTime();
173 }
174
175 @SuppressWarnings("unchecked")
176 public Vector<TmfCheckpoint> getCheckpoints() {
177 return (Vector<TmfCheckpoint>) fCheckpoints.clone();
178 }
179
180 // ------------------------------------------------------------------------
181 // Operators
182 // ------------------------------------------------------------------------
183
184 protected void setTimeRange(TmfTimeRange range) {
185 fTimeRange = range;
186 }
187
188 protected void setStartTime(TmfTimestamp startTime) {
189 fTimeRange = new TmfTimeRange(startTime, fTimeRange.getEndTime());
190 }
191
192 protected void setEndTime(TmfTimestamp endTime) {
193 fTimeRange = new TmfTimeRange(fTimeRange.getStartTime(), endTime);
194 }
195
196 // ------------------------------------------------------------------------
197 // TmfProvider
198 // ------------------------------------------------------------------------
199
200 @Override
201 public ITmfContext armRequest(ITmfDataRequest<T> request) {
202 if (request instanceof ITmfEventRequest<?>) {
203 return seekEvent(((ITmfEventRequest<T>) request).getRange().getStartTime());
204 }
205 return seekEvent(request.getIndex());
206 }
207
208 /**
209 * Return the next piece of data based on the context supplied. The context
210 * would typically be updated for the subsequent read.
211 *
212 * @param context
213 * @return
214 */
215 @SuppressWarnings("unchecked")
216 @Override
217 public T getNext(ITmfContext context) {
218 if (context instanceof TmfContext) {
219 return (T) getNextEvent((TmfContext) context);
220 }
221 return null;
222 }
223
224 // ------------------------------------------------------------------------
225 // ITmfTrace
226 // ------------------------------------------------------------------------
227
228 /* (non-Javadoc)
229 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.event.TmfTimestamp)
230 */
231 public TmfContext seekEvent(TmfTimestamp timestamp) {
232
233 if (timestamp == null) {
234 timestamp = TmfTimestamp.BigBang;
235 }
236
237 // First, find the right checkpoint
238 int index = Collections.binarySearch(fCheckpoints, new TmfCheckpoint(timestamp, null));
239
240 // In the very likely case that the checkpoint was not found, bsearch
241 // returns its negated would-be location (not an offset...). From that
242 // index, we can then position the stream and get the event.
243 if (index < 0) {
244 index = Math.max(0, -(index + 2));
245 }
246
247 // Position the stream at the checkpoint
248 ITmfLocation<?> location;
249 synchronized (fCheckpoints) {
250 if (fCheckpoints.size() > 0) {
251 if (index >= fCheckpoints.size()) {
252 index = fCheckpoints.size() - 1;
253 }
254 location = fCheckpoints.elementAt(index).getLocation();
255 }
256 else {
257 location = null;
258 }
259 }
260 TmfContext context = seekLocation(location);
261 context.setRank(index * fIndexPageSize);
262
263 // And locate the event
264 TmfContext nextEventContext = context.clone(); // Must use clone() to get the right subtype...
265 TmfEvent event = getNextEvent(nextEventContext);
266 while (event != null && event.getTimestamp().compareTo(timestamp, false) < 0) {
267 context.setLocation(nextEventContext.getLocation().clone());
268 context.updateRank(1);
269 event = getNextEvent(nextEventContext);
270 }
271
272 return context;
273 }
274
275 /* (non-Javadoc)
276 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(int)
277 */
278 public TmfContext seekEvent(long rank) {
279
280 // Position the stream at the previous checkpoint
281 int index = (int) rank / fIndexPageSize;
282 ITmfLocation<?> location;
283 synchronized (fCheckpoints) {
284 if (fCheckpoints.size() == 0) {
285 location = null;
286 }
287 else {
288 if (index >= fCheckpoints.size()) {
289 index = fCheckpoints.size() - 1;
290 }
291 location = fCheckpoints.elementAt(index).getLocation();
292 }
293 }
294
295 TmfContext context = seekLocation(location);
296 long pos = index * fIndexPageSize;
297 context.setRank(pos);
298
299 if (pos < rank) {
300 TmfEvent event = getNextEvent(context);
301 while (event != null && ++pos < rank) {
302 event = getNextEvent(context);
303 }
304 }
305
306 return context;
307 }
308
309 /* (non-Javadoc)
310 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getNextEvent(org.eclipse.linuxtools.tmf.trace.ITmfTrace.TraceContext)
311 */
312 public synchronized TmfEvent getNextEvent(TmfContext context) {
313 // parseEvent() does not update the context
314 TmfEvent event = parseEvent(context);
315 if (event != null) {
316 context.setLocation(getCurrentLocation());
317 context.updateRank(1);
318 processEvent(event);
319 }
320 return event;
321 }
322
323 /**
324 * Hook for "special" processing by the concrete class
325 * (called by getNextEvent())
326 *
327 * @param event
328 */
329 protected void processEvent(TmfEvent event) {
330 // Do nothing by default
331 }
332
333 /**
334 * To be implemented by the concrete class
335 */
336 public abstract TmfContext seekLocation(ITmfLocation<?> location);
337 public abstract ITmfLocation<?> getCurrentLocation();
338 public abstract TmfEvent parseEvent(TmfContext context);
339
340 // ------------------------------------------------------------------------
341 // toString
342 // ------------------------------------------------------------------------
343
344 /* (non-Javadoc)
345 * @see java.lang.Object#toString()
346 */
347 @Override
348 public String toString() {
349 return "[TmfTrace (" + fName + ")]";
350 }
351
352 // ------------------------------------------------------------------------
353 // Indexing
354 // ------------------------------------------------------------------------
355
356 /*
357 * The purpose of the index is to perform a pass over the trace and collect
358 * basic information that can be later used to rapidly access a trace events.
359 *
360 * The information collected:
361 * - fCheckpoints, the list of evenly separated checkpoints (timestamp + location)
362 * - fTimeRange, the trace time span
363 * - fNbEvents, the number of events in the trace
364 *
365 * NOTE: Doesn't work for streaming traces.
366 */
367
368 private IndexingJob job;
369
370 // Indicates that an indexing job is already running
371 private boolean fIndexing = false;
372 private Boolean fIndexed = false;
373
374 public void indexTrace(boolean waitForCompletion) {
375 synchronized (this) {
376 if (fIndexed || fIndexing) {
377 return;
378 }
379 fIndexing = true;
380 }
381
382 job = new IndexingJob("Indexing " + fName);
383 job.schedule();
384
385 if (waitForCompletion) {
386 try {
387 job.join();
388 } catch (InterruptedException e) {
389 e.printStackTrace();
390 }
391 }
392 }
393
394 private class IndexingJob extends Job {
395
396 public IndexingJob(String name) {
397 super(name);
398 }
399
400 /* (non-Javadoc)
401 * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
402 */
403 @Override
404 protected IStatus run(IProgressMonitor monitor) {
405
406 monitor.beginTask("Indexing " + fName, IProgressMonitor.UNKNOWN);
407
408 int nbEvents = 0;
409 TmfTimestamp startTime = null;
410 TmfTimestamp lastTime = null;
411
412 // Reset the index
413 fCheckpoints = new Vector<TmfCheckpoint>();
414
415 try {
416 // Position the trace at the beginning
417 TmfContext context = seekLocation(null);
418 ITmfLocation<?> location = context.getLocation().clone();
419
420 // Get the first event
421 TmfEvent event = getNextEvent(context);
422 if (event != null) {
423 startTime = new TmfTimestamp(event.getTimestamp());
424 }
425
426 // Index the trace
427 while (event != null) {
428 lastTime = event.getTimestamp();
429 if ((nbEvents++ % fIndexPageSize) == 0) {
430 lastTime = new TmfTimestamp(event.getTimestamp());
431 fCheckpoints.add(new TmfCheckpoint(lastTime, location));
432
433 monitor.worked(1);
434
435 // Check monitor *after* fCheckpoints has been updated
436 if (monitor.isCanceled()) {
437 monitor.done();
438 return Status.CANCEL_STATUS;
439 }
440 }
441
442 // We will need this location at the next iteration
443 if ((nbEvents % fIndexPageSize) == 0) {
444 location = context.getLocation().clone();
445 }
446
447 event = getNextEvent(context);
448 }
449 }
450 finally {
451 synchronized(this) {
452 fNbEvents = nbEvents;
453 fTimeRange = new TmfTimeRange(startTime, lastTime);
454 fIndexing = false;
455 fIndexed = true;
456 }
457 notifyListeners(fTimeRange);
458 monitor.done();
459 }
460
461 return Status.OK_STATUS;
462 }
463 }
464
465 protected void notifyListeners(TmfTimeRange range) {
466 broadcast(new TmfTraceUpdatedSignal(this, this, range));
467 }
468
469 }
This page took 0.040723 seconds and 4 git commands to generate.