mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-01 22:25:25 +02:00
[208476] Added queuing of events to the View Model cache.
This commit is contained in:
parent
0eb5614e96
commit
383e01aec2
7 changed files with 161 additions and 53 deletions
|
@ -22,6 +22,7 @@ import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.register.SyncR
|
|||
import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.update.BreakpointHitUpdatePolicy;
|
||||
import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.variable.SyncVariableDataAccess;
|
||||
import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.variable.VariableVMNode;
|
||||
import org.eclipse.dd.dsf.debug.service.IRunControl.ISuspendedDMEvent;
|
||||
import org.eclipse.dd.dsf.service.DsfSession;
|
||||
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter;
|
||||
import org.eclipse.dd.dsf.ui.viewmodel.DefaultVMContentProviderStrategy;
|
||||
|
@ -326,4 +327,12 @@ public class ExpressionVMProvider extends AbstractDMVMProvider
|
|||
}
|
||||
handleEvent(new ExpressionsChangedEvent(type, rootElements));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canSkipHandlingEvent(Object newEvent, Object eventToSkip) {
|
||||
// To optimize the performance of the view when stepping rapidly, skip all
|
||||
// other events when a suspended event is received, including older suspended
|
||||
// events.
|
||||
return newEvent instanceof ISuspendedDMEvent;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ package org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.register;
|
|||
|
||||
import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.numberformat.FormattedValuePreferenceStore;
|
||||
import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.update.BreakpointHitUpdatePolicy;
|
||||
import org.eclipse.dd.dsf.debug.service.IRunControl.ISuspendedDMEvent;
|
||||
import org.eclipse.dd.dsf.service.DsfSession;
|
||||
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter;
|
||||
import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode;
|
||||
|
@ -99,4 +100,13 @@ public class RegisterVMProvider extends AbstractDMVMProvider
|
|||
public void propertyChange(PropertyChangeEvent event) {
|
||||
handleEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canSkipHandlingEvent(Object newEvent, Object eventToSkip) {
|
||||
// To optimize the performance of the view when stepping rapidly, skip all
|
||||
// other events when a suspended event is received, including older suspended
|
||||
// events.
|
||||
return newEvent instanceof ISuspendedDMEvent;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ package org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.variable;
|
|||
|
||||
import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.numberformat.FormattedValuePreferenceStore;
|
||||
import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.update.BreakpointHitUpdatePolicy;
|
||||
import org.eclipse.dd.dsf.debug.service.IRunControl.ISuspendedDMEvent;
|
||||
import org.eclipse.dd.dsf.service.DsfSession;
|
||||
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter;
|
||||
import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode;
|
||||
|
@ -82,4 +83,12 @@ public class VariableVMProvider extends AbstractDMVMProvider
|
|||
return new IVMUpdatePolicy[] { new AutomaticUpdatePolicy(), new ManualUpdatePolicy(), new BreakpointHitUpdatePolicy() };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canSkipHandlingEvent(Object newEvent, Object eventToSkip) {
|
||||
// To optimize the performance of the view when stepping rapidly, skip all
|
||||
// other events when a suspended event is received, including older suspended
|
||||
// events.
|
||||
return newEvent instanceof ISuspendedDMEvent;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,12 +15,14 @@ import java.util.HashMap;
|
|||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
|
||||
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
|
||||
import org.eclipse.dd.dsf.concurrent.IDsfStatusConstants;
|
||||
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
|
||||
import org.eclipse.dd.dsf.ui.concurrent.DisplayDsfExecutor;
|
||||
import org.eclipse.dd.dsf.ui.concurrent.ViewerDataRequestMonitor;
|
||||
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
|
||||
|
@ -123,6 +125,13 @@ abstract public class AbstractVMProvider implements IVMProvider
|
|||
*/
|
||||
private IRootVMNode fRootNode;
|
||||
|
||||
private class ModelProxyEventQueue {
|
||||
private boolean fProcessingEvent = false;
|
||||
private List<Object> fEventQueue = new LinkedList<Object>();
|
||||
}
|
||||
|
||||
private Map<IVMModelProxy, ModelProxyEventQueue> fEventQueues = new HashMap<IVMModelProxy, ModelProxyEventQueue>();
|
||||
|
||||
/**
|
||||
* Constructs the view model provider for given DSF session. The
|
||||
* constructor is thread-safe to allow VM provider to be constructed
|
||||
|
@ -198,24 +207,109 @@ abstract public class AbstractVMProvider implements IVMProvider
|
|||
public void handleEvent(final Object event) {
|
||||
for (final IVMModelProxy proxyStrategy : getActiveModelProxies()) {
|
||||
if (proxyStrategy.isDeltaEvent(event)) {
|
||||
proxyStrategy.createDelta(
|
||||
event,
|
||||
new DataRequestMonitor<IModelDelta>(getExecutor(), null) {
|
||||
@Override
|
||||
public void handleCompleted() {
|
||||
if (isSuccess()) {
|
||||
proxyStrategy.fireModelChanged(getData());
|
||||
if (!fEventQueues.containsKey(proxyStrategy)) {
|
||||
fEventQueues.put(proxyStrategy, new ModelProxyEventQueue());
|
||||
}
|
||||
final ModelProxyEventQueue queue = fEventQueues.get(proxyStrategy);
|
||||
if (queue.fProcessingEvent) {
|
||||
if (!queue.fEventQueue.isEmpty()) {
|
||||
for (ListIterator<Object> itr = queue.fEventQueue.listIterator(queue.fEventQueue.size() - 1); itr.hasPrevious();) {
|
||||
Object eventToSkip = itr.previous();
|
||||
if (canSkipHandlingEvent(event, eventToSkip)) {
|
||||
itr.remove();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@Override public String toString() {
|
||||
return "Result of a delta for event: '" + event.toString() + "' in VMP: '" + this + "'" + "\n" + getData().toString(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
|
||||
}
|
||||
});
|
||||
}
|
||||
queue.fEventQueue.add(event);
|
||||
} else {
|
||||
doHandleEvent(queue, proxyStrategy, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up model proxies that were removed.
|
||||
List<IVMModelProxy> activeProxies = getActiveModelProxies();
|
||||
for (Iterator<IVMModelProxy> itr = fEventQueues.keySet().iterator(); itr.hasNext();) {
|
||||
if (!activeProxies.contains(itr.next())) {
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void doHandleEvent(final ModelProxyEventQueue queue, final IVMModelProxy proxyStrategy, final Object event) {
|
||||
queue.fProcessingEvent = true;
|
||||
handleEvent(
|
||||
proxyStrategy, event,
|
||||
new RequestMonitor(getExecutor(), null) {
|
||||
@Override
|
||||
protected void handleCompleted() {
|
||||
queue.fProcessingEvent = false;
|
||||
if (!queue.fEventQueue.isEmpty()) {
|
||||
doHandleEvent(queue, proxyStrategy, queue.fEventQueue.remove(0));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the given event for the given proxy strategy.
|
||||
* <p>
|
||||
* This method is called by the base {@link #handleEvent(Object)}
|
||||
* implementation to handle the given event using the given model proxy.
|
||||
* The default implementation of this method checks whether the given
|
||||
* proxy is active and if the proxy is active, it is called to generate the
|
||||
* delta which is then sent to the viewer.
|
||||
* </p>
|
||||
* @param proxyStrategy Model proxy strategy to use to process this event.
|
||||
* @param event Event to process.
|
||||
* @param rm Request monitor to call when processing the event is
|
||||
* completed.
|
||||
*/
|
||||
protected void handleEvent(final IVMModelProxy proxyStrategy, final Object event, RequestMonitor rm) {
|
||||
if (!proxyStrategy.isDisposed()) {
|
||||
proxyStrategy.createDelta(
|
||||
event,
|
||||
new DataRequestMonitor<IModelDelta>(getExecutor(), rm) {
|
||||
@Override
|
||||
public void handleCompleted() {
|
||||
if (isSuccess()) {
|
||||
proxyStrategy.fireModelChanged(getData());
|
||||
}
|
||||
super.handleCompleted();
|
||||
}
|
||||
@Override public String toString() {
|
||||
return "Result of a delta for event: '" + event.toString() + "' in VMP: '" + this + "'" + "\n" + getData().toString(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
|
||||
}
|
||||
});
|
||||
} else {
|
||||
rm.done();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether processing of a given event can be skipped. This
|
||||
* method is called when there are multiple events waiting to be processed
|
||||
* by the provider. As new events are received from the model, they are
|
||||
* compared with the events in the queue using this method, events at the
|
||||
* end of the queue are tested for removal. If this method returns that a
|
||||
* given event can be skipped in favor of the new event, the skipped event
|
||||
* is removed from the queue. This process is repeated with the new event
|
||||
* until an event which cannot be stopped is found or the queue goes empty.
|
||||
* <p>
|
||||
* This method may be overriden by specific view model provider
|
||||
* implementations extending this abstract class.
|
||||
* </p>
|
||||
* @param newEvent New event that was received from the model.
|
||||
* @param eventToSkip Event which is currently at the end of the queue.
|
||||
* @return True if the event at the end of the queue can be skipped in
|
||||
* favor of the new event.
|
||||
*/
|
||||
protected boolean canSkipHandlingEvent(Object newEvent, Object eventToSkip) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public IRootVMNode getRootVMNode() {
|
||||
return fRootNode;
|
||||
}
|
||||
|
|
|
@ -336,8 +336,6 @@ public class DefaultVMModelProxyStrategy implements IVMModelProxy {
|
|||
new DataRequestMonitor<List<Object>>(getVMProvider().getExecutor(), null) {
|
||||
@Override
|
||||
protected void handleCompleted() {
|
||||
if (isDisposed()) return;
|
||||
|
||||
// Check for an empty list of elements. If it's empty then we
|
||||
// don't have to call the children nodes, so return here.
|
||||
// No need to propagate error, there's no means or need to display it.
|
||||
|
@ -449,13 +447,7 @@ public class DefaultVMModelProxyStrategy implements IVMModelProxy {
|
|||
}
|
||||
|
||||
final MultiRequestMonitor<RequestMonitor> elementsDeltasMultiRequestMon =
|
||||
new MultiRequestMonitor<RequestMonitor>(getVMProvider().getExecutor(), null) {
|
||||
@Override
|
||||
protected void handleCompleted() {
|
||||
if (isDisposed()) return;
|
||||
requestMonitor.done();
|
||||
}
|
||||
};
|
||||
new MultiRequestMonitor<RequestMonitor>(getVMProvider().getExecutor(), requestMonitor);
|
||||
|
||||
// For each element from this node, create a new delta,
|
||||
// and then call all the child nodes to build their delta.
|
||||
|
@ -508,8 +500,6 @@ public class DefaultVMModelProxyStrategy implements IVMModelProxy {
|
|||
new DataRequestMonitor<Map<IVMNode, Integer>>(getVMProvider().getExecutor(), null) {
|
||||
@Override
|
||||
protected void handleCompleted() {
|
||||
if (isDisposed()) return;
|
||||
|
||||
final CountingRequestMonitor multiRm = new CountingRequestMonitor(getVMProvider().getExecutor(), requestMonitor);
|
||||
int multiRmCount = 0;
|
||||
|
||||
|
@ -562,11 +552,6 @@ public class DefaultVMModelProxyStrategy implements IVMModelProxy {
|
|||
final Integer[] counts = new Integer[childNodes.length];
|
||||
final MultiRequestMonitor<RequestMonitor> childrenCountMultiRequestMon =
|
||||
new MultiRequestMonitor<RequestMonitor>(getVMProvider().getExecutor(), rm) {
|
||||
@Override
|
||||
protected void handleCompleted() {
|
||||
if (isDisposed()) return;
|
||||
super.handleCompleted();
|
||||
}
|
||||
@Override
|
||||
protected void handleSuccess() {
|
||||
Map<IVMNode, Integer> data = new HashMap<IVMNode, Integer>();
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.util.concurrent.Executor;
|
|||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor;
|
||||
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
|
||||
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
|
||||
import org.eclipse.dd.dsf.datamodel.IDMContext;
|
||||
import org.eclipse.dd.dsf.datamodel.IDMData;
|
||||
import org.eclipse.dd.dsf.datamodel.IDMService;
|
||||
|
@ -555,39 +556,16 @@ public class AbstractCachingVMProvider extends AbstractVMProvider implements ICa
|
|||
}
|
||||
|
||||
@Override
|
||||
public void handleEvent(final Object event) {
|
||||
protected void handleEvent(final IVMModelProxy proxyStrategy, final Object event, RequestMonitor rm) {
|
||||
IElementUpdateTester elementTester = getActiveUpdatePolicy().getTesterTester(event);
|
||||
|
||||
List<FlushMarkerKey> flushKeys = new LinkedList<FlushMarkerKey>();
|
||||
List<IVMModelProxy> proxies = new LinkedList<IVMModelProxy>();
|
||||
|
||||
for (final IVMModelProxy proxyStrategy : getActiveModelProxies()) {
|
||||
if (proxyStrategy.isDeltaEvent(event)) {
|
||||
flushKeys.add(new FlushMarkerKey(proxyStrategy.getRootElement(), elementTester));
|
||||
proxies.add(proxyStrategy);
|
||||
}
|
||||
}
|
||||
flushKeys.add(new FlushMarkerKey(proxyStrategy.getRootElement(), elementTester));
|
||||
|
||||
flush(flushKeys);
|
||||
|
||||
for (final IVMModelProxy proxyStrategy : proxies) {
|
||||
if (!proxyStrategy.isDisposed() && proxyStrategy.isDeltaEvent(event)) {
|
||||
proxyStrategy.createDelta(
|
||||
event,
|
||||
new DataRequestMonitor<IModelDelta>(getExecutor(), null) {
|
||||
@Override
|
||||
public void handleCompleted() {
|
||||
|
||||
if (isSuccess()) {
|
||||
proxyStrategy.fireModelChanged(getData());
|
||||
}
|
||||
}
|
||||
@Override public String toString() {
|
||||
return "Result of a delta for event: '" + event.toString() + "' in VMP: '" + this + "'" + "\n" + getData().toString(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
super.handleEvent(proxyStrategy, event, rm);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,10 +14,14 @@ package org.eclipse.dd.gdb.internal.ui.viewmodel.launch;
|
|||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
import org.eclipse.dd.dsf.concurrent.ThreadSafe;
|
||||
import org.eclipse.dd.dsf.datamodel.DMContexts;
|
||||
import org.eclipse.dd.dsf.datamodel.IDMContext;
|
||||
import org.eclipse.dd.dsf.datamodel.IDMEvent;
|
||||
import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.LaunchRootVMNode;
|
||||
import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.StackFramesVMNode;
|
||||
import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.StandardProcessVMNode;
|
||||
import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.LaunchRootVMNode.LaunchesEvent;
|
||||
import org.eclipse.dd.dsf.debug.service.IRunControl.ISuspendedDMEvent;
|
||||
import org.eclipse.dd.dsf.service.DsfSession;
|
||||
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter;
|
||||
import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode;
|
||||
|
@ -126,4 +130,23 @@ public class LaunchVMProvider extends AbstractDMVMProvider
|
|||
// shut down.
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canSkipHandlingEvent(Object newEvent, Object eventToSkip) {
|
||||
// To optimize view performance when stepping rapidly, skip events that came
|
||||
// before the last suspended events. However, the debug view can get suspended
|
||||
// events for different threads, so make sure to skip only the events if they
|
||||
// were in the same hierarchy as the last suspended event.
|
||||
if (newEvent instanceof ISuspendedDMEvent && eventToSkip instanceof IDMEvent<?>) {
|
||||
IDMContext newEventDmc = ((IDMEvent<?>)newEvent).getDMContext();
|
||||
IDMContext eventToSkipDmc = ((IDMEvent<?>)eventToSkip).getDMContext();
|
||||
|
||||
if (newEventDmc.equals(eventToSkipDmc) || DMContexts.isAncestorOf(eventToSkipDmc, newEventDmc)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue