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