mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-03-27 01:01:52 -07:00
Fixed word wrap.
Copied from Perforce Change: 179344 ServerID: perforce.ravenbrook.com
This commit is contained in:
parent
b2f94388e4
commit
272ccfdf4a
1 changed files with 89 additions and 18 deletions
|
|
@ -192,47 +192,118 @@ System](..\manual\build.txt), part of the manual.
|
|||
6. The second stage fix in the MPM
|
||||
----------------------------------
|
||||
If a pointer gets past the first-stage fix filters, it is passed to
|
||||
`_mps_fix2`, the "second stage fix". The second stage can filter out yet more pointers using information about segments before it has to consult the pool class.
|
||||
`_mps_fix2`, the "second stage fix". The second stage can filter out
|
||||
yet more pointers using information about segments before it has to
|
||||
consult the pool class.
|
||||
|
||||
The first test applied is the "tract test". The MPS looks up the tract containing the address in the tract table, which is a simple linear table indexed by the address shifted -- a kind of flat page table.
|
||||
The first test applied is the "tract test". The MPS looks up the tract
|
||||
containing the address in the tract table, which is a simple linear
|
||||
table indexed by the address shifted -- a kind of flat page table.
|
||||
|
||||
Note that if the arena has been extended, the tract table becomes less simple, and this test may involved looking in more than one table. This will cause a considerable slow-down in garbage collection scanning. This is the reason that it's important to give a good estimate of the amount of address space you will ever occupy with objects when you initialize the arena.
|
||||
Note that if the arena has been extended, the tract table becomes less
|
||||
simple, and this test may involved looking in more than one table. This
|
||||
will cause a considerable slow-down in garbage collection scanning.
|
||||
This is the reason that it's important to give a good estimate of the
|
||||
amount of address space you will ever occupy with objects when you
|
||||
initialize the arena.
|
||||
|
||||
The pointer might not even be in the arena (and so not in any tract). The first stage fix doesn't guarantee it. So we eliminate any pointers not in the arena at this stage.
|
||||
The pointer might not even be in the arena (and so not in any tract).
|
||||
The first stage fix doesn't guarantee it. So we eliminate any pointers
|
||||
not in the arena at this stage.
|
||||
|
||||
If the pointer is in an allocated tract, then the table also contains a cache of the "white set" -- the set of garbage collection traces for which the tract is "interesting". If a tract isn't interesting, then we know that it contains no condemned objects, and we can filter out the pointer.
|
||||
If the pointer is in an allocated tract, then the table also contains a
|
||||
cache of the "white set" -- the set of garbage collection traces for
|
||||
which the tract is "interesting". If a tract isn't interesting, then we
|
||||
know that it contains no condemned objects, and we can filter out the
|
||||
pointer.
|
||||
|
||||
If the tract is interesting them it's part of a segment containing objects that have been condemned. The MPM can't know anything about the internal layout of the segment, so at this point we dispatch to the third stage fix.
|
||||
If the tract is interesting them it's part of a segment containing
|
||||
objects that have been condemned. The MPM can't know anything about the
|
||||
internal layout of the segment, so at this point we dispatch to the
|
||||
third stage fix.
|
||||
|
||||
This dispatch is slightly subtle. We have a cache of the function to dispatch to in the scan state, which has recently been looked at and is with luck still in the processor cache. The reason there is a dispatch at all is to allow for a fast changeover to emergency garbage collection, or overriding of garbage collection with extra operations. Those are beyond the scope of this document. Normally, `ss->fix` points at `PoolFix`, and we rely somewhat on modern processor [branch target prediction](https://en.wikipedia.org/wiki/Branch_target_predictor). `PoolFix` is passed the pool, which is fetched from the tract table entry, and that should be in the cache.
|
||||
This dispatch is slightly subtle. We have a cache of the function to
|
||||
dispatch to in the scan state, which has recently been looked at and is
|
||||
with luck still in the processor cache. The reason there is a dispatch
|
||||
at all is to allow for a fast changeover to emergency garbage
|
||||
collection, or overriding of garbage collection with extra operations.
|
||||
Those are beyond the scope of this document. Normally, `ss->fix` points
|
||||
at `PoolFix`, and we rely somewhat on modern processor [branch target
|
||||
prediction](https://en.wikipedia.org/wiki/Branch_target_predictor).
|
||||
`PoolFix` is passed the pool, which is fetched from the tract table
|
||||
entry, and that should be in the cache.
|
||||
|
||||
`PoolFix` itself dispatches to the pool class. Normally, a dispatch to a pool class would indirect through the pool class object. That would be a double indirection from the tract, so instead we have a cache of the pool's fix method in the pool object. This also allows a pool class to vary its fix method per pool instance, a fact that is exploited to optimize fixing in the AMC Pool depending on what kind of object format it is managing.
|
||||
`PoolFix` itself dispatches to the pool class. Normally, a dispatch to
|
||||
a pool class would indirect through the pool class object. That would
|
||||
be a double indirection from the tract, so instead we have a cache of
|
||||
the pool's fix method in the pool object. This also allows a pool class
|
||||
to vary its fix method per pool instance, a fact that is exploited to
|
||||
optimize fixing in the AMC Pool depending on what kind of object format
|
||||
it is managing.
|
||||
|
||||
|
||||
7. The third stage fix in the pool class
|
||||
----------------------------------------
|
||||
The final stage of fixing is entirely dependent on the pool class. The MPM can't, in general, know how the objects within a pool are arranged, so this is pool class specific code.
|
||||
The final stage of fixing is entirely dependent on the pool class. The
|
||||
MPM can't, in general, know how the objects within a pool are arranged,
|
||||
so this is pool class specific code.
|
||||
|
||||
Furthermore, the pool class must make decisions based on the "reference rank" of the pointer. If a pointer is ambiguous (`RankAMBIG`) then it can't be changed, so even a [copying] pool class can't move an object. On the other hand, if the pointer is weak (`RankWEAK`) then the pool fix method shouldn't preserve the object at all, even if it's condemned.
|
||||
Furthermore, the pool class must make decisions based on the "reference
|
||||
rank" of the pointer. If a pointer is ambiguous (`RankAMBIG`) then it
|
||||
can't be changed, so even a [copying] pool class can't move an object.
|
||||
On the other hand, if the pointer is weak (`RankWEAK`) then the pool fix
|
||||
method shouldn't preserve the object at all, even if it's condemned.
|
||||
|
||||
The exact details of the logic that the pool fix must implement in order to co-operate with the MPM and other pools are beyond the scope of this document, which is about the critical path. It being the critical path, it's important that whatever the pool fix does is simple and fast and returns to scanning as soon as possible.
|
||||
The exact details of the logic that the pool fix must implement in order
|
||||
to co-operate with the MPM and other pools are beyond the scope of this
|
||||
document, which is about the critical path. It being the critical path,
|
||||
it's important that whatever the pool fix does is simple and fast and
|
||||
returns to scanning as soon as possible.
|
||||
|
||||
The first step, though, it to further filter out pointers which aren't to objects, if that's its policy. Then, it may preserve the object, according to its policy, and possibly ensure that the object gets scanned at some point in the future, if it contains more pointers.
|
||||
The first step, though, it to further filter out pointers which aren't
|
||||
to objects, if that's its policy. Then, it may preserve the object,
|
||||
according to its policy, and possibly ensure that the object gets
|
||||
scanned at some point in the future, if it contains more pointers.
|
||||
|
||||
As a simple example, `LOFix` is the pool fix method for the Leaf Only pool class. It implements a [marking] garbage collector, and does not have to worry about scanning preserved objects because it is used to store objects that don't contain pointers. (It is used in compiler run-time systems to store binary data such as character strings, thus avoiding any scanning, decoding, or remembered set overhead for them.)
|
||||
As a simple example, `LOFix` is the pool fix method for the Leaf Only
|
||||
pool class. It implements a [marking] garbage collector, and does not
|
||||
have to worry about scanning preserved objects because it is used to
|
||||
store objects that don't contain pointers. (It is used in compiler
|
||||
run-time systems to store binary data such as character strings, thus
|
||||
avoiding any scanning, decoding, or remembered set overhead for them.)
|
||||
|
||||
`LOFix` filters any ambiguous pointers that aren't aligned, since they can't point to objects it allocated. Otherwise it subtracts the segment base address and shifts the result to get an index into a mark bit table. If the object wasn't marked and the pointer is weak, then it sets the pointer to zero, since the object is about to be recycled. Otherwise, the mark bit is set, which preserves the object from recycling when `LOReclaim` is called later on. `LOFix` illustrates about the minimum and most efficient thing a pool fix method can do.
|
||||
`LOFix` filters any ambiguous pointers that aren't aligned, since they
|
||||
can't point to objects it allocated. Otherwise it subtracts the segment
|
||||
base address and shifts the result to get an index into a mark bit
|
||||
table. If the object wasn't marked and the pointer is weak, then it
|
||||
sets the pointer to zero, since the object is about to be recycled.
|
||||
Otherwise, the mark bit is set, which preserves the object from
|
||||
recycling when `LOReclaim` is called later on. `LOFix` illustrates
|
||||
about the minimum and most efficient thing a pool fix method can do.
|
||||
|
||||
|
||||
8. Other considerations
|
||||
-----------------------
|
||||
So far this document has described the ways in which the garbage collector is designed around optimising the critical path. There are a few other things that the MPS does that are important.
|
||||
So far this document has described the ways in which the garbage
|
||||
collector is designed around optimising the critical path. There are a
|
||||
few other things that the MPS does that are important.
|
||||
|
||||
Firstly, inlining is very important. The first stage fix is inlined into the format scanner by being implemented in macros in [mps.h](..\code\mps.h). And to get even better inlining, [we recommend](..\manual\build.txt) that the whole MPS is compiled in a single translation unit with the client format and that strong global optimisation is applied.
|
||||
Firstly, inlining is very important. The first stage fix is inlined
|
||||
into the format scanner by being implemented in macros in
|
||||
[mps.h](..\code\mps.h). And to get even better inlining, [we
|
||||
recommend](..\manual\build.txt) that the whole MPS is compiled in a
|
||||
single translation unit with the client format and that strong global
|
||||
optimisation is applied.
|
||||
|
||||
Secondly, we are very careful with code annotations on the critical path. Assertions, statistics, and telemetry are all disabled on the critical path in "hot" (production) builds. (In fact, it's because the critical path is critical that we can afford to leave annotations switched on elsewhere.)
|
||||
Secondly, we are very careful with code annotations on the critical
|
||||
path. Assertions, statistics, and telemetry are all disabled on the
|
||||
critical path in "hot" (production) builds. (In fact, it's because the
|
||||
critical path is critical that we can afford to leave annotations
|
||||
switched on elsewhere.)
|
||||
|
||||
Last, but by no means least, we pay a lot of brainpower and measurement to the critical path, and are very very careful about changing it. Code review around the critical path is especially vigilant.
|
||||
Last, but by no means least, we pay a lot of brainpower and measurement
|
||||
to the critical path, and are very very careful about changing it. Code
|
||||
review around the critical path is especially vigilant.
|
||||
|
||||
And we write long documents about it.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue