diff --git a/mps/manual/html/_sources/design/abq.txt b/mps/manual/html/_sources/design/abq.txt new file mode 100644 index 00000000000..a6846871029 --- /dev/null +++ b/mps/manual/html/_sources/design/abq.txt @@ -0,0 +1,106 @@ +.. _design-abq: + + +Queue design +============ + +.. mps:prefix:: design.mps.abq + + +Introduction +------------ + +:mps:tag:`intro` This is the design of the ABQ module, which implements a +fixed-length queue of small objects. + +:mps:tag:`readership` This document is intended for any MM developer. + +:mps:tag:`name` The name ABQ originally stood for "Available Block Queue" as +the module is used by the MVT pool. + + +Requirements +------------ + +:mps:tag:`req.push` Clients can efficiently push new elements onto the queue. + +:mps:tag:`req.pop` Clients can efficiently pop elements from the queue. + +:mps:tag:`req.empty` Clients can efficiently test whether the queue is empty. + +:mps:tag:`req.abstract` The ABQ module does not know anything about the +elements in the queue other than their size. + +:mps:tag:`req.delete` Clients can delete elements from the queue. (Note: not necessarily efficiently.) + +:mps:tag:`req.iterate` Clients can iterate over elements in the queue. + + +Interface +--------- + +.. c:type:: ABQStruct *ABQ + +:c:macro:`ABQ` is the type of a queue. It is an alias for ``ABQStruct *``. +:c:type:`ABQStruct` is defined in the header so that it can be inlined in +client structures: clients must not depend on its implementation +details. + +.. c:function:: ABQInit(Arena arena, ABQ abq, void *owner, Count elements, Size elementSize) + +Initialize the queue ``abq``. The parameter ``arena`` is the arena +whose control pool should be used to allocate the memory for the +queue; ``owner`` is passed to :c:func:`MeterInit()` for the statistics; +``elements`` is the maximum number of elements that can be stored in +the queue; and ``elementSize`` is the size of each element. + +.. c:function:: void ABQFinish(Arena arena, ABQ abq) + +Finish ``abq`` and free all resources associated with it. + +.. c:function:: Res ABQPush(ABQ abq, void *element) + +If the queue is full, leave it unchanged and return ``ResFAIL``. +Otherwise, push ``element`` on to the queue and return ``ResOK``. + +.. c:function:: Res ABQPop(ABQ abq, void *elementReturn) + +If the queue is empty, return ``ResFAIL``. Othwreise, copy the first +element on the queue into the memory pointed to by ``elementReturn``, +remove the element from the queue, and return ``ResOK``. + +.. c:function:: Res ABQPeek(ABQ abq, void *elementReturn) + +If the queue is empty, return ``ResFAIL``. Otherwise, copy the first +element on the queue into the memory pointed to by ``elementReturn`` +and return ``ResOK``. (This is the same as :c:func:`ABQPop()` except that +the queue is unchanged.) + +.. c:function:: Bool ABQIsEmpty(ABQ abq) + +If the queue is empty, return :c:macro:`TRUE`, otherwise return :c:macro:`FALSE`. + +.. c:function:: Bool ABQIsFull(ABQ abq) + +If the queue is full, return :c:macro:`TRUE`, otherwise return :c:macro:`FALSE`. + +.. c:function:: Count ABQDepth(ABQ abq) + +Return the number of elements in the queue. + +.. c:type:: Bool (*ABQIterateMethod)(Bool *deleteReturn, void *element, void *closureP, Size closureS) + +A callback function for :c:func:`ABQIterate()`. The parameter ``element`` is +an element in the queue, and ``closureP`` and ``closureS`` are the +values that were originally passed to :c:func:`ABQIterate()`. This function +must set ``*deleteReturn`` to :c:macro:`FALSE` if ``element`` must be kept in +the queue, or :c:macro:`TRUE` if ``element`` must be deleted from the queue. +It must return :c:macro:`TRUE` if the iteration must continue, or :c:macro:`FALSE` +if the iteration must stop after processing ``element``. + +.. c:function:: void ABQIterate(ABQ abq, ABQIterateMethod iterate, void *closureP, Size closureS) + +Call ``iterate`` for each elements in the queue, passing the element +and ``closureP``. See :c:type:`ABQIterateMethod` for details. + + diff --git a/mps/manual/html/_sources/design/boot.txt b/mps/manual/html/_sources/design/boot.txt new file mode 100644 index 00000000000..ce4d55de18e --- /dev/null +++ b/mps/manual/html/_sources/design/boot.txt @@ -0,0 +1,37 @@ +.. _design-boot: + + +The MPS Bootstrap +================= + +.. mps:prefix:: design.mps.boot + + +Introduction +------------ +The `Memory Pool System`_ starts with no memory, but must somehow +allocate its own control structures in order to provide memory to the +client program. The MPS is freestanding [ref?] and so it can't get its +memory from the C library's ``malloc``. So how does it get off the +ground? It pulls itself up by its own bootstraps. This document +describes how. + +.. note:: + + This document was written as a prelude to reforming the bootstrap, + so it shouldn't be taken as advocating it as an amazing piece of + design. + + +Pretty much the first call to the MPS is to ``ArenaCreate``, which calls the +arena class specific ``init`` method. That must create an initialized arena, +except for the "control pool", from which many MPS data structures will be +allocated. + +In the case of the VM arena, ``VMArenaInit`` creates a VM large enough to hold +a :c:type:`VMArenaStruct` (which contains the generic :c:type:`ArenaStruct`) and maps +pages into it. It then calls ``ArenaInit`` to initialise the generic part, +before filling in the VM-specific part. Having done that, it adds the initial +``VMChunk`` -- a large area of address space -- that will be used to supply +memory via ``ArenaAlloc``. + diff --git a/mps/manual/html/_sources/design/cbs.txt b/mps/manual/html/_sources/design/cbs.txt new file mode 100644 index 00000000000..8cc005422f0 --- /dev/null +++ b/mps/manual/html/_sources/design/cbs.txt @@ -0,0 +1,329 @@ +.. _design-cbs: + + +Coalescing block structure +========================== + +.. mps:prefix:: design.mps.cbs + + +Introduction +------------ + +:mps:tag:`intro` This is the design for impl.c.cbs, which implements a data +structure for the management of non-intersecting memory ranges, with +eager coalescence. + +:mps:tag:`readership` This document is intended for any MM developer. + +:mps:tag:`source` design.mps.poolmv2, design.mps.poolmvff. + +:mps:tag:`overview` The "coalescing block structure" is a set of addresses +(or a subset of address space), with provision for efficient +management of contiguous ranges, including insertion and deletion, +high level communication with the client about the size of contiguous +ranges, and detection of protocol violations. + + +Definitions +----------- + +:mps:tag:`def.range` A (contiguous) *range* of addresses is a semi-open +interval on address space. + +:mps:tag:`def.isolated` A contiguous range is *isolated* with respect to +some property it has, if adjacent elements do not have that property. + + +Requirements +------------ + +:mps:tag:`req.set` Must maintain a set of addresses. + +:mps:tag:`req.fast` Common operations must have a low amortized cost. + +:mps:tag:`req.add` Must be able to add address ranges to the set. + +:mps:tag:`req.remove` Must be able to remove address ranges from the set. + +:mps:tag:`req.size` Must report concisely to the client when isolated +contiguous ranges of at least a certain size appear and disappear. + +:mps:tag:`req.iterate` Must support the iteration of all isolated +contiguous ranges. This will not be a common operation. + +:mps:tag:`req.protocol` Must detect protocol violations. + +:mps:tag:`req.debug` Must support debugging of client code. + +:mps:tag:`req.small` Must have a small space overhead for the storage of +typical subsets of address space and not have abysmal overhead for the +storage of any subset of address space. + +:mps:tag:`req.align` Must support an alignment (the alignment of all +addresses specifying ranges) of down to ``sizeof(void *)`` without +losing memory. + + +Interface +--------- + +:mps:tag:`header` CBS is used through impl.h.cbs. + + +External types +.............. + +.. c:type:: struct CBSStruct *CBS + +:mps:tag:`type.cbs` :c:macro:`CBS` is the main data structure for manipulating a +CBS. It is intended that a :c:type:`CBSStruct` be embedded in another +structure. No convenience functions are provided for the allocation or +deallocation of the CBS. + +.. c:type:: Bool (*CBSIterateMethod)(CBS cbs, Range range, void *closureP, Size closureS) + +:mps:tag:`type.cbs.iterate.method` Type :c:type:`CBSIterateMethod` is a callback +function that may be passed to :c:func:`CBSIterate()`. It is called for +every isolated contiguous range in address order. The function must +returns a :c:type:`Bool` indicating whether to continue with the iteration. + + +External functions +.................. + +.. c:function:: Res CBSInit(Arena arena, CBS cbs, void *owner, Align alignment, Bool fastFind, ArgList args) + +:mps:tag:`function.cbs.init` :c:func:`CBSInit()` is the function that initialises +the CBS structure. It performs allocation in the supplied arena. The +parameter ``owner`` is passed to :c:func:`MeterInit()`, an ``alignment`` +indicates the alignment of ranges to be maintained. An initialised CBS +contains no ranges. + +``fastFind``, if set, causes the CBS to maintain, for each subtree, +the size of the largest block in that subtree. This must be true if +any of the :c:func:`CBSFindFirst()`, :c:func:`CBSFindLast()`, or +:c:func:`CBSFindLargest()` functions are going to be used on the CBS. + +:c:func:`CBSInit()` may take one keyword argument: + +* :c:macro:`MPS_KEY_CBS_EXTEND_BY` (type :c:type:`Size`; default 4096) is the size + of segment that the CBS will request from the arena in which to + allocate its ``CBSBlock`` structures. + +.. c:function:: void CBSFinish(CBS cbs) + +:mps:tag:`function.cbs.finish` :c:func:`CBSFinish()` is the function that finishes +the CBS structure and discards any other resources associated with the +CBS. + +.. c:function:: Res CBSInsert(Range rangeReturn, CBS cbs, Range range) + +:mps:tag:`function.cbs.insert` If any part of ``range`` is already in the +CBS, then leave it unchanged and return ``ResFAIL``. Otherwise, +attempt to insert ``range`` into the CBS. If the insertion succeeds, +then update ``rangeReturn`` to describe the contiguous isolated range +containing the inserted range (this may differ from ``range`` if there +was coalescence on either side) and return ``ResOK``. If the insertion +fails, return a result code indicating allocation failure. + +:mps:tag:`function.cbs.insert.fail` Insertion of a valid range (that is, one +that does not overlap with any range in the CBS) can only fail if the +new range is isolated and the allocation of the necessary data +structure to represent it failed. + + +.. c:function:: Res CBSDelete(Range rangeReturn, CBS cbs, Range range) + +:mps:tag:`function.cbs.delete` If any part of the range is not in the CBS, +then leave the CBS unchanged and return ``ResFAIL``. Otherwise, update +``rangeReturn`` to describe the contiguous isolated range that +contains ``range`` (this may differ from ``range`` if there are +fragments on either side) and attempt to delete the range from the +CBS. If the deletion succeeds, return ``ResOK``. If the deletion +fails, return a result code indicating allocation failure. + +:mps:tag:`function.cbs.delete.fail` Deletion of a valid range (that is, one +that is wholly contained in the CBS) can only fail if there are +fragments on both sides and the allocation of the necessary data +structures to represent them fails. + +:mps:tag:`function.cbs.delete.return` :c:func:`CBSDelete()` returns the contiguous +isolated range that contains ``range`` even if the deletion fails. +This is so that the caller can try deleting the whole block (which is +guaranteed to succeed) and managing the fragments using a fallback +strategy. + +.. c:function:: void CBSIterate(CBS cbs, CBSIterateMethod iterate, void *closureP, Size closureS) + +:mps:tag:`function.cbs.iterate` :c:func:`CBSIterate()` is the function used to +iterate all isolated contiguous ranges in a CBS. It receives a +pointer, :c:type:`Size` closure pair to pass on to the iterator method, +and an iterator method to invoke on every range in address order. If +the iterator method returns :c:macro:`FALSE`, then the iteration is +terminated. + +.. c:function:: Res CBSDescribe(CBS cbs, mps_lib_FILE *stream) + +:mps:tag:`function.cbs.describe` :c:func:`CBSDescribe()` is a function that prints +a textual representation of the CBS to the given stream, indicating +the contiguous ranges in order, as well as the structure of the +underlying splay tree implementation. It is provided for debugging +purposes only. + +.. c:function:: Bool CBSFindFirst(Range rangeReturn, Range oldRangeReturn, CBS cbs, Size size, FindDelete findDelete) + +:mps:tag:`function.cbs.find.first` Locate the first block (in address order) +within the CBS of at least the specified size, update ``rangeReturn`` +to describe that range, and return :c:macro:`TRUE`. If there is no such +block, it returns :c:macro:`FALSE`. + +In addition, optionally delete the top, bottom, or all of the found +range, depending on the ``findDelete`` argument. This saves a separate +call to :c:func:`CBSDelete()`, and uses the knowledge of exactly where we +found the range. The value of ``findDelete`` must come from this +enumeration:: + + enum { + FindDeleteNONE, /* don't delete after finding */ + FindDeleteLOW, /* delete size bytes from low end of block */ + FindDeleteHIGH, /* delete size bytes from high end of block */ + FindDeleteENTIRE /* delete entire range */ + }; + +The original contiguous isolated range in which the range was found is +returned via the ``oldRangeReturn`` argument. (If ``findDelete`` is +``FindDeleteNONE`` or ``FindDeleteENTIRE``, then this will be +identical to the range returned via the ``rangeReturn`` argument.) + +:c:func:`CBSFindFirst()` requires that ``fastFind`` was true when +:c:func:`CBSInit()` was called. + +.. c:function:: Bool CBSFindLast(Range rangeReturn, Range oldRangeReturn, CBS cbs, Size size, FindDelete findDelete) + +:mps:tag:`function.cbs.find.last` Like :c:func:`CBSFindFirst()`, except that it +finds the last block in address order. + +.. c:function:: Bool CBSFindLargest(Range rangeReturn, Range oldRangeReturn, CBS cbs, Size size, FindDelete findDelete) + +:mps:tag:`function.cbs.find.largest` Locate the largest block within the +CBS, and if that block is at least as big as ``size``, return its +range via the ``rangeReturn`` argument, and return :c:macro:`TRUE`. If there +are no blocks in the CBS at least as large as ``size``, return +:c:macro:`FALSE`. Pass 0 for ``size`` if you want the largest block +unconditionally. + +Like :c:func:`CBSFindFirst()`, optionally delete the range (specifying +``FindDeleteLOW`` or ``FindDeleteHIGH`` has the same effect as +``FindDeleteENTIRE``). This feature requires that ``fastFind`` was +true when :c:func:`CBSInit()` was called. + + +Implementation +-------------- + +:mps:tag:`impl` This section is concerned with describing various aspects of +the implementation. It does not form part of the interface definition. + + + +Splay tree +.......... + +:mps:tag:`impl.splay` The CBS is principally implemented using a splay tree +(see design.mps.splay_). Each splay tree node is embedded in a +``CBSBlock`` that represents a semi-open address range. The key passed +for comparison is the base of another range. + +.. _design.mps.splay: splay + +:mps:tag:`impl.splay.fast-find` :c:func:`CBSFindFirst()` and :c:func:`CBSFindLast()` use +the update/refresh facility of splay trees to store, in each +``CBSBlock``, an accurate summary of the maximum block size in the +tree rooted at the corresponding splay node. This allows rapid +location of the first or last suitable block, and very rapid failure +if there is no suitable block. + +:mps:tag:`impl.find-largest` :c:func:`CBSFindLargest()` simply finds out the size +of the largest block in the CBS from the root of the tree, using +:c:func:`SplayRoot()`, and does :c:func:`SplayFindFirst()` for a block of that +size. This is O(log *n*) in the size of the free list, so it's about +the best you can do without maintaining a separate priority queue, +just to do :c:func:`CBSFindLargest()`. + + +Low memory behaviour +.................... + +:mps:tag:`impl.low-mem` When the CBS tries to allocate a new ``CBSBlock`` +structure for a new isolated range as a result of either +:c:func:`CBSInsert()` or :c:func:`CBSDelete()`, and there is insufficient memory +to allocation the ``CBSBlock`` structure, then the range is not added +to the CBS or deleted from it, and the call to :c:func:`CBSInsert()` or +:c:func:`CBSDelete()` returns ``ResMEMORY``. + + +The CBS block +............. + +:mps:tag:`impl.cbs.block` The block contains a base-limit pair and a splay +tree node. + +:mps:tag:`impl.cbs.block.special` The base and limit may be equal if the +block is halfway through being deleted. + +:mps:tag:`impl.cbs.block.special.just` This conflates values and status, but +is justified because block size is very important. + + +Testing +------- + +:mps:tag:`test` The following testing will be performed on this module: + +:mps:tag:`test.cbstest` There is a stress test for this module in +impl.c.cbstest. This allocates a large block of memory and then +simulates the allocation and deallocation of ranges within this block +using both a :c:macro:`CBS` and a :c:type:`BT`. It makes both valid and invalid +requests, and compares the :c:macro:`CBS` response to the correct behaviour +as determined by the :c:type:`BT`. It also iterates the ranges in the +:c:macro:`CBS`, comparing them to the :c:type:`BT`. It also invokes the +:c:func:`CBSDescribe()` method, but makes no automatic test of the resulting +output. It does not currently test the callbacks. + +:mps:tag:`test.pool` Several pools (currently MVT_ and MVFF_) are implemented +on top of a CBS. These pool are subject to testing in development, QA, +and are/will be heavily exercised by customers. + +.. _MVT: poolmvt +.. _MVFF: poolmvff + + +Notes for future development +---------------------------- + +:mps:tag:`future.not-splay` The initial implementation of CBSs is based on +splay trees. It could be revised to use any other data structure that +meets the requirements (especially :mps:ref:`.req.fast`). + +:mps:tag:`future.hybrid` It would be possible to attenuate the problem of +:mps:ref:`.risk.overhead` (below) by using a single word bit set to represent +the membership in a (possibly aligned) word-width of grains. This +might be used for block sizes less than a word-width of grains, +converting them when they reach all free in the bit set. Note that +this would make coalescence slightly less eager, by up to +``(word-width - 1)``. + + +Risks +----- + +:mps:tag:`risk.overhead` Clients should note that the current implementation +of CBSs has a space overhead proportional to the number of isolated +contiguous ranges. [Four words per range.] If the CBS contains every +other grain in an area, then the overhead will be large compared to +the size of that area. [Four words per two grains.] The CBS structure +is thus suitable only for managing large enough ranges. + + + diff --git a/mps/manual/html/_sources/design/freelist.txt b/mps/manual/html/_sources/design/freelist.txt new file mode 100644 index 00000000000..c8a12533345 --- /dev/null +++ b/mps/manual/html/_sources/design/freelist.txt @@ -0,0 +1,257 @@ +.. _design-freelist: + + +Free list allocator +=================== + +.. mps:prefix:: design.mps.freelist + + +Introduction +------------ + +:mps:tag:`intro` This document describes the free list allocator for the +Memory Pool System. + +:mps:tag:`readership` Any MPS developer. + + +Overview +-------- + +:mps:tag:`overview` The free list allocator is an "emergency" allocator. It +is intended for use as a fallback allocation strategy in low memory +situations, when memory is not available for the control structures +needed by other allocators. In these situations the free list allocator +ensures that memory is not lost, but with several disadvantages: + +1. operations on the free list are O(n) in the number of free blocks; +2. the data structures are stored in client memory and so are + vulnerable to corruption; +3. the data structures have poor locality (and thus potentially poor + cache performance). + +When memory becomes available again to allocate control structures, +the free lists can be "flushed" back into the more efficient data +structures. + +:mps:tag:`bg` The free list allocator was formerly part of the Coalescing +Block Structure module (see design.mps.cbs) but it was split into its +own module because this makes it: + +1. simpler (no need to interact with CBS) and thus more maintainable; +2. possible to test directly (no need to create a CBS and then force + its control pool to run out of memory); and +3. usable as a fallback allocator in other pools (not just in pools + that use CBS). + + +Definitions +----------- + +:mps:tag:`def.range` A (contiguous) *range* of addresses is a semi-open +interval on address space. + +:mps:tag:`def.isolated` A contiguous range is *isolated* with respect to +some property it has, if adjacent elements do not have that property. + + +Requirements +------------ + +:mps:tag:`req.set` Must maintain a set of free address ranges. + +:mps:tag:`req.add` Must be able to add free address ranges to the set. + +:mps:tag:`req.remove` Must be able to remove address ranges from the set (in +particular, when memory is allocated). + +:mps:tag:`req.iterate` Must support the iteration of all isolated contiguous +ranges. + +:mps:tag:`req.protocol` Must detect protocol violations. + +:mps:tag:`req.align` Must support an alignment (the alignment of all +addresses specifying ranges) of down to ``sizeof(void *)`` without +losing memory. + +:mps:tag:`req.zero-overhead` Must have zero space overhead for the storage +of any set of free blocks, so that it can be used to manage memory +when no memory can be allocated for control structures. + +:mps:tag:`req.source` This set of requirements is derived from those of the +CBS module (see design.mps.cbs.req), except that there is no +equivalent of design.mps.cbs.req.fast, and design.mps.cbs.req.small +has been replaced with :mps:ref:`.req.zero-overhead`. + + +Interface +--------- + + +Types +..... + +.. c:type:: struct FreelistStruct *Freelist + +:mps:tag:`type.freelist` The type of free lists. The structure +:c:type:`FreelistStruct` is declared in the header so that it can be inlined +in other structures, but you should not depend on its details. + +.. c:type:: Bool (*FreelistIterateMethod)(Bool *deleteReturn, Freelist fl, Range range, void *closureP, Size closureS) + +:mps:tag:`type.iterate.method` A callback function that may be passed to +:c:func:`FreelistIterate()`. It is called for every isolated contiguous +range in address order, and with the closure arguments that were +originally passed to :c:func:`FreelistIterate()`. It must update +``*deleteReturn`` to :c:macro:`TRUE` if the range must be deleted from the +free lists, or :c:macro:`FALSE` if the range must be kept. The function must +return :c:macro:`TRUE` if the iteration must continue, and :c:macro:`FALSE` if the +iteration must stop (after possibly deleting the current range). + + +Functions +......... + +.. c:function:: Res FreelistInit(Freelist fl, Align alignment) + +:mps:tag:`function.init` Initialize the ``Freelist`` structure pointed to by +``fl``. The argument ``alignment`` is the alignment of address ranges +to be maintained. An initialised free list contains no address ranges. + +.. c:function:: void FreelistFinish(Freelist fl) + +:mps:tag:`function.finish` Finish the free list pointed to by ``fl``. + +.. c:function:: Res FreelistInsert(Range rangeReturn, Freelist fl, Range range) + +:mps:tag:`function.insert` If any part of ``range`` is already in the free +list ``fl``, then leave the free list unchanged and return +``ResFAIL``. Otherwise, insert ``range`` into the free list ``fl``; +update ``rangeReturn`` to describe the contiguous isolated range +containing the inserted range (this may differ from ``range`` if there +was coalescence on either side) and return ``ResOK``. + +.. c:function:: Res FreelistDelete(Range rangeReturn, Freelist fl, Range range) + +:mps:tag:`function.delete` If any part of the range is not in the free list, +then leave the free list unchanged and return ``ResFAIL``. Otherwise, +remove ``range`` from the free list and update ``rangeReturn`` to +describe the contiguous isolated range that formerly contained the +deleted range (this may differ from ``range`` if there were fragments +left on either side), and return ``ResOK``. + +.. c:function:: void FreelistIterate(Freelist fl, FreelistIterateMethod iterate, void *closureP, Size closureS) + +:mps:tag:`function.iterate` Iterate all isolated contiguous ranges in the +free list ``fl`` in address order, calling ``iterate`` for each one. +See :c:type:`FreelistIterateMethod` for details. + +.. c:function:: Bool FreelistFindFirst(Range rangeReturn, Range oldRangeReturn, Freelist fl, Size size, FindDelete findDelete) + +:mps:tag:`function.find.first` Locate the first isolated contiguous range in +address order, within the free list ``fl``, of at least ``size`` +bytes, update ``rangeReturn`` to that range, and return :c:macro:`TRUE`. If +there is no such continuous range, return :c:macro:`FALSE`. + +In addition, optionally delete the found range from the free list, +depending on the ``findDelete`` argument. This saves a separate call +to :c:func:`FreelistDelete()`, and uses the knowledge of exactly where we +found the range. The value of ``findDelete`` must come from this +enumeration:: + + enum { + FindDeleteNONE, /* don't delete after finding */ + FindDeleteLOW, /* delete size bytes from low end of block */ + FindDeleteHIGH, /* delete size bytes from high end of block */ + FindDeleteENTIRE /* delete entire range */ + }; + +The original contiguous isolated range in which the range was found is +returned via the ``oldRangeReturn`` argument. (If ``findDelete`` is +``FindDeleteNONE`` or ``FindDeleteENTIRE``, then this will be +identical to the range returned via the ``rangeReturn`` argument.) + +.. c:function:: Bool FreelistFindLast(Range rangeReturn, Range oldRangeReturn, Freelist fl, Size size, FindDelete findDelete) + +:mps:tag:`function.find.last` Like :c:func:`FreelistFindFirst()`, except that it +finds the last block in address order. + +.. c:function:: Bool FreelistFindLargest(Range rangeReturn, Range oldRangeReturn, Freelist fl, Size, size, FindDelete findDelete) + +:mps:tag:`function.find.largest` Locate the largest block within the free +list ``fl``, and if that block is at least as big as ``size``, return +its range via the ``rangeReturn`` argument, and return :c:macro:`TRUE`. If +there are no blocks in the free list at least as large as ``size``, +return :c:macro:`FALSE`. Pass 0 for ``size`` if you want the largest block +unconditionally. + +Like :c:func:`FreelistFindFirst()`, optionally delete the range from the +free list. (Always the whole range: specifying ``FindDeleteLOW`` or +``FindDeleteHIGH`` has the same effect as ``FindDeleteENTIRE``). + +.. c:function:: void FreelistFlushToCBS(Freelist fl, CBS cbs) + +Remove free address ranges from the free list ``fl`` and add them to +the Coalescing Block Structure ``cbs``. Continue until a call to +:c:func:`CBSInsert()` fails, or until the free list is empty, whichever +happens first. + +.. c:function:: Res FreelistDescribe(Freelist fl, mps_lib_FILE *stream) + +:mps:tag:`function.describe` Print a textual representation of the free +list ``fl`` to the given stream, indicating the contiguous ranges in +order. It is provided for debugging purposes only. + + + +Implementation +-------------- + +:mps:tag:`impl.list` The isolated contiguous free address ranges are kept on +an address-ordered singly linked free list. (As in traditional +:c:func:`malloc()` implementations.) + +:mps:tag:`impl.block` If the free address range is large enough to contain +an inline block descriptor consisting of two pointers, then the two +pointers stored are to the next free range in address order (or +:c:macro:`NULL` if there are no more ranges), and to the limit of current +free address range, in that order. + +:mps:tag:`impl.grain` Otherwise, the free address range must be large enough +to contain a single pointer. The pointer stored is to the next free +range in address order, or :c:macro:`NULL` if there are no more ranges. + +:mps:tag:`impl.tag` Grains and blocks are distinguished by a one-bit tag in +the low bit of the first word (the one containing the pointer to the +next range). Grains have this bit set; blocks have this bit reset. + +:mps:tag:`impl.invariant` The ranges stored in the free list are *isolated*: +no two ranges are adjacent or overlapping. + +:mps:tag:`impl.merge` When a free address range is added to the free list, +it is merged with adjacent ranges so as to maintain +:mps:ref:`.impl.invariant`. + +:mps:tag:`impl.rule.break` The use of :c:macro:`NULL` to mark the end of the list +violates the rule that exceptional values should not be used to +distinguish exeptional situations. This infraction allows the +implementation to meet :mps:ref:`.req.zero-overhead`. (There are other ways to +do this, such as using another tag to indicate the last block in the +list, but these would be more complicated.) + + +Opportunities for improvement +----------------------------- + +:mps:tag:`improve.length` When iterating over the list, we could check that +the number of elements visited in the course of the iteration does not +exceed the recorded size of the list. + +:mps:tag:`improve.maxsize` We could maintain the maximum size of any range +on the list, and use that to make an early exit from +:c:func:`FreelistFindLargest()`. It's not clear that this would actually be +an improvement. + + + diff --git a/mps/manual/html/_sources/design/index.txt b/mps/manual/html/_sources/design/index.txt index a0c98237228..3cf6719ac74 100644 --- a/mps/manual/html/_sources/design/index.txt +++ b/mps/manual/html/_sources/design/index.txt @@ -6,10 +6,14 @@ Design .. toctree:: :numbered: + abq + cbs config critical-path + freelist guide.hex.trans guide.impl.c.format keyword-arguments + range ring sig diff --git a/mps/manual/html/_sources/design/poolmvff.txt b/mps/manual/html/_sources/design/poolmvff.txt index ee4c005675c..c01308cf2f5 100644 --- a/mps/manual/html/_sources/design/poolmvff.txt +++ b/mps/manual/html/_sources/design/poolmvff.txt @@ -120,9 +120,10 @@ Implementation -------------- :mps:tag:`impl.free-list` The pool stores its free list in a CBS (see -`design.mps.cbs `_). It uses the CBS's mayUseInline facility to -avoid running out of memory to store the free list. This is the reason -for the alignment restriction above. +//gdr-peewit/info.ravenbrook.com/project/mps/branch/2013-05-17/emergency/design/poolmvff.txt +`design.mps.cbs `_), failing over in emergencies to a Freelist +(see design.mps.freelist) when the CBS cannot allocate new control +structures. This is the reason for the alignment restriction above. Details diff --git a/mps/manual/html/_sources/design/poolmvt.txt b/mps/manual/html/_sources/design/poolmvt.txt new file mode 100644 index 00000000000..32bb4ef900d --- /dev/null +++ b/mps/manual/html/_sources/design/poolmvt.txt @@ -0,0 +1,952 @@ +.. _design-poolmvt: + + + +Manual Variable Temporal (MVT) pool design +========================================== + +.. mps:prefix:: design.mps.poolmvt + + +Introduction +------------ + +:mps:tag:`intro` This is a second-generation design for a pool that manually +manages variable-sized objects. It is intended as a replacement for +poolmv (except in its control pool role) and poolepdl, and it is +intended to satisfy the requirements of the Dylan "misc" pool and the +product malloc/new drop-in replacement. + +:mps:tag:`readership` MM developers + +:mps:tag:`source` req.dylan(6), req.epcore(16), req.product(2) + +:mps:tag:`background` design.mps.poolmv(0), design.mps.poolepdl(0), +design.product.soft.drop(0), paper.wil95(1), paper.vo96(0), +paper.grun92(1), paper.beck82(0), mail.ptw.1998-02-25.22-18(0) + + +Definitions +----------- + +:mps:tag:`def.alignment` Alignment is a constraint on an object's address, +typically to be a power of 2 (see also, glossary.alignment ) + +:mps:tag:`def.bit-map` A bitmap is a boolean-valued vector (see also, +glossary.bitmap ). + +:mps:tag:`def.block` A block is a contiguous extent of memory. In this +document, block is used to mean a contiguous extent of memory managed +by the pool for the pool client, typically a subset of a segment +(compare with :mps:ref:`.def.segment`). + +:mps:tag:`def.cartesian-tree` A cartesian tree is a binary tree ordered by +two keys (paper.stephenson83(0)). + +:mps:tag:`def.crossing-map` A mechanism that supports finding the start of +an object from any address within the object, typically only required +on untagged architectures (see also, glossary.crossing.map ). + +:mps:tag:`def.footer` A block of descriptive information describing and +immediately following another block of memory (see also +:mps:ref:`.def.header`). + +:mps:tag:`def.fragmentation` Fragmented memory is memory reserved to the +program but not usable by the program because of the arrangement of +memory already in use (see also, glossary.fragmentation ). + +:mps:tag:`def.header` A block of descriptive information describing and +immediately preceding another block of memory (see also, +glossary.in-band.header ). + +:mps:tag:`def.in-band` From "in band signalling", when descriptive +information about a data structure is stored in the data structure +itself (see also, glossary.in-band.header ). + +:mps:tag:`def.out-of-band` When descriptive information about a data +structure is stored separately from the structure itself (see also, +glossary.out-of-band.header ). + +:mps:tag:`def.refcount` A refcount is a count of the number of users of an +object (see also, glossary.reference.count ). + +:mps:tag:`def.segment` A segment is a contiguous extent of memory. In this +document, segment is used to mean a contiguous extent of memory +managed by the MPS arena (design.mps.arena(1)) and subdivided by the +pool to provide blocks (see :mps:ref:`.def.block`) to its clients. + +:mps:tag:`def.splay-tree` A splay tree is a self-adjusting binary tree +(paper.st85(0), paper.sleator96(0)). + +:mps:tag:`def.splinter` A splinter is a fragment of memory that is too small +to be useful (see also, glossary.splinter ) + +:mps:tag:`def.subblock` A subblock is a contiguous extent of memory. In this +document, subblock is used to mean a contiguous extent of memory +manage by the client for its own use, typically a subset of a block +(compare with :mps:ref:`.def.block`). + + +Abbreviations +------------- + +:mps:tag:`abbr.abq` ABQ = Available Block Queue + +:mps:tag:`abbr.ap` AP = Allocation Point + +:mps:tag:`abbr.cbs` CBS = Coalescing Block Structure + +:mps:tag:`abbr.mps` MPS = Memory Pool System + +:mps:tag:`abbr.mv` MV = Manual-Variable + +:mps:tag:`abbr.ps` PS = PostScript + + + +Overview +-------- + +:mps:tag:`overview` MVT is intended to satisfy the requirements of the +clients that need manual-variable pools, improving on the performance +of the existing manual-variable pool implementations, and reducing the +duplication of code that currently exists. The expected clients of MVT +are: Dylan (currently for its misc pool), EP (particularly the dl +pool, but all pools other than the PS object pool), and Product +(initially the malloc/new pool, but also other manual pool classes). + + +Requirements +------------ + +:mps:tag:`req.cat` Requirements are categorized per guide.req(2). + +:mps:tag:`req.risk` req.epcore(16) is known to be obsolete, but the revised +document has not yet been accepted. + + +Critical requirements +..................... + +:mps:tag:`req.fun.man-var` The pool class must support manual allocation and +freeing of variable-sized blocks (source: req.dylan.fun.misc.alloc, +req.epcore.fun.{dl,gen,tmp,stat,cache,trap}.{alloc,free}, +req.product.fun.{malloc,new,man.man}). + +:mps:tag:`non-req.fun.gc` There is not a requirement that the pool class +support formatted objects, scanning, or collection objects; but it +should not be arbitrarily precluded. + +:mps:tag:`req.fun.align` The pool class must support aligned allocations to +client-specified alignments. An individual instance need only support +a single alignment; multiple instances may be used to support more +than one alignment (source: req.epcore.attr.align). + +:mps:tag:`req.fun.reallocate` The pool class must support resizing of +allocated blocks (source req.epcore.fun.dl.promise.free, +req.product.dc.env.{ansi-c,cpp}). + +:mps:tag:`non-req.fun.reallocate.in-place` There is not a requirement blocks +must be resized in place (where possible); but it seems like a good +idea. + +:mps:tag:`req.fun.thread` Each instance of the pool class must support +multiple threads of allocation (source req.epcore.fun.dl.multi, +req.product.dc.env.{ansi-c,cpp}). + +:mps:tag:`req.attr.performance` The pool class must meet or exceed +performance of "competitive" allocators (source: +rec.epcore.attr.{run-time,tp}, req.product.attr.{mkt.eval, perform}). +[Dylan does not seem to have any requirement that storage be allocated +with a particular response time or throughput, just so long as we +don't block for too long. Clearly there is a missing requirement.] + +:mps:tag:`req.attr.performance.time` By inference, the time overhead must be +competetive. + +:mps:tag:`req.attr.performance.space` By inference, the space overhead must +be competetive. + +:mps:tag:`req.attr.reliability` The pool class must have "rock-solid +reliability" (source: req.dylan.attr.rel.mtbf, req.epcore.attr.rel, +req.product.attr.rel). + +:mps:tag:`req.fun.range` The pool class must be able to manage blocks +ranging in size from 1 byte to all of addressable memory +(req.epcore.attr.{dl,gen,tmp,stat,cache,trap}.obj.{min,max}. The range +requirement may be satisfied by multiple instances each managing a +particular client-specified subrange of sizes. [Dylan has requirements +req.dylan.attr.{capacity,obj.max}, but no requirement that such +objects reside in a manual pool.] + +:mps:tag:`req.fun.debug` The pool class must support debugging erroneous +usage by client programs (source: req.epcore.fun.{dc.variety, +debug.support}, req.product.attr.{mkt.eval,perform}). Debugging is +permitted to incur additional overhead. + +:mps:tag:`req.fun.debug.boundaries` The pool class must support checking for +accesses outside the boundaries of live objects. + +:mps:tag:`req.fun.debug.log` The pool class must support logging of all +allocations and deallocations. + +:mps:tag:`req.fun.debug.enumerate` The pool class must support examining all +allocated objects. + +:mps:tag:`req.fun.debug.free` The pool class must support detecting +incorrect, overlapping, and double frees. + +:mps:tag:`req.fun.tolerant` The pool class must support tolerance of +erroneous usage (source req.product.attr.use.level.1). + + +Essential requirements +...................... + +:mps:tag:`req.fun.profile` The pool class should support memory usage +profiling (source: req.product.attr.{mkt.eval, perform}). + +:mps:tag:`req.attr.flex` The pool class should be flexible so that it can be +tuned to specific allocation and freeing patterns (source: +req.product.attr.flex,req.epcore.attr.{dl,cache,trap}.typ). The +flexibility requirement may be satisfied by multiple instances each +optimizing a specific pattern. + +:mps:tag:`req.attr.adapt` The pool class should be adaptive so that it can +accommodate changing allocation and freeing patterns (source: +req.epcore.fun.{tmp,stat}.policy, +req.product.attr.{mkt.eval,perform}). + + +Nice requirements +................. + +:mps:tag:`req.fun.suballocate` The pool class may support freeing of any +aligned, contiguous subset of an allocated block (source +req.epcore.fun.dl.free.any, req.product.attr.{mkt.eval,perform}). + + +Architecture +------------ + +:mps:tag:`arch.overview` The pool has several layers: client allocation is +by Allocation Points (APs). + +:mps:tag:`arch.overview.ap` APs acquire storage from the pool +available-block queue (ABQ). + +:mps:tag:`arch.overview.abq` The ABQ holds blocks of a minimum configurable +size: "reuse size". + +:mps:tag:`arch.overview.storage` The ABQ acquires storage from the arena, +and from its internal free block managers. + +:mps:tag:`arch.overview.storage.contiguous` The arena storage is requested +to be contiguous to maximize opportunities for coalescing (Loci will +be used when available). + +:mps:tag:`arch.overview.cbs` The free block managers hold blocks freed by +the client until, through coalescing, they have reached the reuse +size, at which point they are made available on the ABQ. + +:mps:tag:`arch.ap` The pool will use allocation points as the allocation +interface to the client. + +:mps:tag:`arch.ap.two-phase` Allocation points will request blocks from the +pool and suballocate those blocks (using the existing AP, compare and +increment, 2-phase mechanism) to satisfy client requests. + +:mps:tag:`arch.ap.fill` The pool will have a configurable "fill size" that +will be the preferred size block used to fill the allocation point. + +:mps:tag:`arch.ap.fill.size` The fill size should be chosen to amortize the +cost of refill over a number of typical reserve/commit operations, but +not so large as to exceed the typical object population of the pool. + +:mps:tag:`arch.ap.no-fit` When an allocation does not fit in the remaining +space of the allocation point, there may be a remaining fragment. + +:mps:tag:`arch.ap.no-fit.sawdust` If the fragment is below a configurable +threshold (minimum size), it will be left unused (but returned to the +free block managers so it will be reclaimed when adjacent objects are +freed). + +:mps:tag:`arch.ap.no-fit.splinter` otherwise, the remaining fragment will be +(effectively) returned to the head of the available-block queue, so +that it will be used as soon as possible (that is, by objects of similar +birthdate). + +:mps:tag:`arch.ap.no-fit.oversize` If the requested allocation exceeds the +fill size it is treated exceptionally (this may indicate the client +has either misconfigured or misused the pool and should either change +the pool configuration or create a separate pool for these exceptional +objects for best performance). + +:mps:tag:`arch.ap.no-fit.oversize.policy` Oversize blocks are assumed to +have exceptional lifetimes, hence are allocated to one side and do not +participate in the normal storage recycling of the pool. + +:mps:tag:`arch.ap.refill.overhead` If reuse size is small, or becomes small +due to :mps:ref:`.arch.adapt`, all allocations will effectively be treated +exceptionally (the AP will trip and a oldest-fit block will be chosen +on each allocation). This mode will be within a constant factor in +overhead of an unbuffered pool. + +:mps:tag:`arch.abq` The available block queue holds blocks that have +coalesced sufficiently to reach reuse size. + +:mps:tag:`arch.abq.reuse.size` A multiple of the quantum of virtual memory +is used as the reuse size (:mps:ref:`.anal.policy.size`). + +:mps:tag:`arch.abq.fifo` It is a FIFO queue (recently coalesced blocks go to +the tail of the queue, blocks are taken from the head of the queue for +reuse). + +:mps:tag:`arch.abq.delay-reuse` By thus delaying reuse, coalescing +opportunities are greater. + +:mps:tag:`arch.abq.high-water` It has a configurable high water mark, which +when reached will cause blocks at the head of the queue to be returned +to the arena, rather than reused. + +:mps:tag:`arch.abq.return` When the MPS supports it, the pool will be able +to return free blocks from the ABQ to the arena on demand. + +:mps:tag:`arch.return.segment` arch.abq.return can be guaranteed to be able +to return a segment by setting reuse size to twice the size of the +segments the pool requests from the arena. + +:mps:tag:`arch.cbs` The coalescing block structure holds blocks that have +been freed by the client. + +:mps:tag:`arch.cbs.optimize` The data structure is optimized for coalescing. + +:mps:tag:`arch.cbs.abq` When a block reaches reuse size, it is added to the +ABQ. + +:mps:tag:`arch.cbs.data-structure` The data structures are organized so that +a block can be both in the free block managers and on the ABQ +simultaneously to permit additional coalescing, up until the time the +block is removed from the ABQ and assigned to an AP. + +:mps:tag:`arch.fragmentation.internal` Internal fragmentation results from +The pool will request large segments from the arena to minimize the +internal fragmentation due to objects not crossing segment boundaries. + +:mps:tag:`arch.modular` The architecture will be modular, to allow building +variations on the pool by assembling different parts. + +:mps:tag:`arch.modular.example` For example, it should be possible to build +pools with any of the freelist mechanisms, with in-band or out-of-band +storage (where applicable), that do or do not support derived object +descriptions, etc. + +:mps:tag:`arch.modular.initial` The initial architecture will use +:mps:ref:`.sol.mech.free-list` for the free block managers, +:mps:ref:`.sol.mech.storage.out-of-band`, :mps:ref:`.sol.mech.desc.derived`, and +:mps:ref:`.sol.mech.allocate.buffer`. + +:mps:tag:`arch.segregate` The architecture will support segregated +allocation through the use of multiple allocation points. The client +will choose the appropriate allocation point either at run time, or +when possible, at compile time. + +:mps:tag:`arch.segregate.initial` The initial architecture will segregate +allocations into two classes: large and small. This will be +implemented by creating two pools with different parameters. + +:mps:tag:`arch.segregate.initial.choice` The initial architecture will +provide glue code to choose which pool to allocate from at run time. +If possible this glue code will be written in a way that a good +compiler can optimize the selection of pool at compile time. +Eventually this glue code should be subsumed by the client or +generated automatically by a tool. + +:mps:tag:`arch.debug` Debugging features such as tags, fenceposts, types, +creators will be implemented in a layer above the pool and APs. A +generic pool debugging interface will be developed to support +debugging in this outer layer. + +:mps:tag:`arch.debug.initial` The initial architecture will have counters +for objects/bytes allocated/freed and support for detecting +overlapping frees. + +:mps:tag:`arch.dependency.loci` The architecture depends on the arena being +able to efficiently provide segments of varying sizes without +excessive fragmentation. The locus mechanism should satisfy this +dependency. (See :mps:ref:`.anal.strategy.risk`.) + +:mps:tag:`arch.dependency.mfs` The architecture internal data structures +depend on efficient manual management of small, fixed-sized objects (2 +different sizes). The MFS pool should satisfy this dependency. + +:mps:tag:`arch.contingency` Since the strategy we propose is new, it may not +work. + +:mps:tag:`arch.contingency.pathological` In particular, pathological +allocation patterns could result in fragmentation such that no blocks +recycle from the free bock managers to the ABQ. + +:mps:tag:`arch.contingency.fallback` As a fallback, there will be a pool +creation parameter for a high water mark for the free space. + +:mps:tag:`arch.contingency.fragmentation-limit` When the free space as a +percentage of all the memory managed by the pool (a measure of +fragmentation) reaches that high water mark, the free block managers +will be searched oldest-fit before requesting additional segments from +the arena. + +:mps:tag:`arch.contingency.alternative` We also plan to implement +:mps:ref:`.mech.free-list.cartesian-tree` as an alternative free block manager, +which would permit more efficient searching of the free blocks. + +:mps:tag:`arch.parameters` The architecture supports several parameters so +that multiple pools may be instantiated and tuned to support different +object cohorts. The important parameters are: reuse size, minimum +size, fill size, ABQ high water mark, free block fragmentation limit +(see :mps:ref:`.arch.contingency.fragmentation-limit`). + +:mps:tag:`arch.parameters.client-visible` The client-visible parameters of +the pool are the minimum object size, the mean object size, the +maximum object size, the reserve depth and fragmentation limit. The +minimum object size determines when a splinter is kept on the head of +the ABQ (:mps:ref:`.arch.ap.no-fit.splinter`). The maximum object size +determines the fill size (:mps:ref:`.arch.ap.fill-size`) and hence when a +block is allocated exceptionally (:mps:ref:`.arch.ap.no-fit.oversize`). The +mean object size is the most likely object size. The reserve depth is +a measure of the hysteresis of the object population. The mean object +size, reserve depth and, maximum object size are used to determine the +size of the ABQ (:mps:ref:`.arch.abq.high-water`). The fragmentation limit is +used to determine when contingency mode is used to satisfy an +allocation request (:mps:ref:`.arch.contingency`). + +:mps:tag:`arch.adapt` We believe that an important adaptation to explore is +tying the reuse size inversely to the fragmentation (as measured in +:mps:ref:`.arch.contingency.fragmentation-limit`). + +:mps:tag:`arch.adapt.reuse` By setting reuse size low when fragmentation is +high, smaller blocks will be available for reuse, so fragmentation +should diminish. + +:mps:tag:`arch.adapt.overhead` This will result in higher overhead as the AP +will need to be refilled more often, so reuse size should be raised +again as fragmentation diminishes. + +:mps:tag:`arch.adapt.oldest-fit` In the limit, if reuse size goes to zero, +the pool will implement a "oldest-fit" policy: the oldest free block +of sufficient size will be used for each allocation. + +:mps:tag:`arch.adapt.risk` This adaptation is an experimental policy and +should not be delivered to clients until thoroughly tested. + + +Analysis +-------- + +:mps:tag:`anal.discard` We have discarded many traditional solutions based +on experience and analysis in paper.wil95(1). In particular, managing +the free list as a linear list arranged by address or size and basing +policy on searching such a linear list in a particular direction, from +a particular starting point, using fit and/or immediacy as criteria. +We believe that none of these solutions is derived from considering +the root of the problem to be solved (as described in +:mps:ref:`.anal.strategy`), although their behavior as analyzed by Wilson +gives several insights. + +:mps:tag:`anal.strategy` For any program to run in the minimum required +memory (with minimal overhead -- we discard solutions such as +compression for now), fragmentation must be eliminated. To eliminate +fragmentation, simply place blocks in memory so that they die "in +order" and can be immediately coalesced. This ideal is not achievable, +but we believe we can find object attributes that correlate with +deathtime and exploit them to approximate the ideal. Initially we +believe birth time and type (as approximated by size) will be useful +attributes to explore. + +:mps:tag:`anal.strategy.perform` To meet :mps:ref:`.req.attr.performance`, the +implementation of :mps:ref:`.sol.strategy` must be competitive in both time +and space. + +:mps:tag:`anal.strategy.risk` The current MPS segment substrate can cause +internal fragmentation which an individual pool can do nothing about. +We expect that `request.epcore.170193.sugg.loci`_ will be implemented to +remove this risk. + +.. _`request.epcore.170193.sugg.loci`: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/epcore/170193/ + +:mps:tag:`anal.policy` Deferred coalescing, when taken to the extreme will +not minimize the memory consumption of a program, as no memory would +ever be reused. Eager reuse appears to lead to more fragmentation, +whereas delayed reuse appears to reduce fragmentation +(paper.wil95(1)). The systems studied by Wilson did not directly +address deferring reuse. Our proposed policy is to reuse blocks when +they reach a (configurable) size. We believe that this policy along +with the policy of segregating allocations by death time, will greatly +reduce fragmentation. + +:mps:tag:`anal.policy.risk` This policy could lead to pathological behavior +if allocations cannot be successfully segregated. + +:mps:tag:`anal.policy.allocate.segregate` This policy has some similarities +to CustomAlloc (paper.grun92(1)). CustomAlloc segregates objects by +size classes, and then within those classes chooses a different +allocator depending on whether that size class has a stable or +unstable population. Classes with stable population recycle storage +within the class, whereas classes with unstable populations return +their storage to the general allocation pool for possible reuse by +another class. CustomAlloc, however, requires profiling the +application and tuning the allocator according to those profiles. +Although we intend to support such tuning, we do not want to require +it. + +:mps:tag:`anal.policy.reallocate` For reallocation, :mps:ref:`.fun.suballocate` can +be used to free the remainder if a block is made smaller. Doing so +will cause the freed block to obey :mps:ref:`.sol.policy.allocate` (that is, +the freed block will not be treated specially, it will be subject to +the normal policy on reuse). Copying can be used if a block is made +larger. paper.vo96(0) reports success in over-allocating a block the +first time it is resized larger, presumably because blocks that are +resized once tend to be resized again and over-allocating may avoid a +subsequent copy. If each object that will be reallocated can be given +its own allocation point until its final reallocation, the allocation +point can be used to hold released or spare storage. + +:mps:tag:`anal.policy.size` We believe that this will take advantage of the +underlying virtual memory system's ability to compact the physical +memory footprint of the program by discarding free fragments that +align with the virtual memory quantum. (In a VM system one can +approximate compaction by sparse mapping. If every other page of a +segment is unused, the unused pages can be unmapped, freeing up +physical memory that can be mapped to a new contiguous vm range.) + +:mps:tag:`anal.mech.free-list` The literature (paper.grun92(1), +paper.vo96(0)) indicate that :mps:ref:`.sol.mech.free-list.cartesian-tree` +provides a space-efficient implementation at some cost in speed. +:mps:ref:`.sol.mech.free-list.splay-tree` is faster but less space-efficient. +:mps:ref:`.sol.mech.free-list.bitmap` is unstudied. Many of the faster +allocators maintain caches of free blocks by size to speed allocation +of "popular" sizes. We intend to initially explore not doing so, as we +believe that policy ultimately leads to fragmentation by mixing +objects of varying death times. Instead we intend to use a free list +mechanism to support fast coalescing, deferring reuse of blocks until +a minimum size has been reached. + +:mps:tag:`anal.mech.allocate.optimize-small` Wilson (paper.wil95(1)) notes +that small blocks typically have short lifetimes and that overall +performance is improved if you optimize the management of small +blocks, e.g., :mps:ref:`.sol.mech.allocate.lookup-table` for all small blocks. +We believe that :mps:ref:`.sol.mech.allocate.buffer` does exactly that. + +:mps:tag:`anal.mech.allocate.optimize-new` Wilson (paper.wil95(1)) reports +some benefit from "preserving wilderness", that is, when a block of +memory must be requested from the system to satisfy an allocation, +only the minimum amount of that block is used, the remainder is +preserved (effectively by putting it at the tail of the free list). +This mechanism may or may not implement :mps:ref:`.sol.policy.allocate`. We +believe a better mechanism is to choose to preserve or not, based on +:mps:ref:`.sol.policy.allocate`. + + +Ideas +----- + +:mps:tag:`sol` Many solution ideas for manual management of variable-sized +memory blocks are enumerated by paper.wil95(1). Here we list the most +promising, and some of our own. + + +Strategy +........ + +:mps:tag:`sol.strategy` To run a program in the minimal required memory, +with minimal overhead, utilize memory efficiently. Memory becomes +unusable when fragmented. Strategy is to minimize fragmentation. So +place blocks where they won't cause fragmentation later. + +:mps:tag:`sol.strategy.death` Objects that will die together (in time) +should be allocated together (in space); thus they will coalesce, +reducing fragmentation. + +:mps:tag:`sol.strategy.death.birth` Assume objects allocated near each other +in time will have similar deathtimes (paper.beck82(0)). + +:mps:tag:`sol.strategy.death.type` Assume objects of different type may have +different deathtimes, even if born together. + +:mps:tag:`sol.strategy.death.predict` Find and use program features to predict deathtimes. + +:mps:tag:`sol.strategy.reallocate` Reallocation implies rebirth, or at least +a change in lifetime + +:mps:tag:`sol.strategy.debug` As much of the debugging functionality as +possible should be implemented as a generally available MPS utility; +the pool will provide support for debugging that would be expensive or +impossible to allocate outside the pool. + + +Policy +...... + +Policy is an implementable decision procedure, hopefully approximating +the strategy. + +:mps:tag:`sol.policy.reuse` Defer reusing blocks, to encourage coalescing. + +:mps:tag:`sol.policy.split` When a block is split to satisfy an allocation, +use the remainder as soon as possible. + +:mps:tag:`sol.policy.size` Prevent :mps:ref:`.policy.reuse` from consuming all of +memory by choosing a (coalesced) block for reuse when it reaches a +minimum size. + +:mps:tag:`sol.policy.size.fixed` Use the quantum of virtual memory (e.g., +one page) as minimum size. + +:mps:tag:`sol.policy.size.tune` Allow tuning minimum size. + +:mps:tag:`sol.policy.size.adapt` Adaptively change minimum size. + +:mps:tag:`sol.policy.allocate` Allocate objects with similar birthdate and +lifetime together. + +:mps:tag:`sol.policy.allocate.segregate` Segregate allocations by type. + +:mps:tag:`sol.policy.allocate.segregate.size` Use size as a substitute for type. + +:mps:tag:`sol.policy.allocate.segregate.tune` Permit tuning of segregation. + +:mps:tag:`sol.policy.allocate.segregate.adapt` Adaptively segregate allocations. + +:mps:tag:`sol.policy.reallocate` Implement reallocation in a central +mechanism outside of the pool, create a generic pool interface in +support of same. + +:mps:tag:`sol.policy.debug` Implement a pool debugging interface. + +:mps:tag:`sol.policy.debug.counters` Implement debugging counters in the +pool that are queried with a generic interface. + +:mps:tag:`sol.policy.debug.verify` Implement debugging error returns on +overlapping frees. + + +Mechanism +......... + +Mechanisms are algorithms or data structures used to implement policy. + +:mps:tag:`sol.mech.free-list` Mechanisms that can be used to describe the +free list. + +:mps:tag:`sol.mech.free-list.cartesian-tree` Using address and size as keys +supports fast coalescing of adjacent blocks and fast searching for +optimal-sized blocks. Unfortunately, because the shape of the tree is +constrained by the second key, it can become unbalanced. This data +structure is used in the SunOS 4.1 malloc (paper.grun92(1)). + +:mps:tag:`sol.mech.free-list.splay-tree` The amortized cost of a splay tree +is competitive with balanced binary trees in the worst case, but can +be significantly better for regular patterns of access because +recently-accessed keys are moved to the root of the tree and hence can +be re-accessed quickly. This data structure is used in the System Vr4 +malloc (paper.vo96(0)). (For a complete analysis of the splay tree +algorithm time bounds see paper.st85(0).) + +:mps:tag:`sol.mech.free-list.bit-map` Using address as an index and +fix-sized blocks, the booleans can represent whether a block is free +or not. Adjacent blocks can be used to construct larger blocks. +Efficient algorithms for searching for runs in a vector are known. +This data structure is used in many file system disk block managers. + +:mps:tag:`sol.mech.free-list.refcount` A count of the number of allocated +but not freed subblocks of a block can be used to determine when a +block is available for reuse. This is an extremely compact data +structure, but does not support subblock reuse. + +:mps:tag:`sol.mech.free-list.hybrid` Bitmaps appear suited particularly to +managing small, contiguous blocks. The tree structures appear suited +particularly to managing varying-sized, discontiguous blocks. A +refcount can be very efficient if objects can be placed accurately +according to death time. A hybrid mechanism may offer better +performance for a wider range of situations. + +:mps:tag:`sol.mech.free-list.linked` An address-ordered singly linked free +list using space in each free block to store the block's size and a +pointer to the next block. + +:mps:tag:`sol.mech.storage` Methods that can be used to store the free list description. + +:mps:tag:`sol.mech.storage.in-band` The tree data structures (and +:mps:ref:`.sol.mech.free-list.linked`) are amenable to being stored in the +free blocks themselves, minimizing the space overhead of management. +To do so imposes a minimum size on free blocks and reduces the +locality of the data structure. + +:mps:tag:`sol.mech.storage.out-of-band` The bit-map data structure must be +stored separately. + +:mps:tag:`sol.mech.desc` for an allocated block to be freed, its base and +bound must be known + +:mps:tag:`sol.mech.desc.derived` Most clients can supply the base of the +block. Some clients can supply the bound. + +:mps:tag:`sol.mech.desc.in-band` When the bound cannot be supplied, it can +be stored as an in-band "header". If neither the base nor bound can be +supplied (e.g., the client may only have an interior pointer to the +block), a header and footer may be required. + +:mps:tag:`sol.mech.desc.out-of-band` In un-tagged architectures, it may be +necessary to store the header and footer out-of-band to distinguish +them from client data. Out-of-band storage can improve locality and +reliability. Any of the free-list structures can also be used to +describe allocated blocks out-of-band. + +:mps:tag:`sol.mech.desc.crossing-map` An alternative for untagged +architectures is to store a "crossing map" which records an encoding +of the start of objects and then store the descriptive information +in-band. + +:mps:tag:`sol.mech.allocate` Mechanisms that can be used to allocate blocks +(these typically sit on top of a more general free-list manager). + +:mps:tag:`sol.mech.allocate.lookup-table` Use a table of popular sizes to +cache free blocks of those sizes. + +:mps:tag:`sol.mech.allocate.buffer` Allocate from contiguous blocks using +compare and increment. + +:mps:tag:`sol.mech.allocate.optimize-small` Use a combination of techniques +to ensure the time spent managing a block is small relative to the +block's lifetime; assume small blocks typically have short lifetimes. + +:mps:tag:`sol.mech.allocate.optimize-new` When "virgin" memory is acquired +from the operating system to satisfy a request, try to preserve it +(that is, use only what is necessary). + +:mps:tag:`sol.mech.allocate.segregate.size` Use size as a substitute for +type. + +:mps:tag:`sol.mech.reallocate` use :mps:ref:`.req.fun.suballocate` to return unused +memory when a block shrinks, but differentiate this from an erroneous +overlapping free by using separate interfaces. + + + +Implementation +-------------- + +The implementation consists of the following separable modules: + + +Coalescing Block Structure +.......................... + +:mps:tag:`impl.c.cbs` The initial implementation will use +:mps:ref:`.sol.mech.free-list.splay-tree` and +:mps:ref:`.sol.mech.storage.out-of-band`. For locality, this storage should be +managed as a linked free list of splay nodes suballocated from blocks +acquired from a pool shared by all CBS's. Must support creation and +destruction of an empty tree. Must support search, insert and delete +by key of type Addr. Must support finding left and right neighbors of +a failed search for a key. Must support iterating over the elements of +the tree with reasonable efficiency. Must support storing and +retrieving a value of type Size associated with the key. Standard +checking and description should be provided. See design.mps.splay(0) +and design.mps.cbs(0). + + +Fail-over to address-ordered free list +...................................... + +:mps:tag:`impl.c.freelist` Because the CBS uses out-of-band storage, it may +be unable to handle insert (design.mps.cbs.function.cbs.insert.fail) +and delete (design.mps.cbs.function.cbs.delete.fail) operations. When +this happen MVT fails over to an address-ordered singly linked free +list. This uses in-band storage and so cannot run out of memory, but +it has much worse performance than the CBS. Therefore MVT eagerly +attempts to flush blocks from the free list back to the CBS. See +design.mps.freelist for the design and implementation of the free +list. + + +Available Block Queue +..................... + +:mps:tag:`impl.c.abq` The initial implementation will be a queue of fixed +size (determined at pool creation time from the high water mark). Must +support creation and destruction of an empty queue. Must support +insertion at the head or tail of the queue (failing if full), peeking +at the head of the queue, and removal of the head (failing if empty) +or any element of the queue (found by a search). Standard checking and +description should be provided. See design.mps.abq. + + +Pool implementation +................... + +:mps:tag:`impl.c` The initial implementation will use the above modules to +implement a buffered pool. Must support creation and destruction of +the pool. Creation takes parameters: minimum size, mean size, maximum +size, reserve depth and fragmentation limit. Minimum, mean, and +maximum size are used to calculate the internal fill and reuse sizes. +Reserve depth and mean size are used to calculate the ABQ high water +mark. Fragmentation limit is used to set the contingency mode. Must +support buffer initialization, filling and emptying. Must support +freeing. Standard checking and description should be provided. +[Eventually, it should support scanning, so it can be used with +collected pools, but no manual pool currently does.] + +:mps:tag:`impl.c.future` The implementation should not preclude "buffered +free" (mail.ptw.1997-12-05.19-07(0), ff.) being added in the future. + +:mps:tag:`impl.c.parameters` The pool parameters are calculated as follows +from the input parameters: minimum, mean, and maximum size are taked +directly from the parameters. + +:mps:tag:`impl.c.parameter.fill-size` The fill size is set to the maximum +size times the reciprocal of the fragmentation limit, aligned to the +arena alignment. + +:mps:tag:`imple.c.parameter.reuse-size` The reuse size is set to twice the +fill size (see :mps:ref:`.arch.abq.return.segment`, +:mps:ref:`.impl.c.free.merge.segment`). + +:mps:tag:`impl.c.parameter.abq-limit` The ABQ high-water limit is set to the +reserve depth times the mean size (that is, the queue should hold as +many reuse blocks as would take to cover the population hysteresis if +the population consisted solely of mean-sized blocks, see +:mps:ref:`.arch.abq.high-water`). + +:mps:tag:`impl.c.parameter.avail-limit` The free block high-water limit is +implemented by comparing the available free space to an "available +limit". The available limit is updated each time a segment is +allocated from or returned to the arena by setting it to the total +size of the pool times the fragmentation limit divide vy 100 (see +:mps:ref:`.arch.contingency.fallback`). + +:mps:tag:`impl.c.ap.fill` An AP fill request will be handled as follows: + +- If the request is larger than fill size, attempt to request a + segment from the arena sufficient to satisfy the request. + +- Use any previously returned splinter (from :mps:ref:`.impl.c.ap.empty`), if + large enough. + +- Attempt to retrieve a free block from the head of the ABQ (removing + it from ABQ and the free block managers if found). + +- If above fragmentation limit, attempt to find a block in the free + block managers, using oldest-fit search. + +- Attempt to request a segment of fill size from the arena. + +- Attempt to find a block in the free block managers, using oldest-fit + search. + +- Otherwise, fail. + +:mps:tag:`impl.c.ap.empty` An AP empty request will be handled as follows: + +- If remaining free is less than min size, return it to the free block + managers. + +- If the remaining free is larger than any previous splinter, return + that splinter to the free block managers and save this one for use + by a subsequent fill. + +- Otherwise return the remaining block to the free block managers. + +:mps:tag:`impl.c.free` When blocks are returned to the free block managers +they may be merged with adjacent blocks. If a merge occurs with a +block on the ABQ, the ABQ must be adjusted to reflect the merge. + +:mps:tag:`impl.c.free.exception` Exceptional blocks are returned directly to +the arena. + +:mps:tag:`impl.c.free.merge` If a merge occurs and the merged block is +larger than reuse size: + +- If the ABQ is full, remove the block at the head of the ABQ from the + ABQ and the free block managers and return it to the arena(*). + +- Insert the newly merged block at the tail of the ABQ, leaving it in + the free block managers for further merging. + +:mps:tag:`impl.c.free.merge.segment` (*) Merged blocks may not align with +arena segments. If necessary, return the interior segments of a block +to the arena and return the splinters to the free block managers. + +:mps:tag:`impl.c.free.merge.segment.reuse` If the reuse size (the size at +which blocks recycle from the free block managers to the ABQ) is at +least twice the fill size (the size of segments the pool allocates +from the arena), we can guarantee that there will always be a +returnable segment in every ABQ block. + +:mps:tag:`impl.c.free.merge.segment.overflow` If the reuse size is set +smaller (see :mps:ref:`.arch.adapt`), there may not be a returnable segment in +an ABQ block, in which case the ABQ has "overflowed". Whenever this +occurs, the ABQ will be refilled by searching the free block managers +for dropped reusable blocks when needed. + +:mps:tag:`impl.c.free.merge.segment.risk` The current segment structure does +not really support what we would like to do. Loci should do better: +support reserving contiguous address space and mapping/unmapping any +portion of that address space. + +:mps:tag:`impl.c.free.merge.alternative` Alternatively, if the MPS segment +substrate permitted mapping/unmapping of pages, the pool could use +very large segments and map/unmap pages as needed. + + +AP Dispatch +........... + +:mps:tag:`impl.c.multiap` The initial implementation will be a glue layer +that selects among several AP's for allocation according to the +predicted deathtime (as approximated by size) of the requested +allocation. Each AP will be filled from a pool instance tuned to the +range of object sizes expected to be allocated from that AP. [For +bonus points provide an interface that creates a batch of pools and +AP's according to some set of expected object sizes. Eventually expand +to understand object lifetimes and general lifetime prediction keys.] + +:mps:tag:`impl.c.multiap.sample-code` This glue code is not properly part of +the pool or MPS interface. It is a layer on top of the MPS interface, +intended as sample code for unsophisticated clients. Sophisticated +clients will likely want to choose among multiple AP's more directly. + + +Testing +------- + +:mps:tag:`test.component` Components :mps:ref:`.impl.c.splay`, :mps:ref:`.impl.c.cbs`, and +:mps:ref:`.impl.c.abq` will be subjected to individual component tests to +verify their functionality. + +:mps:tag:`test.regression` All tests applied to poolmv +(design.mps.poolmv(0)) and poolepdl (design.mps.poolepdl(0)) will be +applied to poolmvt to ensure that mvt is at least as functional as the +pools it is replacing. + +:mps:tag:`test.qa` Once poolmvt is integrated into the MPS, the standard MPS +QA tests will be applied to poolmvt prior to each release. + +:mps:tag:`test.customer` Customer acceptance tests will be performed on a +per-customer basis before release to that customer (cf. +proc.release.epcore(2).test) + + +Text +---- + +Possible tweaks (from mail.pekka.1998-04-15.13-10(0)): + +- Try to coalesce splinters returned from AP's with the front (or any) + block on the ABQ. + +- Sort ABQ in some other way to minimize splitting/splinters. For + example, proximity to recently allocated blocks. + + + diff --git a/mps/manual/html/_sources/design/range.txt b/mps/manual/html/_sources/design/range.txt new file mode 100644 index 00000000000..a681fd4d6c6 --- /dev/null +++ b/mps/manual/html/_sources/design/range.txt @@ -0,0 +1,87 @@ +.. _design-range: + + +Ranges +====== + +.. mps:prefix:: design.mps.range + + +Introduction +------------ + +:mps:tag:`intro` This is the design of the Range module, which implements +objects representing address ranges. + +_`readership`: This document is intended for any MPS developer. + + +Requirements +------------ + +_`.req.range` A range object must be able to represent an arbitrary +range of addresses that does not include the top grain of the address +space. + +_`.req.empty` A range object must be able to represent the empty +range. + +_`.req.stack-alloc` It must be possible to allocate range objects on +the stack: that is, they do not require any heap resource. + + +Interface +--------- + +.. c:type:: RangeStruct *Range + +``Range`` is the type of a range. It is an alias for ``RangeStruct *``. :c:type:`RangeStruct` is defined in the header so that it can be +inlined in client structures or allocated on the stack. Clients must +not depend on its implementation details. + +.. c:function:: void RangeInit(Range range, Addr base, Addr limit) + +Initialize a range object to represent the half-open address range +between ``base`` (inclusive) and ``limit`` (exclusive). It must be the +case that ``base <= limit``. If ``base == limit`` then the range is +empty. + +.. c:function:: void RangeFinish(Range range) + +Finish a range object. Because a range object uses no heap resources +(:mps:ref:`.req.stack-alloc`) it is not necessary to call this. However, +clients may wish to do so in order to ensure that the range object is +invalid. + +.. c:function:: Addr RangeBase(Range range) + +Return the base of the range. (This is implemented as a macro, but +there is a function too.) + +.. c:function:: Addr RangeLimit(Range range) + +Return the limit of the range. (This is implemented as a macro, but +there is a function too.) + +.. c:function:: Size RangeSize(Range range) + +Return the size of the range. (This is implemented as a macro, but +there is a function too. The macro evaluates its argument twice.) + +.. c:function:: Bool RangeIsAligned(Range range, Align alignment) + +Return :c:macro:`TRUE` if the base and limit of the range are both aligned to +the given alignment, or :c:macro:`FALSE` if either is not. + +.. c:function:: Bool RangesOverlap(Range range1, Range range2) + +Return :c:macro:`TRUE` if the two ranges overlap (have at least one address +in common), or :c:macro:`FALSE` if they do not. Note that ranges [*A*, *B*) and +[*B*, *C*) do not overlap. + +.. c:function:: Bool RangesNest(Range outer, Range inner) + +Return :c:macro:`TRUE` if all addresses in ``inner`` are also in ``outer``, +or :c:macro:`FALSE` otherwise. + + diff --git a/mps/manual/html/_sources/glossary/_Sidebar.txt b/mps/manual/html/_sources/glossary/_Sidebar.txt deleted file mode 100644 index e0e50826e07..00000000000 --- a/mps/manual/html/_sources/glossary/_Sidebar.txt +++ /dev/null @@ -1,2 +0,0 @@ -* `Ravenbrook `_ -* `Google `_ diff --git a/mps/manual/html/_sources/glossary/home.txt b/mps/manual/html/_sources/glossary/home.txt deleted file mode 100644 index bb55975bf97..00000000000 --- a/mps/manual/html/_sources/glossary/home.txt +++ /dev/null @@ -1,33 +0,0 @@ -.. _glossary: - -Memory Management Glossary -************************** - -.. include:: alphabet.txt - -.. toctree:: - :maxdepth: 1 - - a - b - c - d - e - f - g - h - i - k - l - m - n - o - p - q - r - s - t - u - v - w - z diff --git a/mps/manual/html/_sources/pool/intro.txt b/mps/manual/html/_sources/pool/intro.txt index 42ee7843376..2228a66c8de 100644 --- a/mps/manual/html/_sources/pool/intro.txt +++ b/mps/manual/html/_sources/pool/intro.txt @@ -101,7 +101,7 @@ May contain exact references? [4]_ yes --- yes yes --- May contain ambiguous references? [4]_ no --- no no --- --- --- --- --- no May contain weak references? [4]_ no --- no yes --- --- --- --- --- no Allocations fixed or variable in size? var var var var var fixed var var var var -Alignment? [5]_ conf conf conf conf conf [6]_ [6]_ [7]_ [6]_ conf +Alignment? [5]_ conf conf conf conf conf [6]_ [6]_ [7]_ [7]_ conf Dependent objects? [8]_ no --- no yes --- --- --- --- --- no May use remote references? [9]_ no --- no no --- --- --- --- --- no Blocks are automatically managed? [10]_ yes yes yes yes yes no no no no no @@ -137,12 +137,13 @@ Blocks may use :term:`in-band headers`? yes yes yes yes yes .. [5] "Alignment" is "conf" if the client program may specify :term:`alignment` for each pool. - .. [6] The alignment of blocks allocated from :ref:`pool-mv` and - :ref:`pool-mvt` pools is platform-dependent. + .. [6] The alignment of blocks allocated from :ref:`pool-mv` pools + is platform-dependent. - .. [7] :ref:`pool-mvff` pools have configurable alignment, but it - may not be smaller than the :term:`natural alignment` for - the :term:`platform` (see :c:macro:`MPS_PF_ALIGN`). + .. [7] :ref:`pool-mvt` and :ref:`pool-mvff` pools have + configurable alignment, but it may not be smaller than the + :term:`natural alignment` for the :term:`platform` (see + :c:macro:`MPS_PF_ALIGN`). .. [8] In pools with this property, each object may specify an :term:`dependent object` which the client program diff --git a/mps/manual/html/_sources/pool/mvt.txt b/mps/manual/html/_sources/pool/mvt.txt index 84192aa19a8..fd56d1a299c 100644 --- a/mps/manual/html/_sources/pool/mvt.txt +++ b/mps/manual/html/_sources/pool/mvt.txt @@ -113,7 +113,15 @@ MVT interface Temporal) :term:`pool`. When creating an MVT pool, :c:func:`mps_pool_create_k` may take - five :term:`keyword arguments`: + six :term:`keyword arguments`: + + * :c:macro:`MPS_KEY_ALIGN` (type :c:type:`mps_align_t`, default is + smallest general purpose alignment for the architecture) is the + :term:`alignment` of addresses for allocation (and freeing) in + the pool. If an unaligned size is passed to :c:func:`mps_alloc` or + :c:func:`mps_free`, it will be rounded up to the pool's alignment. + The minimum alignment supported by pools of this class is + ``sizeof(void *)``. * :c:macro:`MPS_KEY_MIN_SIZE` (type :c:type:`size_t`, default is smallest general purpose alignment for the architecture) is the @@ -130,9 +138,9 @@ MVT interface this; doing so will result in the storage of the block never being reused. - These three arguments are *hints* to the MPS: the pool will be - less efficient if they are wrong, but the only thing that will - break is the partial freeing of large blocks. + The three ``SIZE`` arguments above are *hints* to the MPS: the + pool will be less efficient if they are wrong, but the only thing + that will break is the partial freeing of large blocks. * :c:macro:`MPS_KEY_MVT_RESERVE_DEPTH` (type :c:type:`mps_count_t`) is the expected hysteresis of the diff --git a/mps/manual/html/_static/mps.css b/mps/manual/html/_static/mps.css index 17de19a0031..fa6521452fc 100644 --- a/mps/manual/html/_static/mps.css +++ b/mps/manual/html/_static/mps.css @@ -83,8 +83,11 @@ a.mpstag:hover { color: #FFFFFF; } +p.logo { + text-align: center; +} img.logo { - width: 100%; + width: 75%; } div.sphinxsidebar { diff --git a/mps/manual/html/design/abq.html b/mps/manual/html/design/abq.html new file mode 100644 index 00000000000..405c1e57661 --- /dev/null +++ b/mps/manual/html/design/abq.html @@ -0,0 +1,232 @@ + + + + + + + + + + 1. Queue design — Memory Pool System 1.111.0 documentation + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

