Skip to content

Commit d104da0

Browse files
committed
tmf: Allow TmfTrace to refresh it's analysis modules
With this API analysis modules can be added or removed through the analysis framework while trace is open. [Added] API to refresh analysis modules of an ITmfTrace. Change-Id: Ie447bf0739e64ceb4487b48a4f0166e1f3aac62c Signed-off-by: Bernd Hufmann <bernd.hufmann@ericsson.com>
1 parent 237aed6 commit d104da0

5 files changed

Lines changed: 167 additions & 29 deletions

File tree

tmf/org.eclipse.tracecompass.tmf.core.tests/src/org/eclipse/tracecompass/tmf/core/tests/analysis/AnalysisManagerTest.java

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,16 @@
2121

2222
import java.util.Collection;
2323
import java.util.Map;
24+
import java.util.stream.StreamSupport;
2425

26+
import org.eclipse.core.runtime.IStatus;
2527
import org.eclipse.jdt.annotation.NonNull;
28+
import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule;
2629
import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModuleHelper;
2730
import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModuleSource;
2831
import org.eclipse.tracecompass.tmf.core.analysis.TmfAnalysisManager;
32+
import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
33+
import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
2934
import org.eclipse.tracecompass.tmf.core.tests.shared.TmfTestTrace;
3035
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
3136
import org.eclipse.tracecompass.tmf.tests.stubs.analysis.AnalysisModuleSourceStub;
@@ -137,14 +142,75 @@ public void testSources() {
137142
assertFalse(map.containsKey(AnalysisModuleTestHelper.moduleStubEnum.TEST2.name()));
138143

139144
/* Add new source */
140-
TmfAnalysisManager.registerModuleSource(new AnalysisModuleSourceStub());
145+
AnalysisModuleSourceStub stub = new AnalysisModuleSourceStub();
146+
TmfAnalysisManager.registerModuleSource(stub);
147+
try {
148+
/* Now make sure the modules are present */
149+
map = TmfAnalysisManager.getAnalysisModules(traceClass);
150+
assertTrue(map.containsKey(AnalysisModuleTestHelper.moduleStubEnum.TEST.name()));
151+
152+
map = TmfAnalysisManager.getAnalysisModules(ftraceClass);
153+
assertTrue(map.containsKey(AnalysisModuleTestHelper.moduleStubEnum.TEST2.name()));
154+
} finally {
155+
// Make sure source is removed after test
156+
TmfAnalysisManager.deregisterModuleSource(stub);
157+
trace.dispose();
158+
}
159+
}
141160

142-
/* Now make sure the modules are present */
143-
map = TmfAnalysisManager.getAnalysisModules(traceClass);
144-
assertTrue(map.containsKey(AnalysisModuleTestHelper.moduleStubEnum.TEST.name()));
161+
/**
162+
* Test suite to test refresh of analysis module when adding a {@link IAnalysisModuleSource}
163+
*/
164+
@Test
165+
public void testRefreshModules() {
166+
/* Make sure that modules in the new source are not in the list already */
167+
/* Generic TmfTrace */
168+
ITmfTrace trace = TmfTestTrace.A_TEST_10K.getTrace();
145169

146-
map = TmfAnalysisManager.getAnalysisModules(ftraceClass);
147-
assertTrue(map.containsKey(AnalysisModuleTestHelper.moduleStubEnum.TEST2.name()));
170+
/* Trigger trace.executeAnalysis() to populate its analysis modules through open signal */
171+
TmfSignalManager.dispatchSignal(new TmfTraceOpenedSignal(this, trace, null));
172+
@NonNull Iterable<@NonNull IAnalysisModule> modules = trace.getAnalysisModules();
173+
/* Test that specific signals are not there (yet)*/
174+
assertFalse(StreamSupport.stream(modules.spliterator(), false).anyMatch(module -> module.getId().equals(AnalysisModuleTestHelper.moduleStubEnum.TEST.name())));
175+
176+
/* Add new source */
177+
AnalysisModuleSourceStub stub = new AnalysisModuleSourceStub();
178+
TmfAnalysisManager.registerModuleSource(stub);
179+
180+
try {
181+
/* Now check that the modules are not part of the trace yet */
182+
modules = trace.getAnalysisModules();
183+
assertFalse(StreamSupport.stream(modules.spliterator(), false).anyMatch(module -> module.getId().equals(AnalysisModuleTestHelper.moduleStubEnum.TEST.name())));
184+
long before = StreamSupport.stream(modules.spliterator(), false).count();
185+
186+
/* Refresh the analysis */
187+
IStatus status = trace.refreshAnalysisModules();
188+
assertTrue(status.isOK());
189+
190+
/* Now check that the modules are part of the trace */
191+
modules = trace.getAnalysisModules();
192+
long after = StreamSupport.stream(modules.spliterator(), false).count();
193+
assertTrue(after == before + 1);
194+
assertTrue(StreamSupport.stream(modules.spliterator(), false).anyMatch(module -> module.getId().equals(AnalysisModuleTestHelper.moduleStubEnum.TEST.name())));
195+
196+
before = after;
197+
/* Remove source again */
198+
TmfAnalysisManager.deregisterModuleSource(stub);
199+
200+
/* Refresh the analysis */
201+
status = trace.refreshAnalysisModules();
202+
assertTrue(status.isOK());
203+
204+
/* Now check that the modules are not part of the trace anymore */
205+
modules = trace.getAnalysisModules();
206+
after = StreamSupport.stream(modules.spliterator(), false).count();
207+
assertTrue(after == before - 1);
208+
assertFalse(StreamSupport.stream(modules.spliterator(), false).anyMatch(module -> module.getId().equals(AnalysisModuleTestHelper.moduleStubEnum.TEST.name())));
209+
} finally {
210+
// Make sure source is removed after test
211+
TmfAnalysisManager.deregisterModuleSource(stub);
212+
trace.dispose();
213+
}
148214
}
149215

