w3c / requestidlecallback

Cooperative Scheduling of Background Tasks
https://w3c.github.io/requestidlecallback/
Other
50 stars 19 forks source link

The restriction on when a new idle period can start is rather odd. #28

Closed bzbarsky closed 8 years ago

bzbarsky commented 8 years ago

There seems to be some explicit effort to make sure a new idle period can't start until a previous one would have ended, and I'm not sure why that's there. The way the spec is written right now, if the UA starts a 50ms idle period and has one callback to run, runs that callback, the callback uses 5ms of time budget but scheduled another idle callback... then the UA won't run that other idle callback until the remaining 45ms of the idle period have passed. This is kind of related to https://github.com/w3c/requestidlecallback/issues/27.

But there's another undesirable thing that can happen too. Say a UA starts a 50ms idle period with 7 callbacks to run. The first one runs for 5ms, then the UA discovers it needs to handle user input. So it doesn't reschedule the other 6 callbacks in step 2.4 of https://w3c.github.io/requestidlecallback/#dfn-invoke-idle-callbacks-algorithm and handles the user input for, say, 10ms. Now it could in theory go back to running idle callbacks, but the spec requires it to wait for 35ms (for the initial end of the interrupted idle period to be reached) before any more idle callbacks are run. This seems weird to me.

rmcilroy commented 8 years ago

The reason for this is again related to the reason in #27. If we have say an idle period with a 10ms deadline, and the first and only callback decides it needs more than 10ms then it would reschedule itself and return. This means there is still say ~9ms left in the idle period and no idle task to run. If the browser decides to take advantage of this and start a new idle period (this time with 9ms deadline) this will cause the callback to get re-run and have to say it doesn't want this deadline again.

In the case where you are going to give the maximum 50ms deadline it is actually OK to start an idle period within the previous idle period since you are giving the maximum deadline anyway. Actually the requirement here is that the deadline for a new idle period shouldn't be the same, or earlier (in absolute time) than the deadline of the previous idle period. Maybe we should change the spec as such, wdyt? (our implementation in Chrome would still be spec compliment with this change).

But there's another undesirable thing that can happen too. Say a UA starts a 50ms idle period with 7 callbacks to run. The first one runs for 5ms, then the UA discovers it needs to handle user input. So it doesn't reschedule the other 6 callbacks in step 2.4 of https://w3c.github.io/requestidlecallback/#dfn-invoke-idle-callbacks-algorithm and handles the user input for, say, 10ms. Now it could in theory go back to running idle callbacks, but the spec requires it to wait for 35ms (for the initial end of the interrupted idle period to be reached) before any more idle callbacks are run. This seems weird to me.

The spec is written such that the idle tasks happen on a different task queue from any other tasks, and each execution of the "invoke idle callbacks algorithm" only runs one idle task then queues another task on the idle-task task source to run the next callback. As such, the browser is able to treat other task source queues (e.g., user input, etc.) as higher priority sources, and just run them in between idle tasks (this is what Chrome does). Therefore it doesn't always need to end an idle period when higher priority work comes in, instead it can just ensure that that high priority work gets completed before the remaining idle tasks get a chance to run in the idle period.

The text about ending the idle period early was more meant for cases where the browser thinks it won't be drawing frames and gives out a 50ms deadline, then needs to start drawing frames and so shouldn't be running 50ms tasks. As such, it can end the 50ms idle period and then start 16ms inter-frame idle periods between frames. In these cases it is probably OK if the new 16ms idle period starts before the original 50ms idle period deadline was meant to end, but I'm not quite sure how we would spec this and still retain the requirement above. Any thoughts?

bzbarsky commented 8 years ago

Actually the requirement here is that the deadline for a new idle period shouldn't be the same, or earlier (in absolute time) than the deadline of the previous idle period

That makes a bit more sense, yes.