1. Queue design

+
+

1.1. Introduction

+

.intro: This is the design of the ABQ module, which implements a +fixed-length queue of small objects.

+

.readership: This document is intended for any MM developer.

+

.name: The name ABQ originally stood for “Available Block Queue” as +the module is used by the MVT pool.

+
+
+

1.2. Requirements

+

.req.push: Clients can efficiently push new elements onto the queue.

+

.req.pop: Clients can efficiently pop elements from the queue.

+

.req.empty: Clients can efficiently test whether the queue is empty.

+

.req.abstract: The ABQ module does not know anything about the +elements in the queue other than their size.

+

.req.delete: Clients can delete elements from the queue. (Note: not necessarily efficiently.)

+

.req.iterate: Clients can iterate over elements in the queue.

+
+
+

1.3. Interface

+
+
+ABQStruct *ABQ
+
+ +

ABQ is the type of a queue. It is an alias for ABQStruct *. +ABQStruct is defined in the header so that it can be inlined in +client structures: clients must not depend on its implementation +details.

+
+
+ABQInit(Arena arena, ABQ abq, void *owner, Count elements, Size elementSize)
+
+ +

Initialize the queue abq. The parameter arena is the arena +whose control pool should be used to allocate the memory for the +queue; owner is passed to MeterInit() for the statistics; +elements is the maximum number of elements that can be stored in +the queue; and elementSize is the size of each element.

