After GC/CC completion, jemalloc_free_dirty_pages() synchronously purges
every arena on the main thread. This is redundant when the idle purge
infrastructure (memory.lazypurge.*) is enabled, since arenas are already
queued for deferred purge during GC by the allocation path.
Add TaskController::RequestIdleMemoryCleanup() which kicks the idle purge
runner without the pending-task guard that MayScheduleIdleMemoryCleanup
has, and falls back to synchronous purge when lazy purge is disabled.
Replace the two jemalloc_free_dirty_pages() calls in nsJSEnvironment.cpp
(GC and CC completion) with this new method.
Differential Revision: https://phabricator.services.mozilla.com/D284731
We can leverage std::set's extract / insert to avoid allocations when updating task priorities.
It is assumed that this is always better, also for a small number of tasks.
Differential Revision: https://phabricator.services.mozilla.com/D269142
This captures stacks during runnable dispatch which is really
helpful for understanding what's going on and debugging flows.
It's conditional on the Flows profiler feature so that we don't
take the performance cost all the time.
Differential Revision: https://phabricator.services.mozilla.com/D264474
This avoids the small overhead and potential for bugs from the previous
approach of assuming all `const char*` arguments passed to `nsITimer`
initializers are string literals, by instead requiring the argument to be a
`const nsACString&`. This involves changing all callsites to pass a `""_ns`
string literal down instead of a bare string literal.
It appears that while there were currently no buggy callers which
would've provided a dynamic string, there was at least one piece of code
(nsRepeatService::Start) which did pass down a raw char* which may be
dynamically allocated (all callers pass down `nsLiteralCString` so we're
actually OK here right now, but this was a footgun).
Differential Revision: https://phabricator.services.mozilla.com/D261032
This reverts commit 8c929cc018.
Revert "Bug 1979013 - Part 2: Require nsITimer API callers to provide a nsACString, r=xpcom-reviewers,media-playback-reviewers,webrtc-reviewers,profiler-reviewers,dom-storage-reviewers,toolkit-telemetry-reviewers,firefox-style-system-reviewers,mstange,emz,bwc,janv,emilio,padenot"
This reverts commit e01c0a6a32.
Revert "Bug 1979013 - Part 1: Eagerly fetch name for timer callbacks, r=xpcom-reviewers,mccr8"
This reverts commit 9f8e73c163.
This avoids the small overhead and potential for bugs from the previous
approach of assuming all `const char*` arguments passed to `nsITimer`
initializers are string literals, by instead requiring the argument to be a
`const nsACString&`. This involves changing all callsites to pass a `""_ns`
string literal down instead of a bare string literal.
It appears that while there were currently no buggy callers which
would've provided a dynamic string, there was at least one piece of code
(nsRepeatService::Start) which did pass down a raw char* which may be
dynamically allocated (all callers pass down `nsLiteralCString` so we're
actually OK here right now, but this was a footgun).
Differential Revision: https://phabricator.services.mozilla.com/D261032
Normally we expect timer creation/initialization to be infallible, but there appear to be rare cases where it fails.
It would be good to understand the cause, but first of all we should honor the return value in case of error.
Note that allocations during timer init are infallible since bug 1961386, so most likely the cause is not running low on memory.
Differential Revision: https://phabricator.services.mozilla.com/D262593
* Group the two kinds of markers for an idle purge into one. Previously
one delimited the operation and another one marked the result. Now the
result is a field in marker for the whole operation.
* Rename the RunIdleMemoryCleanup marker to IdlePurge.
* Rename the marker for peeking at the status to IdlePurgePeek.
* Move all markers to the GCCC type.
Differential Revision: https://phabricator.services.mozilla.com/D241938
* Group the two kinds of markers for an idle purge into one. Previously
one delimited the operation and another one marked the result. Now the
result is a field in marker for the whole operation.
* Rename the RunIdleMemoryCleanup marker to IdlePurge.
* Rename the marker for peeking at the status to IdlePurgePeek.
* Move all markers to the GCCC type.
Differential Revision: https://phabricator.services.mozilla.com/D241938
* Group the two kinds of markers for an idle purge into one. Previously
one delimited the operation and another one marked the result. Now the
result is a field in marker for the whole operation.
* Rename the RunIdleMemoryCleanup marker to IdlePurge.
* Rename the marker for peeking at the status to IdlePurgePeek.
* Move all markers to the GCCC type.
Differential Revision: https://phabricator.services.mozilla.com/D241938
We want to better predict when it is a good moment to purge. D220616 answered well the question, when to best process a purge when it is needed (that is, during main thread idle time), but that does not necessarily mean it is a good idea for a single arena, to purge in that moment as arenas can be used on other threads intensely while the main thread is idle.
If we saw a recent re-use in an arena we can most likely expect to come more of that and wait with purge a little more. So whenever we are able to re-use a dirty page, we assume that this is a sign of a significant re-use that avoided an allocation of new memory.
We can record a timestamp of when this happened. Unless forced, purge requests are only executed, if their grace period wrt the last significant re-use expired.
Finally we introduce the third result `WantsLater` for a single purge step, which indicates that there are purge requests that wait for their grace period to expire and the main thread should do some later extra spin to process those.
***
Default Atomic
Differential Revision: https://phabricator.services.mozilla.com/D223709
The page size on arm64 macOS and iOS is 16k, yet we try to create stacks with
sizes which are not a multiple of 16k in some situations. Unify these stack
size calculations, and ensure they are always a multiple of the system page
size.
On arm64 macOS, the posix threads implementation is detecting stack sizes which
are a multiple of 4k, and rounding them up to a multiple of 16k to improve
compatibility, but that is not done on iOS.
Differential Revision: https://phabricator.services.mozilla.com/D236402
We can defer the purging of arenas to happen during idle processing on the main thread.
We already have the following prerequisites thanks to bug 1488780:
- The (often) expensive OS functions to give back memory pages are not blocking the use of the arena on other threads anymore.
- A single call to moz_may_purge_one_now (D232083) wraps just arena_t::Purge() that will just do "some work on one chunk" and tell if more is needed, giving us a fine grained control.
Synchronous purging can block the caller of a memory freeing function for an unexpectedly long time. Furthermore, memory that might be reclaimed very soon can be madvised early and thus its reuse can lead to frequent page faults.
We thus use moz_enable_deferred_purge (see D232083) to queue purge requests and execute them on the main thread only if it is about to become idle. We do this using an IdleTaskRunner that ensures we won't purge too often or never.
We believe that the main thread being idle is probably the best easy indicator we have to tell if the process is idle enough to purge without performance regrets.
We expect the peak memory usage of a single arena to not be affected significantly by this during normal use, but the time that this peak holds up might extend. This means the peak sum of all memory from all running processes may rise for short periods of time until enough purges happened on potentially several processes.
There is a chance to mitigate this effect by lowering the settings of allowed dirty pages for arenas, as there should be less churn in general with this patch, potentially resulting in a lower memory usage in average.
Differential Revision: https://phabricator.services.mozilla.com/D220616
Setting this property to true is a promise that the the marker will nest
properly. i.e. it can't have a partially overlapping time range with any other
stack based markers on the same thread.
Differential Revision: https://phabricator.services.mozilla.com/D230006
This replaces TaskController::mThreadPoolCV with an individual condition
variable for each thread, and uses these to wake individual threads. The task
for each thread is assigned beforehand by setting mCurrentTask.
The counter mIdleThreadCount is used to quickly tell if there are any threads
free.
This splits TaskController::RunPoolThread to move the task selection part to
SelectTaskToRun. MaybeDispatchOneTask is called whenever there may be a new
task to dispatch (this runs from both the main thread and pool threads).
I tried to keep the same behaviour with mEffectiveTaskPriority but I don't
fully understand what this is being used for.
Differential Revision: https://phabricator.services.mozilla.com/D214958
This passes a pointer to the current pool thread to RunPoolThread, removing the
need for thread local storage. It also does some refactoring, moving the
PoolThread definition out of the header file.
This also changes the thread vector to use UniquePtr is necessary for the next
patch which adds a CondVar to PoolThread.
Differential Revision: https://phabricator.services.mozilla.com/D214957