Closed Bug 55403 Opened 24 years ago Closed 18 years ago

PL_ProcessPendingEvents optimization

Categories

(Core :: XPCOM, defect, P3)

defect

Tracking

()

RESOLVED INVALID
Future

People

(Reporter: dougt, Assigned: dougt)

References

Details

(Keywords: perf)

In an email from : Colin Blake <colin@theblakes.com>


I was looking at the code in plevent, and came up with an idea for a speed-up.
We don't need to walk the queue while holding the lock to find out how many
events we have to process. We only need to find out which is the last event and
then we can release the lock and pluck events from the queue until we've
processed the last one. Any events which
have been added while we are processing we simply be ignored. Isn't this the
behaviour we want?

Modified BUT UNTESTED code is attached by ways of an example of what I mean.

FWIW...

Colin.


PR_IMPLEMENT(void)
PL_ProcessPendingEvents(PLEventQueue* self)
{
    PRInt32 count;
    PLEvent* last, event;

    if (self == NULL)
      return;

    PR_EnterMonitor(self->monitor);

    if (self->processingEvents) {
      PR_ExitMonitor(self->monitor);
      return;
    }
    self->processingEvents = PR_TRUE;

    /* Only process the events that are already in the queue, and
     * not any new events that get added. Do this by counting the
     * number of events currently in the queue
     */
    last = PR_LIST_TAIL(&self->queue);
    PR_ExitMonitor(self->monitor);

    if (last != &self->queue) { /* check queue was not empty */
      do {
        event = PL_GetEvent(self);
        if (event == NULL)
          break; /* should never get here */

        PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ processing event"));
        PL_HandleEvent(event);
        PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ done processing event"));
      }
      while (event != last);
    }
    rest as before...
I thought we did this, but...

PL_GetEvent has to grab the monitor each time.  Ok, at least you won't hold it
across dispatches.

What about RevokeEvents?  Could that happen in the middle of handling the seven
events we counted, invalidating our count?

/be
RevokeEvents is bad news for both my suggestion and for the existing 
implementation. With my idea if someone revokes what was the last entry, then 
we'll end up processing ALL new events which get added to the queue. With the 
existing implementation, we only process SOME new events which get added. Either 
way, we need to think some more about revokation.
2 
Assignee: dougt → danm
This is related to bug 50104. Stabs I've taken at that bug make it seem like we 
could just keep a "count" variable in the event queue.
Depends on: 50104
Target Milestone: --- → Future
I don't think a simple count will do. A count may become incorrect if you have 
to RevokeEvents while processing.  
What would make it more complicated than adjusting the count in PL_PostEvent, 
PL_GetEvent and PL_DequeueEvent? And of course _pl_CreateEventQueue.
Queue contains A, B, C when ProcessPending is called. You compute 3 as the
number of events to process.

Start processing A, count is now 2.

While processing A two more get queued, D and E. But you're smart and don't
touch the counter. Queue is now B, C, D, E. Your count is 2.

While still processing A, someone calls Revoke. How does revoke know whether
to decrement the count or not? The only way I see is to walk the queue to
locate the entry to revoke, and then, based upon its position, decide if the
counter should be decremented or not. This can be done, but involved locking
down the queue and walking it, which is what we were trying to avoid in the
first place.
  True enough, but we don't require so much precision from the count in 
PL_ProcessingEvents. All we're using the counter for is to limit the time it 
spends in that function, so it doesn't stay there forever while new events come 
in as it processes extant ones. The exact count isn't important for our purposes.
  The current code just calculates a local copy of the count at the beginning, 
and stops processing after that many events have been processed, or when the 
queue is empty, whichever comes first. I'm suggesting we maintain an accurate 
live count, and keep the current code but just set the initial local count by the 
live count in the beginning, rather than stepping through the event queue; the 
thing you were wanting to improve here.
  It seems foolproof to me, and affected by revoking events no more than the 
current code.
Now I see what you're getting at. Yes, you're right. It doesn't really matter
if revoke is called while we're processing, since the worst that'll happen is
that we'll process a few "extra" events. No big deal. Since all the queue
insertion/deletion is done under a lock, keeping a counter should be safe.
Sounds like a solution to me!
Assignee: danm.moz → dougt
Severity: major → normal
Keywords: perf
QA Contact: rayw
PL_ProcessPendingEvents no longer exists (see bug 326273). I think we can close this bug as INVALID now.
Status: NEW → RESOLVED
Closed: 18 years ago
Depends on: nsIThreadManager
Resolution: --- → INVALID
You need to log in before you can comment on or make changes to this bug.