+
+
+void ABQFinish(Arena arena, ABQ abq)
+
+ +

Finish abq and free all resources associated with it.

+
+
+Res ABQPush(ABQ abq, void *element)
+
+ +

If the queue is full, leave it unchanged and return ResFAIL. +Otherwise, push element on to the queue and return ResOK.

+
+
+Res ABQPop(ABQ abq, void *elementReturn)
+
+ +

If the queue is empty, return ResFAIL. Othwreise, copy the first +element on the queue into the memory pointed to by elementReturn, +remove the element from the queue, and return ResOK.

+
+
+Res ABQPeek(ABQ abq, void *elementReturn)
+
+ +

If the queue is empty, return ResFAIL. Otherwise, copy the first +element on the queue into the memory pointed to by elementReturn +and return ResOK. (This is the same as ABQPop() except that +the queue is unchanged.)

+
+
+Bool ABQIsEmpty(ABQ abq)
+
+ +

If the queue is empty, return TRUE, otherwise return FALSE.

+
+
+Bool ABQIsFull(ABQ abq)
+
+ +

If the queue is full, return TRUE, otherwise return FALSE.

+
+
+Count ABQDepth(ABQ abq)
+
+ +

Return the number of elements in the queue.

+
+
+Bool (*ABQIterateMethod)(Bool *deleteReturn, void *element, void *closureP, Size closureS)
+
+ +

A callback function for ABQIterate(). The parameter element is +an element in the queue, and closureP and closureS are the +values that were originally passed to ABQIterate(). This function +must set *deleteReturn to FALSE if element must be kept in +the queue, or TRUE if element must be deleted from the queue. +It must return TRUE if the iteration must continue, or FALSE +if the iteration must stop after processing element.

+
+
+void ABQIterate(ABQ abq, ABQIterateMethod iterate, void *closureP, Size closureS)
+
+ +

Call iterate for each elements in the queue, passing the element +and closureP. See ABQIterateMethod for details.

+
+
+ + +
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/mps/manual/html/glossary/_Sidebar.html b/mps/manual/html/design/boot.html similarity index 53% rename from mps/manual/html/glossary/_Sidebar.html rename to mps/manual/html/design/boot.html index 30244a7f179..bacb6afe21e 100644 --- a/mps/manual/html/glossary/_Sidebar.html +++ b/mps/manual/html/design/boot.html @@ -8,7 +8,7 @@ - <no title> — Memory Pool System 1.111.0 documentation + The MPS Bootstrap — Memory Pool System 1.111.0 documentation @@ -44,10 +44,34 @@
- +
+

The MPS Bootstrap

+
+

Introduction

+

The `Memory Pool System`_ starts with no memory, but must somehow +allocate its own control structures in order to provide memory to the +client program. The MPS is freestanding [ref?] and so it can’t get its +memory from the C library’s malloc. So how does it get off the +ground? It pulls itself up by its own bootstraps. This document +describes how.

