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