Evaluate an alternative to polling for frecency recalcs
Categories
(Toolkit :: Places, defect, P3)
Tracking
()
| Tracking | Status | |
|---|---|---|
| firefox112 | --- | fixed |
People
(Reporter: mak, Assigned: mak)
References
(Blocks 1 open bug)
Details
Attachments
(1 file)
Even if we tried to limit the impact, polling still has an energy impact.
An alternative may be
- Store a time instead of a boolean
- when recalc_frecency changes, check if current_time - stored_time > 1 minute, if so dispatch a runnable to the main-thread
- set stored_time = current_time
- the main thread runnable uses a 1 minute timer before starting the work.
This will be a bit more expensive every 1 minute to dispatch, and we need an efficient way to get the current time. Overall it may not be horrible.
| Assignee | ||
Comment 1•2 years ago
|
||
Using PR_IntervalNow() may be reasonable for this use case.
Comment 2•2 years ago
|
||
Thanks for looking into this!
I don't understand why this code will need to store the current time, but I'm not sure I understand the current behavior completely, so I'll try to explain what I understand, and if I'm missing something you can explain it.
- Whenever something (eg. a page load?) happens,
nsNavHistory::sShouldStartFrecencyRecalculationis set to true inSetShouldStartFrecencyRecalculationFunction::OnFunctionCall(and that could happen from multiple threads). - A repeating 1 minute timer checks the value of
sShouldStartFrecencyRecalculationand if it is true, arms a 2 minutes deferred task and setssShouldStartFrecencyRecalculationback to false. - Actual work is performed when the deferred task executes, in chunks of limited size. If work is left after processing a chunk, the task is re-armed.
Assuming all the above is accurate, would the following simplification work?
- In
SetShouldStartFrecencyRecalculationFunction::OnFunctionCall, instead ofnsNavHistory::sShouldStartFrecencyRecalculation = true;, doif (nsNavHistory::sShouldStartFrecencyRecalculation.exchange(true) == false) /* dispatch a(n idle) main thread runnable */; - From that main thread runnable, arm the deferred task.
- When
recalculateSomeFrecencieshas finished a chunk, queue processing of the next chunk immediately in an idle runnable. - Set
nsNavHistory::sShouldStartFrecencyRecalculationback to false only whenrecalculateSomeFrecencieshas determined there's nothing left to recalculate.
It might be possible to simplify even more by replacing "dispatch a(n idle) main thread runnable" in #1 with "start a 3 minutes timer targeting the main thread" and then get rid of the deferred task entirely. But that would likely be more refactoring for very little actual improvements.
| Assignee | ||
Comment 3•2 years ago
•
|
||
(In reply to Florian Quèze [:florian] from comment #2)
Thanks for looking into this!
I don't understand why this code will need to store the current time
Pretty much just an idea to limit the number of runnables dispatched (max 1 runnable every minute).
- In
SetShouldStartFrecencyRecalculationFunction::OnFunctionCall, instead ofnsNavHistory::sShouldStartFrecencyRecalculation = true;, doif (nsNavHistory::sShouldStartFrecencyRecalculation.exchange(true) == false) /* dispatch a(n idle) main thread runnable */;- From that main thread runnable, arm the deferred task.
- When
recalculateSomeFrecencieshas finished a chunk, queue processing of the next chunk immediately in an idle runnable.- Set
nsNavHistory::sShouldStartFrecencyRecalculationback to false only whenrecalculateSomeFrecencieshas determined there's nothing left to recalculate.
This may work, the only downside I can think of is that between the time we complete the calculation, and the time we set the bool to false, there may be some time where sShouldStartFrecencyRecalculation is still true and a further try to set it to true will be ignored.
In practice it may not be a problem, it just means we'll wait for the next operation affecting frecency or the next session in the worst case, to recalculate.
It might be possible to simplify even more by replacing "dispatch a(n idle) main thread runnable" in #1 with "start a 3 minutes timer targeting the main thread" and then get rid of the deferred task entirely.
The scope of the deferred task is not just to run after N minutes, but also to try to run during idle intervals, if possible (Ah I see, we could dispatch an idle runnable and be done with it... I still prefer DeferredTask for the simplicity to handle it on js side).
I like your idea so let me try it.
| Assignee | ||
Comment 4•2 years ago
|
||
Rather than checking every minute for work to do, use .exchange() to check
if sShouldStartFrecencyRecalculation switches to true and if so dispatch a
runnable to notify PlacesFrecencyRecalculator. The latter sets back
sShouldStartFrecencyRecalculation to false once the recalculation is complete.
Comment 6•2 years ago
|
||
Backed out for causing for causing xpc failures in toolkit/components/search/tests/xpcshell/test_searchSuggest_cookies.js
Backout link: https://hg.mozilla.org/integration/autoland/rev/af5417c4556aa4e16a82d4f0d5be42652be36cf8
| Assignee | ||
Comment 7•2 years ago
|
||
ah yes, I was overzealous with an error check, it may actually happen in reality due to how categories work.
Comment 9•2 years ago
|
||
| bugherder | ||
Updated•2 years ago
|
Description
•