Skip to content

Commit

Permalink
tmf: Allow TmfTrace to refresh it's analysis modules
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
bhufmann committed Jul 11, 2024
1 parent 237aed6 commit d104da0
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,16 @@

import java.util.Collection;
import java.util.Map;
import java.util.stream.StreamSupport;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule;
import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModuleHelper;
import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModuleSource;
import org.eclipse.tracecompass.tmf.core.analysis.TmfAnalysisManager;
import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
import org.eclipse.tracecompass.tmf.core.tests.shared.TmfTestTrace;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.tests.stubs.analysis.AnalysisModuleSourceStub;
Expand Down Expand Up @@ -137,14 +142,75 @@ public void testSources() {
assertFalse(map.containsKey(AnalysisModuleTestHelper.moduleStubEnum.TEST2.name()));

/* Add new source */
TmfAnalysisManager.registerModuleSource(new AnalysisModuleSourceStub());
AnalysisModuleSourceStub stub = new AnalysisModuleSourceStub();
TmfAnalysisManager.registerModuleSource(stub);
try {
/* Now make sure the modules are present */
map = TmfAnalysisManager.getAnalysisModules(traceClass);
assertTrue(map.containsKey(AnalysisModuleTestHelper.moduleStubEnum.TEST.name()));

map = TmfAnalysisManager.getAnalysisModules(ftraceClass);
assertTrue(map.containsKey(AnalysisModuleTestHelper.moduleStubEnum.TEST2.name()));
} finally {
// Make sure source is removed after test
TmfAnalysisManager.deregisterModuleSource(stub);
trace.dispose();
}
}

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

map = TmfAnalysisManager.getAnalysisModules(ftraceClass);
assertTrue(map.containsKey(AnalysisModuleTestHelper.moduleStubEnum.TEST2.name()));
/* Trigger trace.executeAnalysis() to populate its analysis modules through open signal */
TmfSignalManager.dispatchSignal(new TmfTraceOpenedSignal(this, trace, null));
@NonNull Iterable<@NonNull IAnalysisModule> modules = trace.getAnalysisModules();
/* Test that specific signals are not there (yet)*/
assertFalse(StreamSupport.stream(modules.spliterator(), false).anyMatch(module -> module.getId().equals(AnalysisModuleTestHelper.moduleStubEnum.TEST.name())));

/* Add new source */
AnalysisModuleSourceStub stub = new AnalysisModuleSourceStub();
TmfAnalysisManager.registerModuleSource(stub);

try {
/* Now check that the modules are not part of the trace yet */
modules = trace.getAnalysisModules();
assertFalse(StreamSupport.stream(modules.spliterator(), false).anyMatch(module -> module.getId().equals(AnalysisModuleTestHelper.moduleStubEnum.TEST.name())));
long before = StreamSupport.stream(modules.spliterator(), false).count();

/* Refresh the analysis */
IStatus status = trace.refreshAnalysisModules();
assertTrue(status.isOK());

/* Now check that the modules are part of the trace */
modules = trace.getAnalysisModules();
long after = StreamSupport.stream(modules.spliterator(), false).count();
assertTrue(after == before + 1);
assertTrue(StreamSupport.stream(modules.spliterator(), false).anyMatch(module -> module.getId().equals(AnalysisModuleTestHelper.moduleStubEnum.TEST.name())));

before = after;
/* Remove source again */
TmfAnalysisManager.deregisterModuleSource(stub);

/* Refresh the analysis */
status = trace.refreshAnalysisModules();
assertTrue(status.isOK());

/* Now check that the modules are not part of the trace anymore */
modules = trace.getAnalysisModules();
after = StreamSupport.stream(modules.spliterator(), false).count();
assertTrue(after == before - 1);
assertFalse(StreamSupport.stream(modules.spliterator(), false).anyMatch(module -> module.getId().equals(AnalysisModuleTestHelper.moduleStubEnum.TEST.name())));
} finally {
// Make sure source is removed after test
TmfAnalysisManager.deregisterModuleSource(stub);
trace.dispose();
}
}

}
2 changes: 1 addition & 1 deletion tmf/org.eclipse.tracecompass.tmf.core/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-Vendor: %Bundle-Vendor
Bundle-Version: 9.3.0.qualifier
Bundle-Version: 9.4.0.qualifier
Bundle-Localization: plugin
Bundle-SymbolicName: org.eclipse.tracecompass.tmf.core;singleton:=true
Bundle-Activator: org.eclipse.tracecompass.internal.tmf.core.Activator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,18 @@ public static synchronized void registerModuleSource(IAnalysisModuleSource sourc
refreshModules();
}

/**
* Deregisters a source of modules
*
* @param source
* A {@link IAnalysisModuleSource} instance
* @since 9.4
*/
public static synchronized void deregisterModuleSource(IAnalysisModuleSource source) {
fSources.remove(source);
refreshModules();
}

