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