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