For the one-callback case, I guess I can buy your argument that we want to push off things it schedules to after the idle period deadline, though in the case when the idle period was the maximally allowed 50ms even that doesn't necessarily make sense, because the callback is not likely to be rescheduling because it can't fit its work in 50ms.

Therefore it doesn't always need to end an idle period when higher priority work comes in

That is entirely unclear from the spec as written. Especially the notes before and after the "invoke idle callbacks algorithm" sure sounds like the UA would stop an idle period to run other things.

It sounds like this spec's concept of "idle period" doesn't really have much to do with idleness. It's probably worth renaming it to something else, like "idle callback processing batch" or some such that more clearly reflects what it's really after: batching up callbacks that don't need to be delayed and putting in a way to delay new ones scheduled from inside the current batch.

but I'm not quite sure how we would spec this and still retain the requirement above.

Why would we want to retain that requirement in this situation?

The argument above, if I understand it, goes like this: If we start a 50ms idle period, then run an idle callback that runs for 5ms, schedules more work, and returns, then presumably that callback did that because the remaining work would have taken it more than 45ms. So we shouldn't bother trying to reschedule it again within those remaining 45ms.

If that's the argument, then we also shouldn't try rescheduling it for a new 16ms idle period, even if that idle period starts more than 50ms after the long idle period started (the spec requirement right now). If the work would not have fit in 45ms, it certainly won't fit in 16ms. What would make more sense is rescheduling when we have an idle period that is longer than the remaining time in the idle period the callback was scheduled from, or something like that, no? Though I expect that to have problems too, of course.

Fundamentally, the problem is that we're not sure what scheduling an idle callback from inside another idle callback really means. Is it a "hey, poke me sometime later, I have more work quanta but don't want to deal with them right now for some reason", is it a "hey, I have a work quantum that needs X time by I have less time than that, let's try again later", or is it a "hey, poke me again later and I'll see whether I have work to do"? Maybe we should just allow callers to disambiguate somehow, and especially to communicate the "I'd like to run this when I have Xms uninterrupted time" case?

igrigorik commented 8 years ago

Anyway, as a substantive matter #28 (comment) last paragraph is what I think about this setup.

Fundamentally, the problem is that we're not sure what scheduling an idle callback from inside another idle callback really means. Is it a "hey, poke me sometime later, I have more work quanta but don't want to deal with them right now for some reason", is it a "hey, I have a work quantum that needs X time by I have less time than that, let's try again later", or is it a "hey, poke me again later and I'll see whether I have work to do"? Maybe we should just allow callers to disambiguate somehow, and especially to communicate the "I'd like to run this when I have Xms uninterrupted time" case?

@bzbarsky in its current form, it's implicitly ~"poke me during your next idle period and I'll see whether I have work to do". I do agree that it might be useful to allow more flexible scheduling - e.g. reschedule within same idle period, schedule into long idle period or a period with at least X time, and so on. That said, I think this is a feature we should consider for "L2" version of the spec.. if there is sufficient interest and demand for such thing.

In the meantime, I propose we add a note in the spec to document that this is something we've considered and might want to explore in the future. Does that sound reasonable to you?

bzbarsky commented 8 years ago

"poke me during your next idle period and I'll see whether I have work to do"

OK, but why do we think this is the most common thing to want?

Apart from that, I have no strong opinions on this stuff anymore; I've sort of stopped caring....

igrigorik commented 8 years ago

OK, but why do we think this is the most common thing to want?

Current design was informed by our experience with the scheduler use cases used by the various (internal) subsystems within Chrome; current API exposes same/similar capabilities to web developers... And, based on current adoption metrics (up to ~5% of page loads in Chrome), it appears to be doing well with the current model -- I've certainly had people ask about alternative scheduling strategies, but it hasn't (yet) been raised as a blocker.

I've added a note in the spec: https://github.com/w3c/requestidlecallback/commit/9e2694f30839ec3d7d39933eafe9a7f485c4fcf3

Closing this. If we want to explore adding alternative strategies, let's open a separate bug for L2.