+
+

Note

+

This document was written as a prelude to reforming the bootstrap, +so it shouldn’t be taken as advocating it as an amazing piece of +design.

+
+

Pretty much the first call to the MPS is to ArenaCreate, which calls the +arena class specific init method. That must create an initialized arena, +except for the “control pool”, from which many MPS data structures will be +allocated.

+

In the case of the VM arena, VMArenaInit creates a VM large enough to hold +a VMArenaStruct (which contains the generic ArenaStruct) and maps +pages into it. It then calls ArenaInit to initialise the generic part, +before filling in the VM-specific part. Having done that, it adds the initial +VMChunk – a large area of address space – that will be used to supply +memory via ArenaAlloc.

+
+
@@ -57,7 +81,15 @@

Downloads

+

+

Table Of Contents

+ +

Downloads

MPS Kit release 1.111.0
diff --git a/mps/manual/html/design/bt.html b/mps/manual/html/design/bt.html index cf3c8ffbb48..c7338dea279 100644 --- a/mps/manual/html/design/bt.html +++ b/mps/manual/html/design/bt.html @@ -713,8 +713,8 @@ development.

intended to execute all of the module’s code in at least some minimal way.

.test.cbstest: cbstest.c. This was written as a test of the -CBS module (design.mps.cbs(2)). It compares the functional -operation of a CBS with that of a BT so is a good functional +CBS module (design.mps.cbs(2)). It compares the functional +operation of a CBS with that of a BT so is a good functional test of either module.

.test.mmqa.120: MMQA_test_function!210.c. This is used because it has a fair amount of segment allocation and freeing so exercises the arena diff --git a/mps/manual/html/design/cbs.html b/mps/manual/html/design/cbs.html new file mode 100644 index 00000000000..8242ce8331a --- /dev/null +++ b/mps/manual/html/design/cbs.html @@ -0,0 +1,422 @@ + + + + + + + + + + 2. Coalescing block structure — Memory Pool System 1.111.0 documentation + + + + + + + + + + + + + + + +

+ +
+
+
+
+ +
+

2. Coalescing block structure

+
+

2.1. Introduction

+

.intro: This is the design for impl.c.cbs, which implements a data +structure for the management of non-intersecting memory ranges, with +eager coalescence.

+

.readership: This document is intended for any MM developer.

+

.source: design.mps.poolmv2, design.mps.poolmvff.

+

.overview: The “coalescing block structure” is a set of addresses +(or a subset of address space), with provision for efficient +management of contiguous ranges, including insertion and deletion, +high level communication with the client about the size of contiguous +ranges, and detection of protocol violations.

+
+
+

2.2. Definitions

+

.def.range: A (contiguous) range of addresses is a semi-open +interval on address space.

+

.def.isolated: A contiguous range is isolated with respect to +some property it has, if adjacent elements do not have that property.

