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