150216
}

tmf/org.eclipse.tracecompass.tmf.core/META-INF/MANIFEST.MF

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
22
Bundle-ManifestVersion: 2
33
Bundle-Name: %Bundle-Name
44
Bundle-Vendor: %Bundle-Vendor
5-
Bundle-Version: 9.3.0.qualifier
5+
Bundle-Version: 9.4.0.qualifier
66
Bundle-Localization: plugin
77
Bundle-SymbolicName: org.eclipse.tracecompass.tmf.core;singleton:=true
88
Bundle-Activator: org.eclipse.tracecompass.internal.tmf.core.Activator

tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/analysis/TmfAnalysisManager.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,18 @@ public static synchronized void registerModuleSource(IAnalysisModuleSource sourc
8181
refreshModules();
8282
}
8383

84+
/**
85+
* Deregisters a source of modules
86+
*
87+
* @param source
88+
* A {@link IAnalysisModuleSource} instance
89+
* @since 9.4
90+
*/
91+
public static synchronized void deregisterModuleSource(IAnalysisModuleSource source) {
92+
fSources.remove(source);
93+
refreshModules();
94+
}
95+
8496
/**
8597
* Initializes sources and new module listeners from the extension point
8698
*/

tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/trace/ITmfTrace.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.eclipse.core.resources.IProject;
2828
import org.eclipse.core.resources.IResource;
2929
import org.eclipse.core.runtime.IStatus;
30+
import org.eclipse.core.runtime.Status;
3031
import org.eclipse.jdt.annotation.NonNull;
3132
import org.eclipse.jdt.annotation.Nullable;
3233
import org.eclipse.tracecompass.common.core.math.SaturatedArithmetic;
@@ -272,6 +273,17 @@ public interface ITmfTrace extends ITmfEventProvider {
272273
*/
273274
@NonNull Iterable<@NonNull IAnalysisModule> getAnalysisModules();
274275

276+
/**
277+
* Refresh the analysis modules for this traces
278+
*
279+
* @return An IStatus indicating whether the analysis could be run
280+
* successfully or not
281+
* @since 9.4
282+
*/
283+
default IStatus refreshAnalysisModules() {
284+
return Status.OK_STATUS;
285+
}
286+
275287
// ------------------------------------------------------------------------
276288
// Aspect getters
277289
// ------------------------------------------------------------------------

tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/trace/TmfTrace.java

Lines changed: 70 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@
2121
import java.io.File;
2222
import java.util.Collection;
2323
import java.util.Collections;
24+
import java.util.HashMap;
2425
import java.util.HashSet;
2526
import java.util.LinkedHashMap;
2627
import java.util.List;
2728
import java.util.Map;
29+
import java.util.Set;
2830

2931
import org.eclipse.core.resources.IResource;
3032
import org.eclipse.core.runtime.IAdaptable;
@@ -142,6 +144,10 @@ public abstract class TmfTrace extends TmfEventProvider implements ITmfTrace, IT
142144
private final Map<String, IAnalysisModule> fAnalysisModules =
143145
Collections.synchronizedMap(new LinkedHashMap<String, IAnalysisModule>());
144146

147+
// Analysis modules that were removed during lifecycle of the trace that need to be disposed
148+
private final Set<IAnalysisModule> fToBeDisposedAnalysisModules =
149+
Collections.synchronizedSet(new HashSet<IAnalysisModule>());
150+
145151
// ------------------------------------------------------------------------
146152
// Construction
147153
// ------------------------------------------------------------------------
@@ -288,29 +294,12 @@ public void indexTrace(boolean waitForCompletion) {
288294
* successfully or not
289295
*/
290296
protected IStatus executeAnalysis() {
291-
MultiStatus status = new MultiStatus(Activator.PLUGIN_ID, IStatus.OK, null, null);
292-
293-
/* First modules are initialized */
294-
Map<String, IAnalysisModuleHelper> modules = TmfAnalysisManager.getAnalysisModules(this.getClass());
295-
for (IAnalysisModuleHelper helper : modules.values()) {
296-
try {
297-
IAnalysisModule module = helper.newModule(this);
298-
if (module == null) {
299-
continue;
300-
}
301-
fAnalysisModules.put(module.getId(), module);
302-
} catch (TmfAnalysisException e) {
303-
status.add(new Status(IStatus.WARNING, Activator.PLUGIN_ID, e.getMessage()));
304-
}
305-
}
297+
return refreshAnalysisModulesImpl();
298+
}
306299

307-
/* Once all modules are initialized, automatic modules are executed */
308-
for (IAnalysisModule module : getAnalysisModules()) {
309-
if (module.isAutomatic()) {
310-
status.add(module.schedule());
311-
}
312-
}
313-
return status;
300+
@Override
301+
public IStatus refreshAnalysisModules() {
302+
return refreshAnalysisModulesImpl();
314303
}
315304

316305
@Override
@@ -349,6 +338,13 @@ public synchronized void dispose() {
349338
}
350339
fAnalysisModules.clear();
351340

341+
/* Clean up the analysis modules removed during lifecycle of trace */
342+
analysisModules = fToBeDisposedAnalysisModules;
343+
for (IAnalysisModule module : analysisModules) {
344+
module.dispose();
345+
}
346+
fToBeDisposedAnalysisModules.clear();
347+
352348
super.dispose();
353349
ByteBufferTracker.setMarked();
354350
}
@@ -784,4 +780,56 @@ public void setComplete(boolean isComplete) {
784780
* reading (traces in an incomplete state)
785781
*/
786782
}
783+
784+
private IStatus refreshAnalysisModulesImpl() {
785+
Map<String, IAnalysisModule> previousAnalysisModules = new HashMap<>(fAnalysisModules);
786+
Map<String, IAnalysisModule> newAnalysisModules = new HashMap<>();
787+
MultiStatus status = new MultiStatus(Activator.PLUGIN_ID, IStatus.OK, null, null);
788+
/* First modules are initialized */
789+
Map<String, IAnalysisModuleHelper> modules = TmfAnalysisManager.getAnalysisModules(this.getClass());
790+
for (IAnalysisModuleHelper helper : modules.values()) {
791+
try {
792+
IAnalysisModule module = helper.newModule(this);
793+
if (module == null) {
794+
continue;
795+
}
796+
newAnalysisModules.put(module.getId(), module);
797+
} catch (TmfAnalysisException e) {
798+
status.add(new Status(IStatus.WARNING, Activator.PLUGIN_ID, e.getMessage()));
799+
}
800+
}
801+
802+
Set<String> oldAnalysisModulesKeys = new HashSet<>(previousAnalysisModules.keySet());
803+
Set<String> keys = new HashSet<>(newAnalysisModules.keySet());
804+
805+
for (String key : keys) {
806+
IAnalysisModule module = newAnalysisModules.remove(key);
807+
if (!oldAnalysisModulesKeys.contains(key)) {
808+
/* Once all modules are initialized, automatic modules are executed */
809+
if (module != null && module.isAutomatic()) {
810+
status.add(module.schedule());
811+
}
812+
previousAnalysisModules.put(key, module);
813+
} else {
814+
oldAnalysisModulesKeys.remove(key);
815+
if (module != null) {
816+
module.dispose();
817+
}
818+
}
819+
}
820+
821+
/* Remove all remaining analysis modules */
822+
for (String key : oldAnalysisModulesKeys) {
823+
IAnalysisModule analysisModule = previousAnalysisModules.remove(key);
824+
if (analysisModule != null) {
825+
fToBeDisposedAnalysisModules.add(analysisModule);
826+
}
827+
}
828+
/* Update fAnalysis with current list of analysis modules */
829+
synchronized (fAnalysisModules) {
830+
fAnalysisModules.clear();
831+
fAnalysisModules.putAll(previousAnalysisModules);
832+
}
833+
return status;
834+
}
787835
}

0 commit comments

Comments
 (0)