+
+
+

2.3. Requirements

+

.req.set: Must maintain a set of addresses.

+

.req.fast: Common operations must have a low amortized cost.

+

.req.add: Must be able to add address ranges to the set.

+

.req.remove: Must be able to remove address ranges from the set.

+

.req.size: Must report concisely to the client when isolated +contiguous ranges of at least a certain size appear and disappear.

+

.req.iterate: Must support the iteration of all isolated +contiguous ranges. This will not be a common operation.

+

.req.protocol: Must detect protocol violations.

+

.req.debug: Must support debugging of client code.

+

.req.small: Must have a small space overhead for the storage of +typical subsets of address space and not have abysmal overhead for the +storage of any subset of address space.

+

.req.align: Must support an alignment (the alignment of all +addresses specifying ranges) of down to sizeof(void *) without +losing memory.

+
+
+

2.4. Interface

+

.header: CBS is used through impl.h.cbs.

+
+

2.4.1. External types

+
+
+struct CBSStruct *CBS
+
+ +

.type.cbs: CBS is the main data structure for manipulating a +CBS. It is intended that a CBSStruct be embedded in another +structure. No convenience functions are provided for the allocation or +deallocation of the CBS.

+
+
+Bool (*CBSIterateMethod)(CBS cbs, Range range, void *closureP, Size closureS)
+
+ +

