tmf: Automatically sync experiments set up with the same hosts
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.core / src / org / eclipse / tracecompass / tmf / core / trace / experiment / TmfExperiment.java
CommitLineData
8c8bf09f 1/*******************************************************************************
5904c11e 2 * Copyright (c) 2009, 2015 Ericsson, École Polytechnique de Montréal
ce2388e0 3 *
8c8bf09f
ASL
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
ce2388e0 8 *
8c8bf09f
ASL
9 * Contributors:
10 * Francois Chouinard - Initial API and implementation
0316808c 11 * Francois Chouinard - Updated as per TMF Trace Model 1.0
ea271da6
PT
12 * Patrick Tasse - Updated for removal of context clone
13 * Patrick Tasse - Updated for ranks in experiment location
e73a4ba5 14 * Geneviève Bastien - Added support of experiment synchronization
b3dd2736 15 * Added the initExperiment method and default constructor
d77f31da 16 * Bernd Hufmann - Updated for added interfaces to ITmfEventProvider
8c8bf09f
ASL
17 *******************************************************************************/
18
5c5fa260 19package org.eclipse.tracecompass.tmf.core.trace.experiment;
8c8bf09f 20
472ea248
AM
21import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
22
e73a4ba5 23import java.io.File;
472ea248 24import java.math.BigInteger;
032ecd45 25import java.nio.ByteBuffer;
472ea248 26import java.util.Collection;
4d2a4a2c 27import java.util.Collections;
fa62dc1d 28import java.util.List;
4d2a4a2c
GB
29import java.util.concurrent.locks.Lock;
30import java.util.concurrent.locks.ReentrantLock;
472ea248
AM
31import java.util.function.Function;
32import java.util.stream.Collectors;
e73a4ba5 33
12c155f5 34import org.eclipse.core.resources.IProject;
828e5592 35import org.eclipse.core.resources.IResource;
e73a4ba5 36import org.eclipse.core.runtime.CoreException;
a94410d9 37import org.eclipse.core.runtime.IStatus;
9928ddeb 38import org.eclipse.core.runtime.MultiStatus;
a94410d9 39import org.eclipse.core.runtime.Status;
aa353506 40import org.eclipse.jdt.annotation.NonNull;
4178260e 41import org.eclipse.jdt.annotation.Nullable;
2bdf0193 42import org.eclipse.tracecompass.internal.tmf.core.Activator;
472ea248 43import org.eclipse.tracecompass.internal.tmf.core.synchronization.TmfTimestampTransform;
5c5fa260
AM
44import org.eclipse.tracecompass.internal.tmf.core.trace.experiment.TmfExperimentContext;
45import org.eclipse.tracecompass.internal.tmf.core.trace.experiment.TmfExperimentLocation;
46import org.eclipse.tracecompass.internal.tmf.core.trace.experiment.TmfLocationArray;
2bdf0193
AM
47import org.eclipse.tracecompass.tmf.core.TmfCommonConstants;
48import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
49import org.eclipse.tracecompass.tmf.core.exceptions.TmfTraceException;
472ea248 50import org.eclipse.tracecompass.tmf.core.project.model.ITmfPropertiesProvider;
2bdf0193
AM
51import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest;
52import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
53import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
54import org.eclipse.tracecompass.tmf.core.signal.TmfTraceRangeUpdatedSignal;
55import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSynchronizedSignal;
472ea248 56import org.eclipse.tracecompass.tmf.core.synchronization.ITmfTimestampTransform;
2bdf0193
AM
57import org.eclipse.tracecompass.tmf.core.synchronization.SynchronizationAlgorithm;
58import org.eclipse.tracecompass.tmf.core.synchronization.SynchronizationManager;
472ea248 59import org.eclipse.tracecompass.tmf.core.synchronization.TimestampTransformFactory;
2bdf0193
AM
60import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
61import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
62import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
5c5fa260 63import org.eclipse.tracecompass.tmf.core.trace.ITmfContext;
5c5fa260
AM
64import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
65import org.eclipse.tracecompass.tmf.core.trace.TmfTrace;
66import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
2bdf0193
AM
67import org.eclipse.tracecompass.tmf.core.trace.indexer.ITmfPersistentlyIndexable;
68import org.eclipse.tracecompass.tmf.core.trace.indexer.ITmfTraceIndexer;
69import org.eclipse.tracecompass.tmf.core.trace.indexer.TmfBTreeTraceIndexer;
70import org.eclipse.tracecompass.tmf.core.trace.location.ITmfLocation;
8c8bf09f 71
472ea248
AM
72import com.google.common.collect.HashMultimap;
73import com.google.common.collect.Multimap;
74
8c8bf09f 75/**
9e0640dc 76 * TmfExperiment presents a time-ordered, unified view of a set of ITmfTrace:s
cbdacf03 77 * that are part of a tracing experiment.
4b7b3670
FC
78 *
79 * @version 1.0
80 * @author Francois Chouinard
8c8bf09f 81 */
5733be39 82public class TmfExperiment extends TmfTrace implements ITmfPersistentlyIndexable {
8c8bf09f 83
c32744d6
FC
84 // ------------------------------------------------------------------------
85 // Constants
86 // ------------------------------------------------------------------------
87
e73a4ba5
GB
88 /**
89 * The file name of the Synchronization
90 *
7f38b742
GB
91 * @deprecated This file name shouldn't be used directly anymore. All
92 * synchronization files have been moved to a folder and you
93 * should use the {@link #getSynchronizationFolder(boolean)}
94 * method to return the path to this folder.
e73a4ba5 95 */
04ba3554 96 @Deprecated
7f38b742 97 public static final String SYNCHRONIZATION_FILE_NAME = "synchronization.bin"; //$NON-NLS-1$
e73a4ba5 98
04ba3554
GB
99 /**
100 * The name of the directory containing trace synchronization data. This
101 * directory typically will be preserved when traces are synchronized.
102 * Analysis involved in synchronization can put their supplementary files in
103 * there so they are not deleted when synchronized traces are copied.
04ba3554 104 */
7f38b742 105 private static final String SYNCHRONIZATION_DIRECTORY = "sync_data"; //$NON-NLS-1$
04ba3554 106
9e0640dc
FC
107 /**
108 * The default index page size
109 */
110 public static final int DEFAULT_INDEX_PAGE_SIZE = 5000;
c32744d6 111
472ea248
AM
112 /**
113 * Property name for traces defining a clock offset.
114 */
115 private static final String CLOCK_OFFSET_PROPERTY = "clock_offset"; //$NON-NLS-1$
116
117 /**
118 * If the automatic clock offset is higher than this value, emit a warning.
119 */
120 private static final long CLOCK_OFFSET_THRESHOLD_NS = 500000;
121
8c8bf09f
ASL
122 // ------------------------------------------------------------------------
123 // Attributes
124 // ------------------------------------------------------------------------
125
9e0640dc
FC
126 /**
127 * The set of traces that constitute the experiment
128 */
129 private boolean fInitialized = false;
a1091415 130
4d2a4a2c
GB
131 /**
132 * Lock for synchronization methods. These methods cannot be 'synchronized'
133 * since it makes it impossible to use an event request on the experiment
134 * during synchronization (the request thread would block)
135 */
136 private final Lock fSyncLock = new ReentrantLock();
4178260e 137
8c8bf09f 138 // ------------------------------------------------------------------------
9e0640dc 139 // Construction
8c8bf09f
ASL
140 // ------------------------------------------------------------------------
141
9e0640dc 142 /**
4178260e
AM
143 * Default constructor. Should not be used directly, but is needed for
144 * extension points.
04ba3554 145 *
4178260e 146 * @deprecated Do not call this directly (but do not remove it either!)
b3dd2736 147 */
4178260e 148 @Deprecated
b3dd2736
GB
149 public TmfExperiment() {
150 super();
151 }
152
153 /**
4178260e 154 * Constructor of an experiment, taking the type, path, traces,
99504bb8
GB
155 * indexPageSize and resource
156 *
157 * @param type
4178260e 158 * The event type
99504bb8 159 * @param path
4178260e 160 * The experiment path
99504bb8 161 * @param traces
4178260e 162 * The experiment set of traces
99504bb8 163 * @param indexPageSize
4178260e
AM
164 * The experiment index page size. You can use
165 * {@link TmfExperiment#DEFAULT_INDEX_PAGE_SIZE} for a default
166 * value.
99504bb8 167 * @param resource
4178260e
AM
168 * The resource associated to the experiment. You can use 'null'
169 * for no resources (tests, etc.)
99504bb8 170 */
4178260e
AM
171 public TmfExperiment(final Class<? extends ITmfEvent> type,
172 final String path,
173 final ITmfTrace[] traces,
174 final int indexPageSize,
175 final @Nullable IResource resource) {
b3dd2736 176 initExperiment(type, path, traces, indexPageSize, resource);
8c8bf09f 177 }
a79913eb 178
032ecd45
MAL
179 @Override
180 protected ITmfTraceIndexer createIndexer(int interval) {
181 if (getCheckpointSize() > 0) {
182 return new TmfBTreeTraceIndexer(this, interval);
183 }
184 return super.createIndexer(interval);
185 }
186
8c8bf09f 187 /**
ff4ed569 188 * Clears the experiment
8c8bf09f
ASL
189 */
190 @Override
a79913eb
FC
191 public synchronized void dispose() {
192
77551cc2
FC
193 // Clean up the index if applicable
194 if (getIndexer() != null) {
195 getIndexer().dispose();
196 }
b5ee6881 197
2fb2eb37 198 super.dispose();
8c8bf09f
ASL
199 }
200
9e0640dc
FC
201 // ------------------------------------------------------------------------
202 // ITmfTrace - Initializers
203 // ------------------------------------------------------------------------
204
9e0640dc 205 @Override
6256d8ad 206 public void initTrace(final IResource resource, final String path, final Class<? extends ITmfEvent> type) {
4178260e 207 /* Do nothing for experiments */
9e0640dc
FC
208 }
209
b3dd2736
GB
210 /**
211 * Initialization of an experiment, taking the type, path, traces,
212 * indexPageSize and resource
213 *
214 * @param type
215 * the event type
216 * @param path
217 * the experiment path
218 * @param traces
219 * the experiment set of traces
220 * @param indexPageSize
221 * the experiment index page size
222 * @param resource
223 * the resource associated to the experiment
b3dd2736 224 */
4178260e
AM
225 public void initExperiment(final Class<? extends ITmfEvent> type,
226 final String path,
227 final ITmfTrace[] traces,
228 final int indexPageSize,
229 final @Nullable IResource resource) {
230
b3dd2736
GB
231 setCacheSize(indexPageSize);
232 setStreamingInterval(0);
d77f31da 233
472ea248
AM
234 Multimap<String, ITmfTrace> tracesPerHost = HashMultimap.create();
235
7976315b 236 // traces have to be set before super.initialize()
d77f31da
BH
237 if (traces != null) {
238 // initialize
d77f31da
BH
239 for (ITmfTrace trace : traces) {
240 if (trace != null) {
472ea248 241 tracesPerHost.put(trace.getHostId(), trace);
d77f31da
BH
242 addChild(trace);
243 }
244 }
245 }
246
b3dd2736
GB
247 try {
248 super.initialize(resource, path, type);
249 } catch (TmfTraceException e) {
250 Activator.logError("Error initializing experiment", e); //$NON-NLS-1$
251 }
252
b3dd2736 253 if (resource != null) {
472ea248
AM
254 synchronizeTraces();
255 }
256
257 /*
258 * For all traces on the same host, if two or more specify different
259 * clock offsets, adjust their clock offset by the average of all of them.
260 *
261 * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=484620
262 */
263 Function<ITmfPropertiesProvider, @Nullable Long> offsetGetter = trace -> {
264 String offset = trace.getProperties().get(CLOCK_OFFSET_PROPERTY);
265 if (offset == null) {
266 return null;
267 }
268 try {
269 return Long.parseLong(offset);
270 } catch (NumberFormatException e) {
271 return null;
272 }
273 };
274
275 for (String host : tracesPerHost.keySet()) {
276 /*
277 * Only attempt to synchronize traces that provide a clock_offset
278 * property.
279 */
280 Collection<ITmfPropertiesProvider> tracesToSynchronize = tracesPerHost.get(host).stream()
281 .filter(trace -> trace instanceof ITmfPropertiesProvider)
282 .map(trace -> (ITmfPropertiesProvider) trace)
283 .filter(trace -> offsetGetter.apply(trace) != null)
284 .collect(Collectors.toList());
285
286 if (tracesToSynchronize.size() < 2) {
287 continue;
288 }
289
290 /* Only synchronize traces if they haven't previously been synchronized */
291 if (tracesToSynchronize.stream()
292 .map(trace -> ((ITmfTrace) trace).getTimestampTransform())
293 .anyMatch(transform -> !transform.equals(TmfTimestampTransform.IDENTITY))) {
294 continue;
295 }
296
297 /* Calculate the average of all clock offsets */
298 BigInteger sum = BigInteger.ZERO;
299 for (ITmfPropertiesProvider trace : tracesToSynchronize) {
300 long offset = checkNotNull(offsetGetter.apply(trace));
301 sum = sum.add(BigInteger.valueOf(offset));
302 }
303 long average = sum.divide(BigInteger.valueOf(tracesToSynchronize.size())).longValue();
304
305 if (average > CLOCK_OFFSET_THRESHOLD_NS) {
306 Activator.logWarning("Average clock correction (" + average + ") is higher than threshold of " + //$NON-NLS-1$ //$NON-NLS-2$
307 CLOCK_OFFSET_THRESHOLD_NS + " ns for experiment " + this.toString()); //$NON-NLS-1$
308 }
309
310 /*
311 * Apply the offset correction to all identified traces, but only if
312 * they do not already have an equivalent one (for example, closing
313 * and re-opening the same experiment should not retrigger building
314 * all supplementary files).
315 */
316 tracesToSynchronize.forEach(t -> {
317 long offset = checkNotNull(offsetGetter.apply(t));
318 long delta = average - offset;
319
320 ITmfTrace trace = (ITmfTrace) t;
321 ITmfTimestampTransform currentTransform = trace.getTimestampTransform();
322 ITmfTimestampTransform newTransform = TimestampTransformFactory.createWithOffset(delta);
323
324 if (!newTransform.equals(currentTransform)) {
325 TmfTraceManager.deleteSupplementaryFiles(trace);
326 trace.setTimestampTransform(newTransform);
327 }
328 });
b3dd2736
GB
329 }
330 }
331
9e0640dc 332 @Override
a94410d9
MK
333 public IStatus validate(final IProject project, final String path) {
334 return Status.OK_STATUS;
9e0640dc
FC
335 }
336
8c8bf09f 337 // ------------------------------------------------------------------------
e31e01e8 338 // Accessors
8c8bf09f
ASL
339 // ------------------------------------------------------------------------
340
f0c0d2c2
AM
341 /**
342 * Get the traces contained in this experiment.
343 *
344 * @return The array of contained traces
345 */
aa353506 346 public List<@NonNull ITmfTrace> getTraces() {
fa62dc1d 347 return getChildren(ITmfTrace.class);
8c8bf09f
ASL
348 }
349
8c8bf09f 350 /**
cbdacf03
FC
351 * Returns the timestamp of the event at the requested index. If none,
352 * returns null.
9b749023 353 *
e73a4ba5
GB
354 * @param index
355 * the event index (rank)
0d9a6d76 356 * @return the corresponding event timestamp
8c8bf09f 357 */
cbdacf03 358 public ITmfTimestamp getTimestamp(final int index) {
0316808c 359 final ITmfContext context = seekEvent(index);
c32744d6 360 final ITmfEvent event = getNext(context);
4c9f2944 361 context.dispose();
a79913eb 362 return (event != null) ? event.getTimestamp() : null;
8c8bf09f
ASL
363 }
364
49e2f79a
FC
365 // ------------------------------------------------------------------------
366 // Request management
367 // ------------------------------------------------------------------------
368
369 @Override
fd3f1eff 370 public synchronized ITmfContext armRequest(final ITmfEventRequest request) {
9b749023 371
6a953367 372 // Make sure we have something to read from
fa62dc1d 373 if (getChildren().isEmpty()) {
6a953367
BH
374 return null;
375 }
9b749023 376
fd3f1eff
AM
377 if (!TmfTimestamp.BIG_BANG.equals(request.getRange().getStartTime())
378 && request.getIndex() == 0) {
379 final ITmfContext context = seekEvent(request.getRange().getStartTime());
380 request.setStartIndex((int) context.getRank());
49e2f79a 381 return context;
5419a136 382
49e2f79a
FC
383 }
384
5419a136 385 return seekEvent(request.getIndex());
49e2f79a
FC
386 }
387
a79913eb 388 // ------------------------------------------------------------------------
9f584e4c
FC
389 // ITmfTrace trace positioning
390 // ------------------------------------------------------------------------
391
a79913eb 392 @Override
1e1bef82 393 public synchronized ITmfContext seekEvent(final ITmfLocation location) {
a79913eb 394 // Validate the location
9e0640dc 395 if (location != null && !(location instanceof TmfExperimentLocation)) {
a79913eb 396 return null; // Throw an exception?
9e0640dc 397 }
d77f31da 398
fa62dc1d 399 int length = getNbChildren();
8f50c396 400
ea271da6 401 // Initialize the location array if necessary
38db0431 402 TmfLocationArray locationArray = ((location == null) ? new TmfLocationArray(length) : ((TmfExperimentLocation) location).getLocationInfo());
ea271da6
PT
403
404 ITmfLocation[] locations = locationArray.getLocations();
405 long[] ranks = locationArray.getRanks();
406
a79913eb 407 // Create and populate the context's traces contexts
fa62dc1d 408 final TmfExperimentContext context = new TmfExperimentContext(length);
9b635e61 409
d62bb185 410 // Position the traces
ea271da6 411 long rank = 0;
fa62dc1d 412 for (int i = 0; i < length; i++) {
a79913eb 413 // Get the relevant trace attributes
fa62dc1d 414 final ITmfContext traceContext = ((ITmfTrace) getChild(i)).seekEvent(locations[i]);
07ef7847 415 context.setContext(i, traceContext);
ea271da6 416 traceContext.setRank(ranks[i]);
7f38b742
GB
417 // update location after seek
418 locations[i] = traceContext.getLocation();
fa62dc1d 419 context.setEvent(i, ((ITmfTrace) getChild(i)).getNext(traceContext));
ea271da6 420 rank += ranks[i];
a79913eb 421 }
8f50c396 422
a79913eb 423 // Finalize context
ea271da6 424 context.setLocation(new TmfExperimentLocation(new TmfLocationArray(locations, ranks)));
a79913eb 425 context.setLastTrace(TmfExperimentContext.NO_TRACE);
ea271da6 426 context.setRank(rank);
49e2f79a 427
9b749023 428 return context;
a79913eb 429 }
9f584e4c 430
3bd44ac8
FC
431 // ------------------------------------------------------------------------
432 // ITmfTrace - SeekEvent operations (returning a trace context)
433 // ------------------------------------------------------------------------
434
c76c54bb 435 @Override
0316808c 436 public ITmfContext seekEvent(final double ratio) {
91f6e587 437 final ITmfContext context = seekEvent(Math.round(ratio * getNbEvents()));
c76c54bb
FC
438 return context;
439 }
440
a79913eb 441 @Override
1e1bef82 442 public double getLocationRatio(final ITmfLocation location) {
9e0640dc 443 if (location instanceof TmfExperimentLocation) {
ea271da6
PT
444 long rank = 0;
445 TmfLocationArray locationArray = ((TmfExperimentLocation) location).getLocationInfo();
446 for (int i = 0; i < locationArray.size(); i++) {
447 rank += locationArray.getRank(i);
448 }
449 return (double) rank / getNbEvents();
9e0640dc
FC
450 }
451 return 0.0;
c76c54bb
FC
452 }
453
a79913eb 454 @Override
1e1bef82 455 public ITmfLocation getCurrentLocation() {
ea271da6
PT
456 // never used
457 return null;
a79913eb 458 }
c76c54bb 459
9e0640dc
FC
460 // ------------------------------------------------------------------------
461 // ITmfTrace trace positioning
462 // ------------------------------------------------------------------------
463
07671572 464 @Override
6256d8ad 465 public synchronized ITmfEvent parseEvent(final ITmfContext context) {
ea271da6
PT
466 final ITmfContext tmpContext = seekEvent(context.getLocation());
467 final ITmfEvent event = getNext(tmpContext);
07671572
FC
468 return event;
469 }
a79913eb 470
0316808c 471 @Override
6256d8ad 472 public synchronized ITmfEvent getNext(ITmfContext context) {
a79913eb
FC
473
474 // Validate the context
9e0640dc 475 if (!(context instanceof TmfExperimentContext)) {
a79913eb 476 return null; // Throw an exception?
9e0640dc 477 }
0e8c76f8 478
fa62dc1d
BH
479 int length = getNbChildren();
480
0e8c76f8 481 // Make sure that we have something to read from
fa62dc1d 482 if (length == 0) {
0e8c76f8
BH
483 return null;
484 }
485
a87cc4ef 486 TmfExperimentContext expContext = (TmfExperimentContext) context;
a79913eb 487
e73a4ba5
GB
488 // If an event was consumed previously, first get the next one from that
489 // trace
cbdacf03 490 final int lastTrace = expContext.getLastTrace();
a79913eb 491 if (lastTrace != TmfExperimentContext.NO_TRACE) {
07ef7847 492 final ITmfContext traceContext = expContext.getContext(lastTrace);
fa62dc1d 493 expContext.setEvent(lastTrace, ((ITmfTrace) getChild(lastTrace)).getNext(traceContext));
a79913eb 494 expContext.setLastTrace(TmfExperimentContext.NO_TRACE);
a79913eb
FC
495 }
496
497 // Scan the candidate events and identify the "next" trace to read from
498 int trace = TmfExperimentContext.NO_TRACE;
a4115405 499 ITmfTimestamp timestamp = TmfTimestamp.BIG_CRUNCH;
fa62dc1d 500 for (int i = 0; i < length; i++) {
07ef7847 501 final ITmfEvent event = expContext.getEvent(i);
fa62dc1d 502
cbf0057c 503 if (event != null) {
cbdacf03 504 final ITmfTimestamp otherTS = event.getTimestamp();
065cc19b 505 if (otherTS.compareTo(timestamp) < 0) {
a79913eb
FC
506 trace = i;
507 timestamp = otherTS;
508 }
509 }
510 }
a87cc4ef 511
6256d8ad 512 ITmfEvent event = null;
07671572 513 if (trace != TmfExperimentContext.NO_TRACE) {
07ef7847 514 event = expContext.getEvent(trace);
408e65d2 515 if (event != null) {
5904c11e 516 updateAttributes(expContext, event);
408e65d2
FC
517 expContext.increaseRank();
518 expContext.setLastTrace(trace);
07ef7847
AM
519 final ITmfContext traceContext = expContext.getContext(trace);
520 if (traceContext == null) {
521 throw new IllegalStateException();
522 }
17324c9a 523
ea271da6 524 // Update the experiment location
38db0431
MK
525 ITmfLocation location = expContext.getLocation();
526 if (location instanceof TmfExperimentLocation) {
527 TmfLocationArray locationArray = new TmfLocationArray(
528 ((TmfExperimentLocation) location).getLocationInfo(),
529 trace, traceContext.getLocation(), traceContext.getRank());
530 expContext.setLocation(new TmfExperimentLocation(locationArray));
531 }
408e65d2 532 }
07671572 533 }
a87cc4ef 534
a87cc4ef 535 return event;
a79913eb
FC
536 }
537
66262ad8
BH
538 @Override
539 public ITmfTimestamp getInitialRangeOffset() {
d77f31da 540
fa62dc1d
BH
541 List<ITmfTrace> children = getChildren(ITmfTrace.class);
542
543 if (children.isEmpty()) {
66262ad8
BH
544 return super.getInitialRangeOffset();
545 }
546
547 ITmfTimestamp initTs = TmfTimestamp.BIG_CRUNCH;
fa62dc1d
BH
548 for (ITmfTrace trace : children) {
549 ITmfTimestamp ts = (trace).getInitialRangeOffset();
66262ad8
BH
550 if (ts.compareTo(initTs) < 0) {
551 initTs = ts;
552 }
553 }
554 return initTs;
555 }
556
04ba3554
GB
557 /**
558 * Get the path to the folder in the supplementary file where
559 * synchronization-related data can be kept so they are not deleted when the
7f38b742
GB
560 * experiment is synchronized. Analysis involved in synchronization can put
561 * their supplementary files in there so they are preserved after
562 * synchronization.
04ba3554 563 *
7f38b742
GB
564 * If the directory does not exist, it will be created. A return value of
565 * <code>null</code> means either the trace resource does not exist or
566 * supplementary resources cannot be kept.
567 *
568 * @param absolute
569 * If <code>true</code>, it returns the absolute path in the file
570 * system, including the supplementary file path. Otherwise, it
571 * returns only the directory name.
04ba3554
GB
572 * @return The path to the folder where synchronization-related
573 * supplementary files can be kept or <code>null</code> if not
574 * available.
04ba3554 575 */
7f38b742 576 public String getSynchronizationFolder(boolean absolute) {
04ba3554
GB
577 /* Set up the path to the synchronization file we'll use */
578 IResource resource = this.getResource();
579 String syncDirectory = null;
580
581 try {
582 /* get the directory where the file will be stored. */
583 if (resource != null) {
7f38b742 584 String fullDirectory = resource.getPersistentProperty(TmfCommonConstants.TRACE_SUPPLEMENTARY_FOLDER);
04ba3554 585 /* Create the synchronization data directory if not present */
7f38b742
GB
586 if (fullDirectory != null) {
587 fullDirectory = fullDirectory + File.separator + SYNCHRONIZATION_DIRECTORY;
588 File syncDir = new File(fullDirectory);
04ba3554
GB
589 syncDir.mkdirs();
590 }
7f38b742
GB
591 if (absolute) {
592 syncDirectory = fullDirectory;
593 } else {
594 syncDirectory = SYNCHRONIZATION_DIRECTORY;
595 }
04ba3554
GB
596 }
597 } catch (CoreException e) {
598 return null;
599 }
600
601 return syncDirectory;
602 }
603
e73a4ba5
GB
604 /**
605 * Synchronizes the traces of an experiment. By default it only tries to
606 * read a synchronization file if it exists
607 *
608 * @return The synchronization object
e73a4ba5 609 */
4d2a4a2c 610 public SynchronizationAlgorithm synchronizeTraces() {
e73a4ba5
GB
611 return synchronizeTraces(false);
612 }
613
614 /**
615 * Synchronizes the traces of an experiment.
616 *
617 * @param doSync
618 * Whether to actually synchronize or just try opening a sync
619 * file
620 * @return The synchronization object
e73a4ba5 621 */
4d2a4a2c
GB
622 public SynchronizationAlgorithm synchronizeTraces(boolean doSync) {
623 fSyncLock.lock();
e73a4ba5 624
4d2a4a2c
GB
625 try {
626 String syncDirectory = getSynchronizationFolder(true);
e73a4ba5 627
4d2a4a2c 628 final File syncFile = (syncDirectory != null) ? new File(syncDirectory + File.separator + SYNCHRONIZATION_FILE_NAME) : null;
e73a4ba5 629
aa353506 630 final SynchronizationAlgorithm syncAlgo = SynchronizationManager.synchronizeTraces(syncFile, Collections.singleton(this), doSync);
e73a4ba5 631
4d2a4a2c 632 final TmfTraceSynchronizedSignal signal = new TmfTraceSynchronizedSignal(this, syncAlgo);
e73a4ba5 633
4d2a4a2c
GB
634 /* Broadcast in separate thread to prevent deadlock */
635 new Thread() {
636 @Override
637 public void run() {
638 broadcast(signal);
639 }
640 }.start();
e73a4ba5 641
4d2a4a2c
GB
642 return syncAlgo;
643 } finally {
644 fSyncLock.unlock();
645 }
e73a4ba5
GB
646 }
647
a79913eb 648 @Override
3b38ea61 649 @SuppressWarnings("nls")
5419a136 650 public synchronized String toString() {
a79913eb
FC
651 return "[TmfExperiment (" + getName() + ")]";
652 }
8c8bf09f
ASL
653
654 // ------------------------------------------------------------------------
9e0640dc 655 // Streaming support
8c8bf09f
ASL
656 // ------------------------------------------------------------------------
657
1b70b6dc 658 private synchronized void initializeStreamingMonitor() {
9e0640dc
FC
659
660 if (fInitialized) {
828e5592 661 return;
9e0640dc 662 }
828e5592
PT
663 fInitialized = true;
664
1b70b6dc 665 if (getStreamingInterval() == 0) {
0316808c 666 final ITmfContext context = seekEvent(0);
cbdacf03 667 final ITmfEvent event = getNext(context);
4c9f2944 668 context.dispose();
9b749023 669 if (event == null) {
1b70b6dc 670 return;
9b749023 671 }
4593bd5b 672 final TmfTimeRange timeRange = new TmfTimeRange(event.getTimestamp(), TmfTimestamp.BIG_CRUNCH);
faa38350 673 final TmfTraceRangeUpdatedSignal signal = new TmfTraceRangeUpdatedSignal(this, this, timeRange);
828e5592
PT
674
675 // Broadcast in separate thread to prevent deadlock
676 new Thread() {
677 @Override
678 public void run() {
679 broadcast(signal);
680 }
681 }.start();
1b70b6dc
PT
682 return;
683 }
684
9e0640dc 685 final Thread thread = new Thread("Streaming Monitor for experiment " + getName()) { //$NON-NLS-1$
bcbea6a6 686 private ITmfTimestamp safeTimestamp = null;
6be2d5cc 687 private ITmfTimestamp lastSafeTimestamp = null;
bcbea6a6 688 private TmfTimeRange timeRange = null;
1b70b6dc
PT
689
690 @Override
691 public void run() {
fc7cd0be 692 while (!executorIsShutdown()) {
9e0640dc 693 if (!getIndexer().isIndexing()) {
a4115405
FC
694 ITmfTimestamp startTimestamp = TmfTimestamp.BIG_CRUNCH;
695 ITmfTimestamp endTimestamp = TmfTimestamp.BIG_BANG;
fa62dc1d
BH
696
697 for (final ITmfTrace trace : getChildren(ITmfTrace.class)) {
9b749023 698 if (trace.getStartTime().compareTo(startTimestamp) < 0) {
1b70b6dc 699 startTimestamp = trace.getStartTime();
9b749023
AM
700 }
701 if (trace.getStreamingInterval() != 0 && trace.getEndTime().compareTo(endTimestamp) > 0) {
1b70b6dc 702 endTimestamp = trace.getEndTime();
9b749023 703 }
1b70b6dc 704 }
6cfc180e
GB
705 ITmfTimestamp safeTs = safeTimestamp;
706 if (safeTs != null && (lastSafeTimestamp == null || safeTs.compareTo(lastSafeTimestamp) > 0)) {
707 timeRange = new TmfTimeRange(startTimestamp, safeTs);
708 lastSafeTimestamp = safeTs;
9b749023 709 } else {
1b70b6dc 710 timeRange = null;
9b749023 711 }
1b70b6dc
PT
712 safeTimestamp = endTimestamp;
713 if (timeRange != null) {
38db0431 714 final TmfTraceRangeUpdatedSignal signal = new TmfTraceRangeUpdatedSignal(TmfExperiment.this, TmfExperiment.this, timeRange);
1b70b6dc
PT
715 broadcast(signal);
716 }
717 }
718 try {
719 Thread.sleep(getStreamingInterval());
cbdacf03 720 } catch (final InterruptedException e) {
1b70b6dc
PT
721 e.printStackTrace();
722 }
723 }
724 }
725 };
726 thread.start();
727 }
728
1b70b6dc
PT
729 @Override
730 public long getStreamingInterval() {
731 long interval = 0;
fa62dc1d 732 for (final ITmfTrace trace : getChildren(ITmfTrace.class)) {
1b70b6dc 733 interval = Math.max(interval, trace.getStreamingInterval());
9b749023 734 }
1b70b6dc
PT
735 return interval;
736 }
737
8c8bf09f
ASL
738 // ------------------------------------------------------------------------
739 // Signal handlers
740 // ------------------------------------------------------------------------
741
faa38350 742 @Override
9e0640dc 743 @TmfSignalHandler
faa38350 744 public void traceOpened(TmfTraceOpenedSignal signal) {
9e0640dc 745 if (signal.getTrace() == this) {
faa38350 746 initializeStreamingMonitor();
9928ddeb
GB
747
748 /* Initialize the analysis */
749 MultiStatus status = new MultiStatus(Activator.PLUGIN_ID, IStatus.OK, null, null);
750 status.add(executeAnalysis());
751 if (!status.isOK()) {
752 Activator.log(status);
753 }
b5e8ee95 754 TmfTraceManager.refreshSupplementaryFiles(this);
9e0640dc 755 }
a1091415
PT
756 }
757
032ecd45
MAL
758 @Override
759 public synchronized int getCheckpointSize() {
760 int totalCheckpointSize = 0;
761 try {
fa62dc1d
BH
762 List<ITmfTrace> children = getChildren(ITmfTrace.class);
763 for (ITmfTrace trace : children) {
764 if (!(trace instanceof ITmfPersistentlyIndexable)) {
765 return 0;
766 }
032ecd45 767
fa62dc1d
BH
768 ITmfPersistentlyIndexable persistableIndexTrace = (ITmfPersistentlyIndexable) trace;
769 int currentTraceCheckpointSize = persistableIndexTrace.getCheckpointSize();
770 if (currentTraceCheckpointSize <= 0) {
771 return 0;
032ecd45 772 }
fa62dc1d
BH
773 totalCheckpointSize += currentTraceCheckpointSize;
774 // each entry in the TmfLocationArray has a rank in addition
775 // of the location
776 totalCheckpointSize += 8;
032ecd45
MAL
777 }
778 } catch (UnsupportedOperationException e) {
779 return 0;
780 }
781
782 return totalCheckpointSize;
783 }
784
785 @Override
786 public ITmfLocation restoreLocation(ByteBuffer bufferIn) {
fa62dc1d
BH
787 List<ITmfTrace> children = getChildren(ITmfTrace.class);
788 int length = children.size();
789 ITmfLocation[] locations = new ITmfLocation[length];
790 long[] ranks = new long[length];
791 for (int i = 0; i < length; ++i) {
792 final ITmfTrace trace = children.get(i);
032ecd45
MAL
793 locations[i] = ((ITmfPersistentlyIndexable) trace).restoreLocation(bufferIn);
794 ranks[i] = bufferIn.getLong();
795 }
796 TmfLocationArray arr = new TmfLocationArray(locations, ranks);
797 TmfExperimentLocation l = new TmfExperimentLocation(arr);
798 return l;
799 }
4dc47e28 800}
This page took 0.188648 seconds and 5 git commands to generate.