2010-09-15 Francois Chouinard <fchouinard@gmail.com> Contribution for Bug287563
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf / src / org / eclipse / linuxtools / tmf / trace / TmfTrace.java
CommitLineData
8c8bf09f 1/*******************************************************************************
e31e01e8 2 * Copyright (c) 2009, 2010 Ericsson
8c8bf09f
ASL
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.trace;
14
b0a282fb 15import java.io.File;
62d1696a 16import java.io.FileNotFoundException;
62d1696a 17import java.util.Collections;
8c8bf09f
ASL
18import java.util.Vector;
19
fc6ccf6f 20import org.eclipse.linuxtools.tmf.component.TmfEventProvider;
8c8bf09f
ASL
21import org.eclipse.linuxtools.tmf.event.TmfEvent;
22import org.eclipse.linuxtools.tmf.event.TmfTimeRange;
23import org.eclipse.linuxtools.tmf.event.TmfTimestamp;
2fb2eb37
FC
24import org.eclipse.linuxtools.tmf.request.ITmfDataRequest;
25import org.eclipse.linuxtools.tmf.request.ITmfEventRequest;
664902f7
FC
26import org.eclipse.linuxtools.tmf.request.TmfDataRequest;
27import org.eclipse.linuxtools.tmf.request.TmfEventRequest;
f6b14ce2 28import org.eclipse.linuxtools.tmf.request.ITmfDataRequest.ExecutionType;
abfad0aa
FC
29import org.eclipse.linuxtools.tmf.signal.TmfSignalHandler;
30import org.eclipse.linuxtools.tmf.signal.TmfTraceOpenedSignal;
664902f7 31import org.eclipse.linuxtools.tmf.signal.TmfTraceUpdatedSignal;
8c8bf09f
ASL
32
33/**
146a887c 34 * <b><u>TmfTrace</u></b>
8c8bf09f 35 * <p>
146a887c
FC
36 * Abstract implementation of ITmfTrace. It should be sufficient to extend this
37 * class and provide implementation for <code>getCurrentLocation()</code> and
38 * <code>seekLocation()</code>, as well as a proper parser, to have a working
4e3aa37d 39 * concrete implementation.
ff4ed569 40 * <p>
54d55ced 41 * Note: The notion of event rank is still under heavy discussion. Although
ff4ed569 42 * used by the Events View and probably useful in the general case, there
54d55ced 43 * is no easy way to implement it for LTTng (actually a strong case is being
ff4ed569
FC
44 * made that this is useless).
45 * <p>
46 * That it is not supported by LTTng does by no mean indicate that it is not
47 * useful for (just about) every other tracing tool. Therefore, this class
48 * provides a minimal (and partial) implementation of rank. However, the current
49 * implementation should not be relied on in the general case.
54d55ced 50 *
4e3aa37d 51 * TODO: Add support for live streaming (notifications, incremental indexing, ...)
8c8bf09f 52 */
ff4ed569 53public abstract class TmfTrace<T extends TmfEvent> extends TmfEventProvider<T> implements ITmfTrace, Cloneable {
62d1696a 54
e31e01e8 55 // ------------------------------------------------------------------------
62d1696a 56 // Constants
e31e01e8 57 // ------------------------------------------------------------------------
62d1696a
FC
58
59 // The default number of events to cache
e31e01e8 60 // TODO: Make the DEFAULT_CACHE_SIZE a preference
664902f7 61 public static final int DEFAULT_INDEX_PAGE_SIZE = 1000;
8c8bf09f 62
e31e01e8 63 // ------------------------------------------------------------------------
8c8bf09f 64 // Attributes
e31e01e8 65 // ------------------------------------------------------------------------
8c8bf09f 66
b0a282fb
FC
67 // The trace path
68 private final String fPath;
69
8d2e2848 70 // The cache page size AND checkpoints interval
9f584e4c 71 protected int fIndexPageSize;
62d1696a
FC
72
73 // The set of event stream checkpoints (for random access)
9f584e4c 74 protected Vector<TmfCheckpoint> fCheckpoints = new Vector<TmfCheckpoint>();
62d1696a
FC
75
76 // The number of events collected
a3fe52fc 77 protected long fNbEvents = 0;
62d1696a
FC
78
79 // The time span of the event stream
cb866e08
FC
80 private TmfTimestamp fStartTime = TmfTimestamp.BigCrunch;
81 private TmfTimestamp fEndTime = TmfTimestamp.BigBang;
62d1696a 82
e31e01e8 83 // ------------------------------------------------------------------------
50adc88e 84 // Constructors
e31e01e8 85 // ------------------------------------------------------------------------
8c8bf09f 86
ff4ed569
FC
87 /**
88 * @param path
89 * @throws FileNotFoundException
90 */
ce785d7d 91 protected TmfTrace(String name, Class<T> type, String path) throws FileNotFoundException {
664902f7 92 this(name, type, path, DEFAULT_INDEX_PAGE_SIZE);
ff4ed569
FC
93 }
94
62d1696a 95 /**
e31e01e8
FC
96 * @param path
97 * @param cacheSize
62d1696a
FC
98 * @throws FileNotFoundException
99 */
ce785d7d
FC
100 protected TmfTrace(String name, Class<T> type, String path, int cacheSize) throws FileNotFoundException {
101 super(name, type);
b0a282fb 102 int sep = path.lastIndexOf(File.separator);
ce785d7d
FC
103 String simpleName = (sep >= 0) ? path.substring(sep + 1) : path;
104 setName(simpleName);
b0a282fb 105 fPath = path;
664902f7 106 fIndexPageSize = (cacheSize > 0) ? cacheSize : DEFAULT_INDEX_PAGE_SIZE;
8c8bf09f
ASL
107 }
108
ff4ed569
FC
109 /* (non-Javadoc)
110 * @see java.lang.Object#clone()
62d1696a 111 */
ff4ed569
FC
112 @SuppressWarnings("unchecked")
113 @Override
114 public TmfTrace<T> clone() throws CloneNotSupportedException {
115 TmfTrace<T> clone = (TmfTrace<T>) super.clone();
cb866e08
FC
116 clone.fCheckpoints = (Vector<TmfCheckpoint>) fCheckpoints;
117 clone.fStartTime = new TmfTimestamp(fStartTime);
118 clone.fEndTime = new TmfTimestamp(fEndTime);
ff4ed569 119 return clone;
8c8bf09f
ASL
120 }
121
e31e01e8 122 // ------------------------------------------------------------------------
8c8bf09f 123 // Accessors
e31e01e8 124 // ------------------------------------------------------------------------
8c8bf09f 125
62d1696a 126 /**
b0a282fb 127 * @return the trace path
62d1696a 128 */
b0a282fb
FC
129 public String getPath() {
130 return fPath;
8c8bf09f
ASL
131 }
132
62d1696a
FC
133 /* (non-Javadoc)
134 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getNbEvents()
135 */
4e3aa37d 136 public long getNbEvents() {
62d1696a 137 return fNbEvents;
8c8bf09f
ASL
138 }
139
b0a282fb
FC
140 /**
141 * @return the size of the cache
142 */
8d2e2848 143 public int getCacheSize() {
9f584e4c 144 return fIndexPageSize;
b0a282fb
FC
145 }
146
62d1696a
FC
147 /* (non-Javadoc)
148 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getTimeRange()
149 */
8c8bf09f 150 public TmfTimeRange getTimeRange() {
cb866e08 151 return new TmfTimeRange(fStartTime, fEndTime);
8c8bf09f
ASL
152 }
153
e31e01e8
FC
154 /* (non-Javadoc)
155 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStartTime()
156 */
146a887c 157 public TmfTimestamp getStartTime() {
cb866e08 158 return fStartTime;
146a887c
FC
159 }
160
e31e01e8
FC
161 /* (non-Javadoc)
162 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getEndTime()
163 */
146a887c 164 public TmfTimestamp getEndTime() {
cb866e08 165 return fEndTime;
146a887c
FC
166 }
167
ff4ed569
FC
168 @SuppressWarnings("unchecked")
169 public Vector<TmfCheckpoint> getCheckpoints() {
170 return (Vector<TmfCheckpoint>) fCheckpoints.clone();
54d55ced
FC
171 }
172
abfad0aa
FC
173 /**
174 * Returns the rank of the first event with the requested timestamp.
175 * If none, returns the index of the next event (if any).
176 *
177 * @param timestamp
178 * @return
179 */
180 public long getRank(TmfTimestamp timestamp) {
181 TmfContext context = seekEvent(timestamp);
182 return context.getRank();
183 }
184
e31e01e8 185 // ------------------------------------------------------------------------
8c8bf09f 186 // Operators
e31e01e8 187 // ------------------------------------------------------------------------
8c8bf09f 188
4e3aa37d 189 protected void setTimeRange(TmfTimeRange range) {
cb866e08
FC
190 fStartTime = range.getStartTime();
191 fEndTime = range.getEndTime();
4e3aa37d
FC
192 }
193
194 protected void setStartTime(TmfTimestamp startTime) {
cb866e08 195 fStartTime = startTime;
4e3aa37d
FC
196 }
197
198 protected void setEndTime(TmfTimestamp endTime) {
cb866e08 199 fEndTime = endTime;
4e3aa37d
FC
200 }
201
e31e01e8
FC
202 // ------------------------------------------------------------------------
203 // TmfProvider
204 // ------------------------------------------------------------------------
205
206 @Override
2fb2eb37
FC
207 public ITmfContext armRequest(ITmfDataRequest<T> request) {
208 if (request instanceof ITmfEventRequest<?>) {
209 return seekEvent(((ITmfEventRequest<T>) request).getRange().getStartTime());
e31e01e8 210 }
ff4ed569 211 return seekEvent(request.getIndex());
e31e01e8
FC
212 }
213
214 /**
215 * Return the next piece of data based on the context supplied. The context
216 * would typically be updated for the subsequent read.
217 *
218 * @param context
219 * @return
220 */
221 @SuppressWarnings("unchecked")
222 @Override
223 public T getNext(ITmfContext context) {
9f584e4c
FC
224 if (context instanceof TmfContext) {
225 return (T) getNextEvent((TmfContext) context);
e31e01e8
FC
226 }
227 return null;
228 }
229
e31e01e8
FC
230 // ------------------------------------------------------------------------
231 // ITmfTrace
232 // ------------------------------------------------------------------------
233
146a887c
FC
234 /* (non-Javadoc)
235 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.event.TmfTimestamp)
236 */
9f584e4c 237 public TmfContext seekEvent(TmfTimestamp timestamp) {
62d1696a 238
4e3aa37d
FC
239 if (timestamp == null) {
240 timestamp = TmfTimestamp.BigBang;
241 }
242
243 // First, find the right checkpoint
9f584e4c 244 int index = Collections.binarySearch(fCheckpoints, new TmfCheckpoint(timestamp, null));
62d1696a 245
8d2e2848 246 // In the very likely case that the checkpoint was not found, bsearch
62d1696a
FC
247 // returns its negated would-be location (not an offset...). From that
248 // index, we can then position the stream and get the event.
249 if (index < 0) {
250 index = Math.max(0, -(index + 2));
251 }
252
253 // Position the stream at the checkpoint
452ad365 254 ITmfLocation<?> location;
e31e01e8
FC
255 synchronized (fCheckpoints) {
256 if (fCheckpoints.size() > 0) {
257 if (index >= fCheckpoints.size()) {
258 index = fCheckpoints.size() - 1;
259 }
260 location = fCheckpoints.elementAt(index).getLocation();
261 }
262 else {
263 location = null;
264 }
8d2e2848 265 }
54d55ced
FC
266 TmfContext context = seekLocation(location);
267 context.setRank(index * fIndexPageSize);
62d1696a 268
54d55ced 269 // And locate the event
ff4ed569 270 TmfContext nextEventContext = context.clone(); // Must use clone() to get the right subtype...
62d1696a
FC
271 TmfEvent event = getNextEvent(nextEventContext);
272 while (event != null && event.getTimestamp().compareTo(timestamp, false) < 0) {
54d55ced
FC
273 context.setLocation(nextEventContext.getLocation().clone());
274 context.updateRank(1);
62d1696a
FC
275 event = getNextEvent(nextEventContext);
276 }
277
54d55ced 278 return context;
62d1696a
FC
279 }
280
146a887c
FC
281 /* (non-Javadoc)
282 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(int)
283 */
9f584e4c 284 public TmfContext seekEvent(long rank) {
62d1696a
FC
285
286 // Position the stream at the previous checkpoint
9f584e4c 287 int index = (int) rank / fIndexPageSize;
452ad365 288 ITmfLocation<?> location;
e31e01e8 289 synchronized (fCheckpoints) {
54d55ced
FC
290 if (fCheckpoints.size() == 0) {
291 location = null;
292 }
293 else {
e31e01e8 294 if (index >= fCheckpoints.size()) {
54d55ced 295 index = fCheckpoints.size() - 1;
e31e01e8
FC
296 }
297 location = fCheckpoints.elementAt(index).getLocation();
298 }
8d2e2848 299 }
54d55ced 300
9f584e4c
FC
301 TmfContext context = seekLocation(location);
302 long pos = index * fIndexPageSize;
303 context.setRank(pos);
e31e01e8 304
9f584e4c 305 if (pos < rank) {
e31e01e8 306 TmfEvent event = getNextEvent(context);
9f584e4c 307 while (event != null && ++pos < rank) {
e31e01e8
FC
308 event = getNextEvent(context);
309 }
165c977c 310 }
62d1696a 311
8f50c396 312 return context;
8c8bf09f
ASL
313 }
314
146a887c
FC
315 /* (non-Javadoc)
316 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getNextEvent(org.eclipse.linuxtools.tmf.trace.ITmfTrace.TraceContext)
317 */
9f584e4c 318 public synchronized TmfEvent getNextEvent(TmfContext context) {
e31e01e8 319 // parseEvent() does not update the context
cc6eec3e 320 TmfEvent event = parseEvent(context);
4e3aa37d 321 if (event != null) {
550d787e 322 updateIndex(context, context.getRank(), event.getTimestamp());
cb866e08 323 context.setLocation(getCurrentLocation());
54d55ced 324 context.updateRank(1);
4e3aa37d
FC
325 processEvent(event);
326 }
146a887c
FC
327 return event;
328 }
8c8bf09f 329
cb866e08
FC
330 protected synchronized void updateIndex(ITmfContext context, long rank, TmfTimestamp timestamp) {
331 if (fStartTime.compareTo(timestamp, false) > 0) fStartTime = timestamp;
332 if (fEndTime.compareTo(timestamp, false) < 0) fEndTime = timestamp;
333 if (context.isValidRank()) {
334 if (fNbEvents <= rank)
335 fNbEvents = rank + 1;
336 // Build the index as we go along
337 if ((rank % fIndexPageSize) == 0) {
338 // Determine the table position
339 long position = rank / fIndexPageSize;
340 // Add new entry at proper location (if empty)
341 if (fCheckpoints.size() == position) {
342 ITmfLocation<?> location = context.getLocation().clone();
343 fCheckpoints.add(new TmfCheckpoint(timestamp, location));
344// System.out.println(getName() + "[" + (fCheckpoints.size() - 1) + "] " + timestamp + ", " + location.toString());
345 }
550d787e
FC
346 }
347 }
348 }
349
4e3aa37d 350 /**
e31e01e8
FC
351 * Hook for "special" processing by the concrete class
352 * (called by getNextEvent())
353 *
146a887c
FC
354 * @param event
355 */
ff4ed569 356 protected void processEvent(TmfEvent event) {
146a887c 357 // Do nothing by default
62d1696a 358 }
4e3aa37d 359
e31e01e8
FC
360 /**
361 * To be implemented by the concrete class
4e3aa37d 362 */
452ad365
FC
363 public abstract TmfContext seekLocation(ITmfLocation<?> location);
364 public abstract ITmfLocation<?> getCurrentLocation();
9f584e4c 365 public abstract TmfEvent parseEvent(TmfContext context);
4e3aa37d 366
e31e01e8
FC
367 // ------------------------------------------------------------------------
368 // toString
369 // ------------------------------------------------------------------------
8d2e2848
FC
370
371 /* (non-Javadoc)
372 * @see java.lang.Object#toString()
373 */
374 @Override
375 public String toString() {
ce785d7d 376 return "[TmfTrace (" + getName() + ")]";
8d2e2848 377 }
146a887c 378
664902f7
FC
379 // ------------------------------------------------------------------------
380 // Indexing
381 // ------------------------------------------------------------------------
382
383 /*
384 * The purpose of the index is to keep the information needed to rapidly
385 * restore the traces contexts at regular intervals (every INDEX_PAGE_SIZE
386 * event).
387 */
388
abfad0aa 389 @SuppressWarnings("unchecked")
664902f7
FC
390 private void indexTrace(boolean waitForCompletion) {
391
392 fCheckpoints.clear();
393
f6b14ce2 394 ITmfEventRequest<TmfEvent> request = new TmfEventRequest<TmfEvent>(TmfEvent.class, TmfTimeRange.Eternity, TmfDataRequest.ALL_DATA, 1, ITmfDataRequest.ExecutionType.BACKGROUND) {
664902f7
FC
395
396 TmfTimestamp startTime = null;
397 TmfTimestamp lastTime = null;
398
399 @Override
400 public void handleData() {
401 TmfEvent[] events = getData();
402 if (events.length > 0) {
403 TmfTimestamp ts = events[0].getTimestamp();
404 if (startTime == null) {
405 startTime = new TmfTimestamp(ts);
406 fStartTime = startTime;
407 }
408 lastTime = new TmfTimestamp(ts);
409
410 if ((fNbRead % DEFAULT_INDEX_PAGE_SIZE) == 0) {
411 updateTraceData();
412 }
413 }
414 }
415
416 @Override
417 public void handleSuccess() {
418 updateTraceData();
419 }
420
421 private void updateTraceData() {
6c042a35
FC
422 if (fNbRead != 0) {
423 fEndTime = new TmfTimestamp(lastTime);
424 fNbEvents = fNbRead;
425 notifyListeners();
426 }
664902f7
FC
427 }
428 };
429
430 sendRequest((ITmfDataRequest<T>) request);
431 if (waitForCompletion)
432 try {
433 request.waitForCompletion();
434 } catch (InterruptedException e) {
435 e.printStackTrace();
436 }
437 }
438
439 protected void notifyListeners() {
440 broadcast(new TmfTraceUpdatedSignal(this, this, new TmfTimeRange(fStartTime, fEndTime)));
441 }
442
abfad0aa
FC
443 // ------------------------------------------------------------------------
444 // TmfDataProvider
445 // ------------------------------------------------------------------------
446
447 @Override
f6b14ce2 448 protected void queueBackgroundRequest(final ITmfDataRequest<T> request, final int blockSize, final boolean indexing) {
abfad0aa 449
f6b14ce2
FC
450 // TODO: Handle the data requests also...
451 if (!(request instanceof ITmfEventRequest<?>)) {
452 super.queueRequest(request);
453 return;
454 }
455 final ITmfEventRequest<T> eventRequest = (ITmfEventRequest<T>) request;
abfad0aa 456
f6b14ce2
FC
457 Thread thread = new Thread() {
458 @Override
459 public void run() {
460
461// final long requestStart = System.nanoTime();
462
463 final Integer[] CHUNK_SIZE = new Integer[1];
464 CHUNK_SIZE[0] = blockSize + ((indexing) ? 1 : 0);
465
466 final Integer[] nbRead = new Integer[1];
467 nbRead[0] = 0;
468
469// final TmfTimestamp[] timestamp = new TmfTimestamp[1];
470// timestamp[0] = new TmfTimestamp(eventRequest.getRange().getStartTime());
471// final TmfTimestamp endTS = eventRequest.getRange().getEndTime();
472
473 final Boolean[] isFinished = new Boolean[1];
474 isFinished[0] = Boolean.FALSE;
475
476 while (!isFinished[0]) {
477
478// TmfEventRequest<T> subRequest = new TmfEventRequest<T>(eventRequest.getDataType(), new TmfTimeRange(timestamp[0], endTS), CHUNK_SIZE[0], eventRequest.getBlockize(), ExecutionType.BACKGROUND)
479 TmfDataRequest<T> subRequest = new TmfDataRequest<T>(eventRequest.getDataType(), nbRead[0], CHUNK_SIZE[0], eventRequest.getBlockize(), ExecutionType.BACKGROUND)
480 {
481// int count = 0;
482 @Override
483 public void handleData() {
484 T[] data = getData();
485// timestamp[0] = data[data.length-1].getTimestamp();
486// if (count == 0) {
487// System.out.println("First event of the block: " + data[0].getTimestamp());
488// }
489// count++;
490// Tracer.trace("Ndx: " + ((TmfEvent) data[0]).getTimestamp());
491 eventRequest.setData(data);
492 eventRequest.handleData();
493 if (fNbRead == CHUNK_SIZE[0]) {
494 nbRead[0] += fNbRead;
495// System.out.println("fNbRead=" + fNbRead + ", count=" + count +", total=" + nbRead[0] + ", TS=" + data[0].getTimestamp());
496 }
497 if (fNbRead > CHUNK_SIZE[0]) {
498 System.out.println("ERROR - Read too many events");
499 }
500 }
501 @Override
502 public void handleCompleted() {
503// System.out.println("Request completed at: " + timestamp[0]);
504 if (fNbRead < CHUNK_SIZE[0]) {
505 eventRequest.done();
506 isFinished[0] = Boolean.TRUE;
507 nbRead[0] += fNbRead;
508// System.out.println("fNbRead=" + fNbRead + ", count=" + count +", total=" + nbRead[0]);
509 }
510 super.handleCompleted();
511 }
512 };
513
514 if (!isFinished[0]) {
515 queueRequest(subRequest);
516
517 try {
518 subRequest.waitForCompletion();
519// System.out.println("Finished at " + timestamp[0]);
520 } catch (InterruptedException e) {
521 e.printStackTrace();
522 }
523
524// TmfTimestamp newTS = new TmfTimestamp(timestamp[0].getValue() + 1, timestamp[0].getScale(), timestamp[0].getPrecision());
525// timestamp[0] = newTS;
526 CHUNK_SIZE[0] = blockSize;
527// System.out.println("New timestamp: " + timestamp[0]);
528 }
529 }
530// final long requestEnded = System.nanoTime();
531// System.out.println("Background request completed. Elapsed= " + (requestEnded * 1.0 - requestStart) / 1000000000);
532 }
533 };
534
535 thread.start();
536 }
abfad0aa
FC
537
538 // ------------------------------------------------------------------------
539 // Signal handlers
540 // ------------------------------------------------------------------------
541
542 @TmfSignalHandler
543 public void traceOpened(TmfTraceOpenedSignal signal) {
544 ITmfTrace trace = signal.getTrace();
545 if (trace == this) {
546 indexTrace(false);
547 }
548 }
f6b14ce2 549
8c8bf09f 550}
This page took 0.062326 seconds and 5 git commands to generate.