.type.cbs.iterate.method: Type CBSIterateMethod is a callback +function that may be passed to CBSIterate(). It is called for +every isolated contiguous range in address order. The function must +returns a Bool indicating whether to continue with the iteration.

+
+
+

2.4.2. External functions

+
+
+Res CBSInit(Arena arena, CBS cbs, void *owner, Align alignment, Bool fastFind, ArgList args)
+
+ +

.function.cbs.init: CBSInit() is the function that initialises +the CBS structure. It performs allocation in the supplied arena. The +parameter owner is passed to MeterInit(), an alignment +indicates the alignment of ranges to be maintained. An initialised CBS +contains no ranges.

+

fastFind, if set, causes the CBS to maintain, for each subtree, +the size of the largest block in that subtree. This must be true if +any of the CBSFindFirst(), CBSFindLast(), or +CBSFindLargest() functions are going to be used on the CBS.

+

CBSInit() may take one keyword argument:

+
    +
  • MPS_KEY_CBS_EXTEND_BY (type Size; default 4096) is the size +of segment that the CBS will request from the arena in which to +allocate its CBSBlock structures.
  • +
+
+
+void CBSFinish(CBS cbs)
+
+ +

.function.cbs.finish: CBSFinish() is the function that finishes +the CBS structure and discards any other resources associated with the +CBS.

+
+
+Res CBSInsert(Range rangeReturn, CBS cbs, Range range)
+
+ +

.function.cbs.insert: If any part of range is already in the +CBS, then leave it unchanged and return ResFAIL. Otherwise, +attempt to insert range into the CBS. If the insertion succeeds, +then update rangeReturn to describe the contiguous isolated range +containing the inserted range (this may differ from range if there +was coalescence on either side) and return ResOK. If the insertion +fails, return a result code indicating allocation failure.

+

.function.cbs.insert.fail: Insertion of a valid range (that is, one +that does not overlap with any range in the CBS) can only fail if the +new range is isolated and the allocation of the necessary data +structure to represent it failed.

+
+
+Res CBSDelete(Range rangeReturn, CBS cbs, Range range)
+
+ +

.function.cbs.delete: If any part of the range is not in the CBS, +then leave the CBS unchanged and return ResFAIL. Otherwise, update +rangeReturn to describe the contiguous isolated range that +contains range (this may differ from range if there are +fragments on either side) and attempt to delete the range from the +CBS. If the deletion succeeds, return ResOK. If the deletion +fails, return a result code indicating allocation failure.

+

.function.cbs.delete.fail: Deletion of a valid range (that is, one +that is wholly contained in the CBS) can only fail if there are +fragments on both sides and the allocation of the necessary data +structures to represent them fails.

+

.function.cbs.delete.return: CBSDelete() returns the contiguous +isolated range that contains range even if the deletion fails. +This is so that the caller can try deleting the whole block (which is +guaranteed to succeed) and managing the fragments using a fallback +strategy.

+
+
+void CBSIterate(CBS cbs, CBSIterateMethod iterate, void *closureP, Size closureS)
+
+ +

.function.cbs.iterate: CBSIterate() is the function used to +iterate all isolated contiguous ranges in a CBS. It receives a +pointer, Size closure pair to pass on to the iterator method, +and an iterator method to invoke on every range in address order. If +the iterator method returns FALSE, then the iteration is +terminated.

+
+
+Res CBSDescribe(CBS cbs, mps_lib_FILE *stream)
+
+ +

.function.cbs.describe: CBSDescribe() is a function that prints +a textual representation of the CBS to the given stream, indicating +the contiguous ranges in order, as well as the structure of the +underlying splay tree implementation. It is provided for debugging +purposes only.

+
+
+Bool CBSFindFirst(Range rangeReturn, Range oldRangeReturn, CBS cbs, Size size, FindDelete findDelete)
+
+ +

.function.cbs.find.first: Locate the first block (in address order) +within the CBS of at least the specified size, update rangeReturn +to describe that range, and return TRUE. If there is no such +block, it returns FALSE.

+

In addition, optionally delete the top, bottom, or all of the found +range, depending on the findDelete argument. This saves a separate +call to CBSDelete(), and uses the knowledge of exactly where we +found the range. The value of findDelete must come from this +enumeration:

+
enum {
+    FindDeleteNONE,    /* don't delete after finding */
+    FindDeleteLOW,     /* delete size bytes from low end of block */
+    FindDeleteHIGH,    /* delete size bytes from high end of block */
+    FindDeleteENTIRE   /* delete entire range */
+};
+
+
+

The original contiguous isolated range in which the range was found is +returned via the oldRangeReturn argument. (If findDelete is +FindDeleteNONE or FindDeleteENTIRE, then this will be +identical to the range returned via the rangeReturn argument.)

+

CBSFindFirst() requires that fastFind was true when +CBSInit() was called.

+
+
+Bool CBSFindLast(Range rangeReturn, Range oldRangeReturn, CBS cbs, Size size, FindDelete findDelete)
+
+ +

.function.cbs.find.last: Like CBSFindFirst(), except that it +finds the last block in address order.

+
+
+Bool CBSFindLargest(Range rangeReturn, Range oldRangeReturn, CBS cbs, Size size, FindDelete findDelete)
+
+ +

.function.cbs.find.largest: Locate the largest block within the +CBS, and if that block is at least as big as size, return its +range via the rangeReturn argument, and return TRUE. If there +are no blocks in the CBS at least as large as size, return +FALSE. Pass 0 for size if you want the largest block +unconditionally.

+

Like CBSFindFirst(), optionally delete the range (specifying +FindDeleteLOW or FindDeleteHIGH has the same effect as +FindDeleteENTIRE). This feature requires that fastFind was +true when CBSInit() was called.

+
+
+
+

2.5. Implementation

+

.impl: This section is concerned with describing various aspects of +the implementation. It does not form part of the interface definition.

+
+

2.5.1. Splay tree

+

.impl.splay: The CBS is principally implemented using a splay tree +(see design.mps.splay). Each splay tree node is embedded in a +CBSBlock that represents a semi-open address range. The key passed +for comparison is the base of another range.

+

.impl.splay.fast-find: CBSFindFirst() and CBSFindLast() use +the update/refresh facility of splay trees to store, in each +CBSBlock, an accurate summary of the maximum block size in the +tree rooted at the corresponding splay node. This allows rapid +location of the first or last suitable block, and very rapid failure +if there is no suitable block.

+

.impl.find-largest: CBSFindLargest() simply finds out the size +of the largest block in the CBS from the root of the tree, using +SplayRoot(), and does SplayFindFirst() for a block of that +size. This is O(log n) in the size of the free list, so it’s about +the best you can do without maintaining a separate priority queue, +just to do CBSFindLargest().

+
+
+

2.5.2. Low memory behaviour

+

.impl.low-mem: When the CBS tries to allocate a new CBSBlock +structure for a new isolated range as a result of either +CBSInsert() or CBSDelete(), and there is insufficient memory +to allocation the CBSBlock structure, then the range is not added +to the CBS or deleted from it, and the call to CBSInsert() or +CBSDelete() returns ResMEMORY.

+
+
+

2.5.3. The CBS block

+

.impl.cbs.block: The block contains a base-limit pair and a splay +tree node.

+

.impl.cbs.block.special: The base and limit may be equal if the +block is halfway through being deleted.

+

.impl.cbs.block.special.just: This conflates values and status, but +is justified because block size is very important.

+
+
+
+

2.6. Testing

+

.test: The following testing will be performed on this module:

+

.test.cbstest: There is a stress test for this module in +impl.c.cbstest. This allocates a large block of memory and then +simulates the allocation and deallocation of ranges within this block +using both a CBS and a BT. It makes both valid and invalid +requests, and compares the CBS response to the correct behaviour +as determined by the BT. It also iterates the ranges in the +CBS, comparing them to the BT. It also invokes the +CBSDescribe() method, but makes no automatic test of the resulting +output. It does not currently test the callbacks.

+

.test.pool: Several pools (currently MVT and MVFF) are implemented +on top of a CBS. These pool are subject to testing in development, QA, +and are/will be heavily exercised by customers.

+
+
+

2.7. Notes for future development

+

.future.not-splay: The initial implementation of CBSs is based on +splay trees. It could be revised to use any other data structure that +meets the requirements (especially .req.fast).

+

.future.hybrid: It would be possible to attenuate the problem of +.risk.overhead (below) by using a single word bit set to represent +the membership in a (possibly aligned) word-width of grains. This +might be used for block sizes less than a word-width of grains, +converting them when they reach all free in the bit set. Note that +this would make coalescence slightly less eager, by up to +(word-width - 1).

+
+
+

2.8. Risks

+

.risk.overhead: Clients should note that the current implementation +of CBSs has a space overhead proportional to the number of isolated +contiguous ranges. [Four words per range.] If the CBS contains every +other grain in an area, then the overhead will be large compared to +the size of that area. [Four words per two grains.] The CBS structure +is thus suitable only for managing large enough ranges.

+
+
+ + +
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/mps/manual/html/design/config.html b/mps/manual/html/design/config.html index 272939fef2a..4110bca1318 100644 --- a/mps/manual/html/design/config.html +++ b/mps/manual/html/design/config.html @@ -8,7 +8,7 @@ - 1. MPS Configuration — Memory Pool System 1.111.0 documentation + 3. MPS Configuration — Memory Pool System 1.111.0 documentation @@ -28,8 +28,8 @@ - - + +