Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [platform-debug-dev] Collapsing thread behavior

I propose an alternate solution: greying out stack frames during a step.

I think it's more meaningful in terms of the UI and simpler to implement 
(the whole timer story is gone).

- Jared





"Darin Wright/WPG/OTI" <Darin_Wright@xxxxxxx>
Sent by: platform-debug-dev-admin@xxxxxxxxxxx
11/15/2001 08:43 AM
Please respond to platform-debug-dev

 
        To:     platform-debug-dev@xxxxxxxxxxx
        cc: 
        Subject:        Re: [platform-debug-dev] Collapsing thread behavior


Regarding "Thread Overpopulation": I think that this should be handled by 
creating a "pool" of timers. Each timer has its own thread that it creates 
once, and re-uses when the timer is used. We create timers lazily on 
demand, and also re-use timers. This should keep the timer and thread 
creation to a minimum. (This timer pool would be implemented in the 
"TimeoutManager" described below). 

I'm not sure I understand the "duplicate requests for the same step" 
problem. A step is performed on a "steppable" (IStep). Once a step has 
started, it cannot perform another step until the first step has 
completed. There should never be more than one pending timer per step 
request. 

I think that using the concept of "filtering" is not quite what we are 
looking for - we are doing timeout management, Perhaps we should make the 
concept of "timeout" more generic than for just ISteps. I suggest that we 
have a "TimeoutManager". The manager would have an API like (and could 
reside in the core debug as a utility): 

* public void addTimeoutListener(ITimeoutListener) 
* public void removeTimeoutListener(ITimeoutListener) 
* public void startTimer(Object, int) - starts a timer for "int" 
milliseonds, keyed on the specified object. If the timer expires, all 
listeners are notified of "timeout(Object)" on the registered object. Can 
only start one timer per object. 
* public void stopTimer(Object) - stops the timer on the specified object, 
and resets the object 
* public boolean isExpired(Object) - returns whether a timer on the 
specified object has expired, and the object has not yet been reset 
* public void reset(Object) - removes any  "expired" state associated with 
the specified object 

The Debug UI could write a "ThreadCollapseManager" that uses the timeout 
facilities. It would have API such as: 

* public void startCollapseTimer(IThread) - this starts a timer on the 
thread and listens for the corresponding "step end" event to stop/reset 
the timer. 
* public boolean isThreadCollapsed(IThread) - returns wether the thread 
should be displayed as collapsed 
* public void add/removeCollapseListener(ICollapseLisenter) - notifies 
listeners when to collapse a therad (via #collapse(IThread)). 

All debug view content providers check isCollapsed(IThread) before 
retrieving children for a thread. All debug view content providers 
register as collapse listeners (and refresh the thread when they get a 
collapse callback). 

Darin 



Jed_Anderson@xxxxxxx 
Sent by: platform-debug-dev-admin@xxxxxxxxxxx 
11/14/2001 06:06 PM 
Please respond to platform-debug-dev 
        
        To:        platform-debug-dev@xxxxxxxxxxx 
        cc: 
        Subject:        [platform-debug-dev] Collapsing thread behavior


After many hours of discussion today, Joe, Jared and I have unearthed a
number of problems with my previous proposal.

The problems were:
1. Timing: what if the timer completes during event callback, some
listeners may end up in inconsistent state
2. Thread overpopulation: if each ITimerRequestListener creates it's own
timer, then we are going to have many threads
3. DebugContentProvider lifecycle: if the user closes the DebugView, and
then reopens it, we will lose the filtered state
4. Multiple listeners: two debug views == multiple listeners, we must
address this issue
5. Duplicate requests for the same IStep: since the IStep is all we have 
to
key the requests, duplicate requests for the same IStep could hose things
up.

The newest proposal addresses all but one of these issues.

1. Timing: worst case scenario is flicker
2. Thread overpopulation: only one thread per timer request
3. DebugContentProvider lifecycle: filtering is tied into the 
DebugUIPlugin
which does not die when the DebugView closes
4. Multiple listeners: listeners are notified of filtering atomically
5. Duplicate requests for the same IStep: we cannot handle this in a
reasonable manner (neither can any of the other solutions)

Changes: (names are unimportant right now)

add: interface IFilterListener /* interface indicating that implementers
want to be notified of filtering */
add: IFilerListener#filter(IStep step) /* method indicating that the
implementer should filter the given step */

add: class Filter /* handles timers & notifies listeners of filtered step
objects */
add: Filter#startTimer(IStep target, long timeout)
add: Filter#addFilterListener(IFilterListener listener)
add: Filter#removeFilterListener(IFilterListener listener)
add: IStep[] Filter#getFilteredSteps()

change: StepAction#run /* must call DebugUIPlugin#startTimer(IStep step,
long timeout) */

add: DebugUIPlugin#startTimer(IStep target, long timeout) /* forwards to
Filter#startTimer(target, timeout) */
add: Filter DebugUIPlugin#getFilter() /* returns the singleton Filter
object for this DebugUIPlugin */

add: DebugContentProvider implements IFilterListener
change: DebugContentProvider#<init> /* must register as an 
IFilterListener,
must ask Filter for it's filtered steps */
add: DebugContentProvider#filter(IStep step) /* should filter step &
children of step (currently only Thread & Stack Frame) */

Cases:

a step action completes quickly:

1. StepAction notifies DebugUIPlugin that it needs to start a timer
2. DebugUIPlugin forwards the request to the Filter object
3. The Filter object starts a timer for the IStep object
4. Step End event is received by the Filter object, it stops the timer
5. Step End event is received by the DebugContentProviders and they update
accordingly

a step action completes after the timeout (filter gets first notification)

1. StepAction notifies DebugUIPlugin that it needs to start a timer
2. DebugUIPlugin forwards the request to the Filter object
3. The Filter object starts a timer for the IStep object
4. The timer times out, the Filter tells the listeners to filter the IStep
object associated with the timer
5. Step End event is received by the Filter object, it tells the listeners
to stop filtering the associated IStep
6. Step End event is received by the DebugContentProviders and they update
accordingly

a step action completes after the timeout (DebugContentProviders get first
notification)

1. StepAction notifies DebugUIPlugin that it needs to start a timer
2. DebugUIPlugin forwards the request to the Filter object
3. The Filter object starts a timer for the IStep object
4. The timer times out, the Filter tells the listeners to filter the IStep
object associated with the timer
5. Step End event is received by the DebugContentProviders, they do 
nothing
(they are filtering the IStep)
6. Step End event is received by the Filter object, it tells the listeners
to stop filtering the associated IStep

a step action never completes

1. StepAction notifies DebugUIPlugin that it needs to start a timer
2. DebugUIPlugin forwards the request to the Filter object
3. The Filter object starts a timer for the IStep object
4. The timer times out, the Filter tells the listeners to filter the IStep
object associated with the timer
5. The Filter receives a Thread death, Disconnected or Terminated event 
and
stops & removes the associated timers

step completes exactly when the timer times out
(this will cause flicker as the children are added & removed quickly)

1. StepAction notifies DebugUIPlugin that it needs to start a timer
2. DebugUIPlugin forwards the request to the Filter object
3. The Filter object starts a timer for the IStep object
4. Step End event is received by one of the DebugContentProviders, it
updates to show the correct stack
5. The timer times out, the Filter tells the listeners to filter the IStep
object associated with the timer, all DebugContentProviders collapse
6. Step End event is received by the other DebugContentProviders, they are
filtering and do nothing
7. Step End event is received by the Filter object, it tells the listeners
to stop filtering the associated IStep, they update to the correct
(unfiltered) state

The last case is a simplification of all of the possible orderings of
DebugEvent notification.  They will all cause flicker, but in the end, the
correct state will be shown.

jkca

----- Forwarded by Jed Anderson/MIN/OTI on 11/14/2001 05:03 PM -----
  
                   "Darin Wright/WPG/OTI"    
                   <Darin_Wright@xxxxxxx>            To: 
platform-debug-dev@xxxxxxxxxxx  
                   Sent by:                          cc:      
                   platform-debug-dev-admin@e        Subject: 
[platform-debug-dev] [jdt-debug-dev] Collapsing thread behavior for length 
 
                   clipse.org                        operations            
 
  
  
                   11/11/2001 10:52 PM   
  
  




I agree that collapsing stack frames is a presentation issue, and should 
be
dealt with in the UI - not the model. I agree that we should change the
IStep interface to be declared as non-blocking. I do not think that IStep
(or any other model interface) requires a #timeout() method, as we want to
keep all of the "collapse" behavior in the UI. Thus, if there is a 
timeout,
the UI collapses the stack frames for that thread, and keeps a note that
when retrieving children for that thread, there are none (i.e. do not 
query
the model for stack frames until a "step-end" or "suspend" event has been
received).

If Joe & Jed agree with this (and there are no other objections), I 
believe
we can have Joe go ahead and make the neccessary changes.

Darin


----- Forwarded by Darin Wright/WPG/OTI on 11/11/2001 10:57 PM -----
 
 Jed_Anderson@xxxxxxx 
 Sent by:                         To: 
 platform-debug-dev-admin platform-debug-dev@xxxxxxxxxxx 
 @eclipse.org                     cc: 
                                  Subject:        [platform-debug-dev] 
                          [jdt-debug-dev] Collapsing thread behavior for 
 11/08/2001 06:19 PM      length operations 
 



The overall problem that Joe describes is that our "collapse the stepping
thread that timed out" feature is being done in the model and not the UI.

I don't think we should update the model to achieve this goal, I think we
should do it all in the UI.  As I see this issue, collapsing threads that
have taken too long to step is analogous to the "*.class" filter in the
packages view.    It is a complex filter based off of elapsed time and
state in the model, but nonetheless it is a filter.  If we implement this
entirely in the UI, then _all_ debug models get this functionality for
free.  Otherwise other models have to implement it again.

The rough idea is the same as Joe's proposal:
   1. Step action requests that timers be started with the DebugUIPlugin
   2. Step action invokes the step
   3. If the timer finishes first, the DebugContentProvider collapses the
thread in the UI (not the model), otherwise the UI should update through
the "normal" way, and the DebugContentProvider just interrupts the Timer.

Details:
   * Creation of interface ITimerRequestListener (or other name... not
important now) with one method
        requestTimer(IStep step, long timeout)
   * DebugUIPlugin needs to maintain a list of ITimerRequestListeners
   * DebugUIPlugin#fireRequestTimer(IStep step, long timeout) needs to be
created and implemented to notify the listeners with a requestTimer(IStep,
long) call.
   * DebugContentProvider needs to register as a ITimerRequestListener
with the DebugUIPlugin, it currently registers as an ILaunchListener and 
an
IDebugEventListener, so this shouldn't be an issue.
   * DebugContentProvider implements requestTimer(IStep step, long
timeout) to do the following
        * store step
        * start a timer for timeout
        * check incoming suspend events and check to see if they are step
end events.  if they are compare the stack frame against the stored step.
if they match stop the timer and continue like normal
        * if timer expires filter the view so that only the thread shows
        * NOTE: this is a simplification to make explanation easier, you
have to keep a map of IStep objects to Timer objects

This gives Joe the same functionality so that he can programmatically
invoke the toString without getting the collapsing of the Thread, but it
also cleans up the code UI-Model relationship so that other clients of the
model will not be disrupted by the collapsing feature.

Issue #1:
Since all of the "request for timer" functionality is on the DebugUIPlugin
in my proposal, any other clients of the debug model that are interested 
in
timeouts can implement them.

Issue #2:
I suggest we do away with the ability for model implementers to write
blocking step methods.  If we require that they are non-blocking, and some
model can only do blocking, then it is their responsibility to wrap their
step actions in Threads.  It is the difference between adding API (new
method/interface) and changing API (remove comments that indicate that we
support blocking).  I support the change proposal because I think the
interface is unneeded (read: code bloat) and I don't think forcing model
implementers to provide non-blocking implementations is unreasonable.

jkca

----- Forwarded by Jed Anderson/MIN/OTI on 11/08/2001 05:11 PM -----

                  Joe_Szurszewski@oti.c

                  om                           To:
jdt-debug-dev@xxxxxxxxxxx, platform-debug-dev@xxxxxxxxxxx
                  Sent by:                     cc:

                  jdt-debug-dev-admin@e        Subject:
[jdt-debug-dev] Collapsing thread behavior for length
                  clipse.org                   operations



                  11/08/2001 04:27 PM







      In the latest build (20011107), there is a problem using the
'details pane' in the VariablesView.
If an evaluation of 'toString()' takes longer than the established timeout
value for evaluations (currently
3 seconds), the stack frames of the suspended thread are collapsed
(disappear) to indicate that something
lengthy is happening.  This causes a CHANGE DebugEvent to be fired, which
is ultimately heard by the VariablesView,
which resets its input, which blanks out both it and the details pane. The
view stays blank until the
evaluation finishes, at which time the SUSPEND event causes the
VariablesView to be repopulated, although nothing
in the view is expanded, and the previous selection is lost.  The logic 
for
handling the 'collpase timer'
currently resides in JDIThread, so that ALL method invocations on a thread
get this behavior  This seems counterintuitive,
since JDIThread is part of the model, not the UI.  I propose moving this
logic into the UI as follows:
      -        Move timeout monitoring to the Action subclasses that need
collapse behavior
              (ex. StepIntoActionDelegate)
      -        On action invocation, the action registers for DebugEvents

      -        Action starts timer (copy std. Timer class &
ITimeoutListener interface)
      -        Action invokes the appropriate method (ex. stepInto) on
the IStep debug element in question
      -        Action waits for appropriate DebugEvent (STEP_END on debug
element in question) or timeout,
              whichever comes first
      -        If timeout happens first, invoke some sort of "timeout()"
method on the IStep debug element.
              This cleans up the internal model state of the debug
element, and fires a CHANGE DebugEvent
              so the UI (e.g., DebugView) can update
      -        If STEP_END callback happens first (on the element in
question), cancel the timer.
              The DebugView will also hear this event and update the UI
accordingly

Making this work requires several things.  (1) New API on IStep (or a new
superinterface that IStep extends)
that defines the "timeout()" method.  There is probably a better name for
this.  (2) Changes to JDIThread &
appropriate action classes to relocate timing logic.  (3) Access to Timer 
&
ITimeoutListener types.

Unresolved issues with this approach: (1) Do any other capability
interfaces beyond IStep (ex. ISuspendResume)
need a "timeout()" method?  (2) Current JDI stepping implementation is
non-blocking.  IStep JavaDoc says
stepping implementations may be either blocking or non-blocking.  Do we
intend to stick with this?  If so,
we might need extra logic in the actions to handle blocking
implementations, so that they don't block the
UI thread.  If this is the case, we would also need a method on IStep (or
its superinterface) along the
lines of "isBlocking()" so that an IStep implementation can report whether
it uses a blocking implementation
of stepping, and thus actions can behave correctly.

Benefits: (1) Collapse behavior is now under UI control.  Collapsing only
happens through user-initiated events that
ask for it.  Programmatic evaluation, such as the evaluation of the
toString() method for the details pane, no longer gets
the collapse behavior whether it wants it or not.  (2) Cleaner model/UI
separation.

Any thoughts?


_______________________________________________
platform-debug-dev mailing list
platform-debug-dev@xxxxxxxxxxx
http://dev.eclipse.org/mailman/listinfo/platform-debug-dev



_______________________________________________
platform-debug-dev mailing list
platform-debug-dev@xxxxxxxxxxx
http://dev.eclipse.org/mailman/listinfo/platform-debug-dev






Back to the top