Seperate the cache of unallocated memory into: dirty, clean, unmapped.
Categories
(Core :: Memory Allocator, enhancement)
Tracking
()
| Tracking | Status | |
|---|---|---|
| firefox153 | --- | fixed |
People
(Reporter: pbone, Assigned: pbone)
References
(Blocks 2 open bugs)
Details
(Whiteboard: [sp3])
Attachments
(2 files)
jemalloc uses a single red-black tree to look for unallocated pages, they're sorted by size so it can to "best fit" allocation. But not by "status". So if in the tree there is a unmapped block of 4 pages before a dirty block of 4 pages. and the allocator is looking for at least two pages, it may map in the new memory (increasing RSS) rather than use 2 dirty pages (decreasing overheads). This is especially true if for example there was a block of 6 dirty pages which will always be sorted after 4 unmapped pages.
We should modify jemalloc to create multiple free lists for: dirty, clean, unmapped and check them in sequence. This could improve Firefox's memory footprint and performance.
Comment 1•2 years ago
|
||
Wouldn't changing ArenaAvailTreeTrait to account for the status have roughly the same effect?
| Assignee | ||
Comment 2•2 years ago
|
||
(In reply to Mike Hommey [:glandium] from comment #1)
Wouldn't changing ArenaAvailTreeTrait to account for the status have roughly the same effect?
it depends. it's work for the cases where there's a dirty block of 4 pages and an unmapped block of 4 pages.
When there's an unmapped block of 4 pages and a dirty block of 5 pages though I think separate lists would be good. In that case changing the tree trait won't work and I think we'd be happy with that fragmentation rather than mapping in new memory when dirty memory is already there.
What I don't know is if there's a block of 128 pages of dirty memory and we only want to allocate 1 page. Is fragmenting that block okay (we already do that if there's no smaller blocks) Especially since a future allocations are more likely to request a more even 128 pages rather than 127.
Comment 3•2 years ago
|
||
Well, that kind of hits the crux of the issue, which is, is it really more beneficial to use that dirty block of 5 pages or that unmapped block of 4 pages, and how often are you likely to have to make this choice? And as you point out, even if it is beneficial, is there a limit to the size of that dirty block over which you get diminished returns.
| Assignee | ||
Comment 4•2 years ago
|
||
Agreed. I think the first step here would be to do some kind of logging/test to see how often different things happen. then maybe to estimate or test for the costs.
Updated•2 years ago
|
Updated•2 years ago
|
| Assignee | ||
Comment 5•3 months ago
|
||
I'm going to separate this bug into two. The first part (this one) will prefer dirty, then fresh/other then decommitted memory within a size. That is it won't prefer allocating 5 dirty pages rather than 4 decommitted pages.
The 2nd part (Bug 2024836) can take this further to prefer dirty memory at the cost of fragmentation.
| Assignee | ||
Comment 6•3 months ago
|
||
We can prefer to allocate from dirty runs by inserting dirty runs at the
head of a size class' list and other runs at the end.
| Assignee | ||
Comment 7•3 months ago
|
||
Further refine the order runs are returned by inserting fresh and other
runs in the middle of a size class' list leaving only decommitted and
madvised runs to be inserted at the end.
| Assignee | ||
Comment 8•3 months ago
•
|
||
Here are the pref results: https://perf.compare/compare-results?baseRev=52da6d23edc91dc72046025d9ca19b81533409f5&baseRepo=try&newRev=d1e4ac0cb8ae9683952459ef2cf84373fbd2f80b&newRepo=try&framework=13 This improves on Bug 1932624 by allocating dirty pages first and decommitted pages last.
Comment 9•3 months ago
|
||
(In reply to Paul Bone [:pbone] from comment #8)
Here are the pref results: https://perf.compare/compare-results?baseRev=52da6d23edc91dc72046025d9ca19b81533409f5&baseRepo=try&newRev=d1e4ac0cb8ae9683952459ef2cf84373fbd2f80b&newRepo=try&framework=13 This improves on Bug 1932624 by allocating dirty pages first and decommitted pages last.
Interesting. This seems to help old macOS (which did regress in the bug 1932624 runs, so one would need to look at the sum), but slightly regresses Android. Not sure if there can be some interference with OS level optimizations (maybe in some cases the OS maps fresh memory on recently used memory already?). Overall I'd probably think we are less interested in old macOS wrt Android.
| Assignee | ||
Comment 11•3 months ago
|
||
(In reply to Jens Stutte [:jstutte] from comment #10)
Do we have a try run with only pt1 of this stack?
https://treeherder.mozilla.org/jobs?repo=try&revision=a4d65acaaf24a1d44a98c6301b5c2aaf481f32ee
it's still processing but it doesn't seem wonderful. So it chooses LIFO for dirty runs and FIFO for everything else. We could instead try LIFO for everything else and FIFO for decommitted runs.
| Assignee | ||
Updated•3 months ago
|
Updated•3 months ago
|
Updated•3 months ago
|
Comment 12•25 days ago
|
||
Comment 13•25 days ago
|
||
| bugherder | ||
https://hg.mozilla.org/mozilla-central/rev/701b38860543
https://hg.mozilla.org/mozilla-central/rev/913096c89165
Updated•19 days ago
|
Description
•