TMF: Add utility method to return the result of an aspect for an event
[deliverable/tracecompass.git] / org.eclipse.tracecompass.tmf.core / src / org / eclipse / tracecompass / tmf / core / statesystem / TmfStateSystemAnalysisModule.java
CommitLineData
8a6ff07f 1/*******************************************************************************
ed902a2b 2 * Copyright (c) 2013, 2015 École Polytechnique de Montréal
8a6ff07f
GB
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 * Geneviève Bastien - Initial API and implementation
baa96b1d 11 * Bernd Hufmann - Integrated history builder functionality
8a6ff07f
GB
12 *******************************************************************************/
13
2bdf0193 14package org.eclipse.tracecompass.tmf.core.statesystem;
8a6ff07f 15
5db5a3a4
AM
16import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
17
8a6ff07f 18import java.io.File;
baa96b1d 19import java.io.IOException;
5237a931 20import java.util.Collections;
09ec275e 21import java.util.concurrent.CountDownLatch;
8a6ff07f
GB
22
23import org.eclipse.core.runtime.IProgressMonitor;
e1c415b3 24import org.eclipse.core.runtime.IStatus;
baa96b1d 25import org.eclipse.core.runtime.NullProgressMonitor;
baa96b1d 26import org.eclipse.jdt.annotation.Nullable;
2bdf0193
AM
27import org.eclipse.tracecompass.internal.tmf.core.statesystem.backends.partial.PartialHistoryBackend;
28import org.eclipse.tracecompass.internal.tmf.core.statesystem.backends.partial.PartialStateSystem;
e894a508
AM
29import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
30import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
31import org.eclipse.tracecompass.statesystem.core.StateSystemFactory;
32import org.eclipse.tracecompass.statesystem.core.backend.IStateHistoryBackend;
33import org.eclipse.tracecompass.statesystem.core.backend.InMemoryBackend;
34import org.eclipse.tracecompass.statesystem.core.backend.NullBackend;
35import org.eclipse.tracecompass.statesystem.core.backend.historytree.HistoryTreeBackend;
36import org.eclipse.tracecompass.statesystem.core.backend.historytree.ThreadedHistoryTreeBackend;
2bdf0193
AM
37import org.eclipse.tracecompass.tmf.core.analysis.TmfAbstractAnalysisModule;
38import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
39import org.eclipse.tracecompass.tmf.core.exceptions.TmfTraceException;
40import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest;
41import org.eclipse.tracecompass.tmf.core.request.TmfEventRequest;
de83d1ab
MAL
42import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
43import org.eclipse.tracecompass.tmf.core.signal.TmfTraceRangeUpdatedSignal;
2bdf0193
AM
44import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
45import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
de83d1ab 46import org.eclipse.tracecompass.tmf.core.trace.ITmfTraceCompleteness;
2bdf0193 47import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
b8585c7c 48import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
5c5fa260 49import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperiment;
8a6ff07f
GB
50
51/**
52 * Abstract analysis module to generate a state system. It is a base class that
53 * can be used as a shortcut by analysis who just need to build a single state
54 * system with a state provider.
55 *
56 * Analysis implementing this class should only need to provide a state system
57 * and optionally a backend (default to NULL) and, if required, a filename
58 * (defaults to the analysis'ID)
59 *
60 * @author Geneviève Bastien
61 * @since 3.0
62 */
63public abstract class TmfStateSystemAnalysisModule extends TmfAbstractAnalysisModule
5237a931 64 implements ITmfAnalysisModuleWithStateSystems {
8a6ff07f 65
8a6ff07f
GB
66 private static final String EXTENSION = ".ht"; //$NON-NLS-1$
67
09ec275e 68 private final CountDownLatch fInitialized = new CountDownLatch(1);
de83d1ab 69 private final Object fRequestSyncObj = new Object();
09ec275e 70
baa96b1d
BH
71 @Nullable private ITmfStateSystemBuilder fStateSystem;
72 @Nullable private ITmfStateProvider fStateProvider;
73 @Nullable private IStateHistoryBackend fHtBackend;
74 @Nullable private ITmfEventRequest fRequest;
de83d1ab
MAL
75 @Nullable private TmfTimeRange fTimeRange = null;
76
77 private int fNbRead = 0;
5237a931 78
8a6ff07f
GB
79 /**
80 * State system backend types
81 *
82 * @author Geneviève Bastien
83 */
84 protected enum StateSystemBackendType {
85 /** Full history in file */
86 FULL,
87 /** In memory state system */
88 INMEM,
89 /** Null history */
90 NULL,
91 /** State system backed with partial history */
92 PARTIAL
93 }
94
72221aa4
AM
95 /**
96 * Retrieve a state system belonging to trace, by passing the ID of the
97 * relevant analysis module.
98 *
99 * This will start the execution of the analysis module, and start the
100 * construction of the state system, if needed.
101 *
102 * @param trace
103 * The trace for which you want the state system
104 * @param moduleId
105 * The ID of the state system analysis module
106 * @return The state system, or null if there was no match
107 * @since 3.1
108 */
109 public static @Nullable ITmfStateSystem getStateSystem(ITmfTrace trace, String moduleId) {
110 TmfStateSystemAnalysisModule module =
b8585c7c 111 TmfTraceUtils.getAnalysisModuleOfClass(trace, TmfStateSystemAnalysisModule.class, moduleId);
72221aa4 112 if (module != null) {
e1c415b3
BH
113 IStatus status = module.schedule();
114 if (status.isOK()) {
115 module.waitForInitialization();
e1c415b3
BH
116 return module.getStateSystem();
117 }
72221aa4
AM
118 }
119 return null;
120 }
121
96811390
GB
122 /**
123 * Retrieve a state system belonging to trace, by passing the class of the
124 * relevant analysis module. If many modules of the same class exists, the
125 * state system of the first one will be returned.
126 *
127 * This will start the execution of the analysis module, and start the
128 * construction of the state system, if needed.
129 *
130 * @param trace
131 * The trace for which you want the state system
132 * @param clazz
133 * The class of the state system module to retrieve
134 * @return The state system, or null if there was no match
135 */
136 public static @Nullable ITmfStateSystem getStateSystemByModuleClass(ITmfTrace trace, Class<? extends TmfStateSystemAnalysisModule> clazz) {
137 TmfStateSystemAnalysisModule module = null;
138 for (TmfStateSystemAnalysisModule mod : TmfTraceUtils.getAnalysisModulesOfClass(trace, clazz)) {
139 module = mod;
140 break;
141 }
142 if (module != null) {
143 IStatus status = module.schedule();
144 if (status.isOK()) {
145 module.waitForInitialization();
146 return module.getStateSystem();
147 }
148 }
149 return null;
150 }
151
8a6ff07f
GB
152 /**
153 * Get the state provider for this analysis module
154 *
155 * @return the state provider
156 */
8a6ff07f
GB
157 protected abstract ITmfStateProvider createStateProvider();
158
159 /**
160 * Get the state system backend type used by this module
161 *
162 * @return The {@link StateSystemBackendType}
163 */
a3b864c0
AM
164 protected StateSystemBackendType getBackendType() {
165 /* Using full history by default, sub-classes can override */
166 return StateSystemBackendType.FULL;
167 }
8a6ff07f
GB
168
169 /**
170 * Get the supplementary file name where to save this state system. The
171 * default is the ID of the analysis followed by the extension.
172 *
173 * @return The supplementary file name
174 */
175 protected String getSsFileName() {
176 return getId() + EXTENSION;
177 }
178
179 /**
baa96b1d
BH
180 * Get the state system generated by this analysis, or null if it is not yet
181 * created.
8a6ff07f
GB
182 *
183 * @return The state system
184 */
baa96b1d 185 @Nullable
8a6ff07f
GB
186 public ITmfStateSystem getStateSystem() {
187 return fStateSystem;
188 }
189
09ec275e
AM
190 /**
191 * Block the calling thread until the analysis module has been initialized.
192 * After this method returns, {@link #getStateSystem()} should not return
193 * null anymore.
194 */
195 public void waitForInitialization() {
196 try {
197 fInitialized.await();
198 } catch (InterruptedException e) {}
199 }
200
baa96b1d
BH
201 // ------------------------------------------------------------------------
202 // TmfAbstractAnalysisModule
203 // ------------------------------------------------------------------------
8a6ff07f 204
baa96b1d
BH
205 @Override
206 protected boolean executeAnalysis(@Nullable final IProgressMonitor monitor) {
207 IProgressMonitor mon = (monitor == null ? new NullProgressMonitor() : monitor);
208 final ITmfStateProvider provider = createStateProvider();
8a6ff07f 209
84a9548a 210 String id = getId();
84a9548a 211
8a6ff07f
GB
212 /* FIXME: State systems should make use of the monitor, to be cancelled */
213 try {
214 /* Get the state system according to backend */
215 StateSystemBackendType backend = getBackendType();
216 String directory;
baa96b1d 217 File htFile;
e1c415b3
BH
218
219 ITmfTrace trace = getTrace();
220 if (trace == null) {
221 // Analysis was cancelled in the meantime
222 fInitialized.countDown();
223 return false;
224 }
8a6ff07f
GB
225 switch (backend) {
226 case FULL:
e1c415b3 227 directory = TmfTraceManager.getSupplementaryFileDir(trace);
baa96b1d 228 htFile = new File(directory + getSsFileName());
84a9548a 229 createFullHistory(id, provider, htFile);
8a6ff07f
GB
230 break;
231 case PARTIAL:
e1c415b3 232 directory = TmfTraceManager.getSupplementaryFileDir(trace);
baa96b1d 233 htFile = new File(directory + getSsFileName());
84a9548a 234 createPartialHistory(id, provider, htFile);
8a6ff07f
GB
235 break;
236 case INMEM:
84a9548a 237 createInMemoryHistory(id, provider);
8a6ff07f
GB
238 break;
239 case NULL:
84a9548a 240 createNullHistory(id, provider);
8a6ff07f
GB
241 break;
242 default:
243 break;
244 }
245 } catch (TmfTraceException e) {
e1c415b3 246 fInitialized.countDown();
8a6ff07f
GB
247 return false;
248 }
baa96b1d 249 return !mon.isCanceled();
8a6ff07f
GB
250 }
251
252 @Override
253 protected void canceling() {
baa96b1d
BH
254 ITmfEventRequest req = fRequest;
255 if ((req != null) && (!req.isCompleted())) {
256 req.cancel();
257 }
258 }
259
a1529f38
AM
260 @Override
261 public void dispose() {
130e6f4e 262 super.dispose();
a1529f38
AM
263 if (fStateSystem != null) {
264 fStateSystem.dispose();
265 }
a1529f38
AM
266 }
267
baa96b1d
BH
268 // ------------------------------------------------------------------------
269 // History creation methods
270 // ------------------------------------------------------------------------
271
272 /*
273 * Load the history file matching the target trace. If the file already
274 * exists, it will be opened directly. If not, it will be created from
275 * scratch.
276 */
84a9548a 277 private void createFullHistory(String id, ITmfStateProvider provider, File htFile) throws TmfTraceException {
baa96b1d
BH
278
279 /* If the target file already exists, do not rebuild it uselessly */
280 // TODO for now we assume it's complete. Might be a good idea to check
281 // at least if its range matches the trace's range.
282
283 if (htFile.exists()) {
284 /* Load an existing history */
285 final int version = provider.getVersion();
286 try {
84a9548a
AM
287 IStateHistoryBackend backend = new HistoryTreeBackend(htFile, version);
288 fHtBackend = backend;
bcec0116 289 fStateSystem = StateSystemFactory.newStateSystem(id, backend, false);
09ec275e 290 fInitialized.countDown();
baa96b1d
BH
291 return;
292 } catch (IOException e) {
293 /*
294 * There was an error opening the existing file. Perhaps it was
295 * corrupted, perhaps it's an old version? We'll just
296 * fall-through and try to build a new one from scratch instead.
297 */
298 }
299 }
300
301 /* Size of the blocking queue to use when building a state history */
302 final int QUEUE_SIZE = 10000;
303
304 try {
84a9548a 305 IStateHistoryBackend backend = new ThreadedHistoryTreeBackend(htFile,
baa96b1d 306 provider.getStartTime(), provider.getVersion(), QUEUE_SIZE);
84a9548a 307 fHtBackend = backend;
bcec0116 308 fStateSystem = StateSystemFactory.newStateSystem(id, backend);
baa96b1d
BH
309 provider.assignTargetStateSystem(fStateSystem);
310 build(provider);
311 } catch (IOException e) {
312 /*
313 * If it fails here however, it means there was a problem writing to
314 * the disk, so throw a real exception this time.
315 */
316 throw new TmfTraceException(e.toString(), e);
317 }
318 }
319
320 /*
321 * Create a new state system backed with a partial history. A partial
322 * history is similar to a "full" one (which you get with
323 * {@link #newFullHistory}), except that the file on disk is much smaller,
324 * but queries are a bit slower.
325 *
326 * Also note that single-queries are implemented using a full-query
327 * underneath, (which are much slower), so this might not be a good fit for
328 * a use case where you have to do lots of single queries.
329 */
84a9548a 330 private void createPartialHistory(String id, ITmfStateProvider provider, File htPartialFile)
baa96b1d
BH
331 throws TmfTraceException {
332 /*
333 * The order of initializations is very tricky (but very important!)
334 * here. We need to follow this pattern:
335 * (1 is done before the call to this method)
336 *
337 * 1- Instantiate realStateProvider
338 * 2- Instantiate realBackend
339 * 3- Instantiate partialBackend, with prereqs:
340 * 3a- Instantiate partialProvider, via realProvider.getNew()
341 * 3b- Instantiate nullBackend (partialSS's backend)
342 * 3c- Instantiate partialSS
343 * 3d- partialProvider.assignSS(partialSS)
344 * 4- Instantiate realSS
345 * 5- partialSS.assignUpstream(realSS)
346 * 6- realProvider.assignSS(realSS)
347 * 7- Call HistoryBuilder(realProvider, realSS, partialBackend) to build the thing.
348 */
349
350 /* Size of the blocking queue to use when building a state history */
351 final int QUEUE_SIZE = 10000;
352
353 final long granularity = 50000;
354
355 /* 2 */
356 IStateHistoryBackend realBackend = null;
357 try {
358 realBackend = new ThreadedHistoryTreeBackend(htPartialFile,
359 provider.getStartTime(), provider.getVersion(), QUEUE_SIZE);
360 } catch (IOException e) {
361 throw new TmfTraceException(e.toString(), e);
362 }
363
364 /* 3a */
365 ITmfStateProvider partialProvider = provider.getNewInstance();
366
367 /* 3b-3c, constructor automatically uses a NullBackend */
368 PartialStateSystem pss = new PartialStateSystem();
369
370 /* 3d */
371 partialProvider.assignTargetStateSystem(pss);
372
373 /* 3 */
374 IStateHistoryBackend partialBackend =
375 new PartialHistoryBackend(partialProvider, pss, realBackend, granularity);
376
377 /* 4 */
bcec0116 378 @SuppressWarnings("restriction")
e894a508
AM
379 org.eclipse.tracecompass.internal.statesystem.core.StateSystem realSS =
380 (org.eclipse.tracecompass.internal.statesystem.core.StateSystem) StateSystemFactory.newStateSystem(id, partialBackend);
baa96b1d
BH
381
382 /* 5 */
383 pss.assignUpstream(realSS);
384
385 /* 6 */
386 provider.assignTargetStateSystem(realSS);
387
388 /* 7 */
389 fHtBackend = partialBackend;
390 fStateSystem = realSS;
391
392 build(provider);
393 }
394
395 /*
396 * Create a new state system using a null history back-end. This means that
397 * no history intervals will be saved anywhere, and as such only
398 * {@link ITmfStateSystem#queryOngoingState} will be available.
399 */
84a9548a
AM
400 private void createNullHistory(String id, ITmfStateProvider provider) {
401 IStateHistoryBackend backend = new NullBackend();
402 fHtBackend = backend;
bcec0116 403 fStateSystem = StateSystemFactory.newStateSystem(id, backend);
baa96b1d
BH
404 provider.assignTargetStateSystem(fStateSystem);
405 build(provider);
406 }
407
408 /*
409 * Create a new state system using in-memory interval storage. This should
410 * only be done for very small state system, and will be naturally limited
411 * to 2^31 intervals.
412 */
84a9548a
AM
413 private void createInMemoryHistory(String id, ITmfStateProvider provider) {
414 IStateHistoryBackend backend = new InMemoryBackend(provider.getStartTime());
415 fHtBackend = backend;
bcec0116 416 fStateSystem = StateSystemFactory.newStateSystem(id, backend);
baa96b1d
BH
417 provider.assignTargetStateSystem(fStateSystem);
418 build(provider);
419 }
420
a1529f38 421 private void disposeProvider(boolean deleteFiles) {
baa96b1d
BH
422 ITmfStateProvider provider = fStateProvider;
423 if (provider != null) {
424 provider.dispose();
425 }
426 if (deleteFiles && (fHtBackend != null)) {
427 fHtBackend.removeFiles();
428 }
429 }
430
431 private void build(ITmfStateProvider provider) {
432 if ((fStateSystem == null) || (fHtBackend == null)) {
433 throw new IllegalArgumentException();
434 }
435
436 ITmfEventRequest request = fRequest;
437 if ((request != null) && (!request.isCompleted())) {
438 request.cancel();
439 }
440
de83d1ab
MAL
441 fTimeRange = TmfTimeRange.ETERNITY;
442 final ITmfTrace trace = provider.getTrace();
d0c7e4ba 443 if (!isCompleteTrace(trace)) {
de83d1ab
MAL
444 TmfTimeRange traceTimeRange = trace.getTimeRange();
445 if (traceTimeRange != null) {
446 fTimeRange = traceTimeRange;
447 }
448 }
baa96b1d 449
baa96b1d 450 fStateProvider = provider;
de83d1ab
MAL
451 synchronized (fRequestSyncObj) {
452 startRequest();
453 }
baa96b1d 454
09ec275e
AM
455 /*
456 * The state system object is now created, we can consider this module
457 * "initialized" (components can retrieve it and start doing queries).
458 */
459 fInitialized.countDown();
460
461 /*
462 * Block the executeAnalysis() construction is complete (so that the
463 * progress monitor displays that it is running).
464 */
baa96b1d 465 try {
de83d1ab
MAL
466 if (fRequest != null) {
467 fRequest.waitForCompletion();
468 }
baa96b1d
BH
469 } catch (InterruptedException e) {
470 e.printStackTrace();
471 }
472 }
473
474 private class StateSystemEventRequest extends TmfEventRequest {
475 private final ITmfStateProvider sci;
476 private final ITmfTrace trace;
477
de83d1ab 478 public StateSystemEventRequest(ITmfStateProvider sp, TmfTimeRange timeRange, int index) {
baa96b1d 479 super(sp.getExpectedEventType(),
de83d1ab
MAL
480 timeRange,
481 index,
baa96b1d
BH
482 ITmfEventRequest.ALL_DATA,
483 ITmfEventRequest.ExecutionType.BACKGROUND);
484 this.sci = sp;
485
486 // sci.getTrace() will eventually return a @NonNull
5db5a3a4 487 trace = checkNotNull(sci.getTrace());
baa96b1d 488
baa96b1d
BH
489 }
490
491 @Override
41f3b36b 492 public void handleData(final ITmfEvent event) {
baa96b1d 493 super.handleData(event);
41f3b36b 494 if (event.getTrace() == trace) {
baa96b1d 495 sci.processEvent(event);
2d208fb7
GB
496 } else if (trace instanceof TmfExperiment) {
497 /*
498 * If the request is for an experiment, check if the event is
499 * from one of the child trace
500 */
501 for (ITmfTrace childTrace : ((TmfExperiment) trace).getTraces()) {
502 if (childTrace == event.getTrace()) {
503 sci.processEvent(event);
504 }
505 }
baa96b1d
BH
506 }
507 }
508
509 @Override
510 public void handleSuccess() {
511 super.handleSuccess();
de83d1ab
MAL
512 if (isCompleteTrace(trace)) {
513 disposeProvider(false);
514 } else {
515 fNbRead += getNbRead();
516 synchronized (fRequestSyncObj) {
517 final TmfTimeRange timeRange = fTimeRange;
518 if (timeRange != null) {
519 if (getRange().getEndTime().getValue() < timeRange.getEndTime().getValue()) {
520 startRequest();
521 }
522 }
523 }
524 }
baa96b1d
BH
525 }
526
527 @Override
528 public void handleCancel() {
529 super.handleCancel();
de83d1ab
MAL
530 if (isCompleteTrace(trace)) {
531 disposeProvider(true);
532 }
baa96b1d
BH
533 }
534
535 @Override
536 public void handleFailure() {
537 super.handleFailure();
a1529f38 538 disposeProvider(true);
baa96b1d 539 }
8a6ff07f
GB
540 }
541
5237a931
AM
542 // ------------------------------------------------------------------------
543 // ITmfAnalysisModuleWithStateSystems
544 // ------------------------------------------------------------------------
545
546 @Override
baa96b1d
BH
547 @Nullable
548 public ITmfStateSystem getStateSystem(String id) {
5237a931
AM
549 if (id.equals(getId())) {
550 return fStateSystem;
551 }
552 return null;
553 }
554
8a6ff07f 555 @Override
5237a931 556 public Iterable<ITmfStateSystem> getStateSystems() {
5db5a3a4 557 return checkNotNull(Collections.<ITmfStateSystem> singleton(fStateSystem));
8a6ff07f 558 }
de83d1ab
MAL
559
560 /**
561 * Signal handler for the TmfTraceRangeUpdatedSignal signal
562 *
563 * @param signal The incoming signal
564 */
565 @TmfSignalHandler
566 public void traceRangeUpdated(final TmfTraceRangeUpdatedSignal signal) {
567 fTimeRange = signal.getRange();
568 ITmfStateProvider stateProvider = fStateProvider;
569 synchronized (fRequestSyncObj) {
570 if (signal.getTrace() == getTrace() && stateProvider != null && stateProvider.getAssignedStateSystem() != null) {
571 ITmfEventRequest request = fRequest;
572 if ((request == null) || request.isCompleted()) {
573 startRequest();
574 }
575 }
576 }
577 }
578
579 private void startRequest() {
580 ITmfStateProvider stateProvider = fStateProvider;
581 TmfTimeRange timeRange = fTimeRange;
582 if (stateProvider == null || timeRange == null) {
583 return;
584 }
585 ITmfEventRequest request = new StateSystemEventRequest(stateProvider, timeRange, fNbRead);
586 stateProvider.getTrace().sendRequest(request);
587 fRequest = request;
588 }
589
590 private static boolean isCompleteTrace(ITmfTrace trace) {
591 return !(trace instanceof ITmfTraceCompleteness) || ((ITmfTraceCompleteness) trace).isComplete();
592 }
8a6ff07f 593}
This page took 0.080594 seconds and 5 git commands to generate.