/**
* Initializes sources and new module listeners from the extension point
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.common.core.math.SaturatedArithmetic;
Expand Down Expand Up @@ -272,6 +273,17 @@ public interface ITmfTrace extends ITmfEventProvider {
*/
@NonNull Iterable<@NonNull IAnalysisModule> getAnalysisModules();

/**
* Refresh the analysis modules for this traces
*
* @return An IStatus indicating whether the analysis could be run
* successfully or not
* @since 9.4
*/
default IStatus refreshAnalysisModules() {
return Status.OK_STATUS;
}

// ------------------------------------------------------------------------
// Aspect getters
// ------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@
import java.io.File;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

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

// Analysis modules that were removed during lifecycle of the trace that need to be disposed
private final Set<IAnalysisModule> fToBeDisposedAnalysisModules =
Collections.synchronizedSet(new HashSet<IAnalysisModule>());

// ------------------------------------------------------------------------
// Construction
// ------------------------------------------------------------------------
Expand Down Expand Up @@ -288,29 +294,12 @@ public void indexTrace(boolean waitForCompletion) {
* successfully or not
*/
protected IStatus executeAnalysis() {
MultiStatus status = new MultiStatus(Activator.PLUGIN_ID, IStatus.OK, null, null);

/* First modules are initialized */
Map<String, IAnalysisModuleHelper> modules = TmfAnalysisManager.getAnalysisModules(this.getClass());
for (IAnalysisModuleHelper helper : modules.values()) {
try {
IAnalysisModule module = helper.newModule(this);
if (module == null) {
continue;
}
fAnalysisModules.put(module.getId(), module);
} catch (TmfAnalysisException e) {
status.add(new Status(IStatus.WARNING, Activator.PLUGIN_ID, e.getMessage()));
}
}
return refreshAnalysisModulesImpl();
}

/* Once all modules are initialized, automatic modules are executed */
for (IAnalysisModule module : getAnalysisModules()) {
if (module.isAutomatic()) {
status.add(module.schedule());
}
}
return status;
@Override
public IStatus refreshAnalysisModules() {
return refreshAnalysisModulesImpl();
}

@Override
Expand Down Expand Up @@ -349,6 +338,13 @@ public synchronized void dispose() {
}
fAnalysisModules.clear();

/* Clean up the analysis modules removed during lifecycle of trace */
analysisModules = fToBeDisposedAnalysisModules;
for (IAnalysisModule module : analysisModules) {
module.dispose();
}
fToBeDisposedAnalysisModules.clear();

super.dispose();
ByteBufferTracker.setMarked();
}
Expand Down Expand Up @@ -784,4 +780,56 @@ public void setComplete(boolean isComplete) {
* reading (traces in an incomplete state)
*/
}

private IStatus refreshAnalysisModulesImpl() {
Map<String, IAnalysisModule> previousAnalysisModules = new HashMap<>(fAnalysisModules);
Map<String, IAnalysisModule> newAnalysisModules = new HashMap<>();
MultiStatus status = new MultiStatus(Activator.PLUGIN_ID, IStatus.OK, null, null);
/* First modules are initialized */
Map<String, IAnalysisModuleHelper> modules = TmfAnalysisManager.getAnalysisModules(this.getClass());
for (IAnalysisModuleHelper helper : modules.values()) {
try {
IAnalysisModule module = helper.newModule(this);
if (module == null) {
continue;
}
newAnalysisModules.put(module.getId(), module);
} catch (TmfAnalysisException e) {
status.add(new Status(IStatus.WARNING, Activator.PLUGIN_ID, e.getMessage()));
}
}

Set<String> oldAnalysisModulesKeys = new HashSet<>(previousAnalysisModules.keySet());
Set<String> keys = new HashSet<>(newAnalysisModules.keySet());

for (String key : keys) {
IAnalysisModule module = newAnalysisModules.remove(key);
if (!oldAnalysisModulesKeys.contains(key)) {
/* Once all modules are initialized, automatic modules are executed */
if (module != null && module.isAutomatic()) {
status.add(module.schedule());
}
previousAnalysisModules.put(key, module);
} else {
oldAnalysisModulesKeys.remove(key);
if (module != null) {
module.dispose();
}
}
}

/* Remove all remaining analysis modules */
for (String key : oldAnalysisModulesKeys) {
IAnalysisModule analysisModule = previousAnalysisModules.remove(key);
if (analysisModule != null) {
fToBeDisposedAnalysisModules.add(analysisModule);
}
}
/* Update fAnalysis with current list of analysis modules */
synchronized (fAnalysisModules) {
fAnalysisModules.clear();
fAnalysisModules.putAll(previousAnalysisModules);
}
return status;
}
}

0 comments on commit d104da0

Please sign in to comment.