Misc minor edits.

Copied from Perforce
 Change: 180118
 ServerID: perforce.ravenbrook.com
This commit is contained in:
Gareth Rees 2012-10-27 20:59:48 +01:00
parent 609b815f9e
commit 86d0cd8775
9 changed files with 123 additions and 122 deletions

View file

@ -40,7 +40,7 @@ General debugging advice
space layout randomization`_: if you perform computation based on
the addresses of objects, for example, hashing objects by their
address, then ASLR will cause your hash tables to be laid out
differently on each run, which may effect the order of memory
differently on each run, which may affect the order of memory
management operations.)
.. _address space layout randomization: http://en.wikipedia.org/wiki/Address_space_layout_randomization
@ -50,7 +50,7 @@ General debugging advice
are discovered. So if you have a bug that's hard to reproduce, or
which manifests itself in different ways on different runs, you may
be able to provoke it more reliably, or get a more consistent
result by having a mode for testing in which you run frequent
result, by having a mode for testing in which you run frequent
collections (by calling :c:func:`mps_arena_collect` followed by
:c:func:`mps_arena_release`), perhaps as frequently as every
allocation.

View file

@ -11,7 +11,7 @@ Memory Pool System
guide/index
topic/index
pool/index
topic/porting
topic/internals
Appendices
@ -27,9 +27,4 @@ Appendices
contact
todo
Indices and tables
##################
* :ref:`genindex`
* :ref:`search`

View file

@ -31,14 +31,34 @@ The AMC pool class exploits assumptions about object lifetimes and inter-connect
If an allocation point is created in an AMC pool, the call to :c:func:`mps_ap_create` will take no additional parameters.
--------------------
AMC symbol reference
--------------------
AMC interface
-------------
::
#include "mpscamc.h"
.. c:function:: mps_class_t mps_class_amc(void)
Return the :term:`pool class` for an AMC (Automatic
Mostly-Copying) :term:`pool`.
When creating an AMC pool, :c:func:`mps_pool_create` takes two
extra arguments::
mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
mps_class_t mps_class_amc(),
mps_fmt_t fmt,
mps_chain_t chain)
``fmt`` specifies the :term:`object format` for the objects
allocated in the pool.
``chain`` specifies the :term:`generation chain` for the pool.
AMC introspection
-----------------
.. c:function:: void mps_amc_apply(mps_pool_t pool, mps_amc_apply_stepper_t f, void *p, size_t s)
@ -78,7 +98,7 @@ AMC symbol reference
Walking the heap is "dodgy".
.. c:type:: void (*mps_amc_apply_stepper_t)(mps_addr_t object, void *p, size_t s);
.. c:type:: void (*mps_amc_apply_stepper_t)(mps_addr_t object, void *p, size_t s)
The type of a :term:`stepper function` for :term:`formatted
objects <formatted object>` in an AMC pool.
@ -92,20 +112,3 @@ AMC symbol reference
automatically managed memory except within ``object``.
.. c:function:: mps_class_t mps_class_amc(void)
Return the :term:`pool class` for an AMC (Automatic
Mostly-Copying) :term:`pool`.
When creating an AMC pool, :c:func:`mps_pool_create` takes two
extra arguments::
mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena,
mps_class_t mps_class_amc(),
mps_fmt_t fmt,
mps_chain_t chain)
``fmt`` specifies the :term:`object format` for the objects
allocated in the pool.
``chain`` specifies the :term:`generation chain` for the pool.

View file

@ -19,11 +19,8 @@ that pool. You create a generation chain by preparing an array of
kilobytes) and *predicted mortality* (between 0 and 1) of each
generation, and passing them to :c:func:`mps_chain_create`.
The term *capacity* is misleading: it's actually a threshold on the
*new size* of a generation. The :dfn:`new size` is the size of the
newly allocated (in generation 0) or newly promoted (in other
generations) blocks. When the new size exceeds the capacity, the MPS
will be prepared to start collecting the generation. See
When the size of the generation exceeds the capacity, the MPS will be
prepared to start collecting the generation. See
:ref:`topic-collection-schedule` below.
For example::
@ -31,7 +28,6 @@ For example::
mps_gen_param_s gen_params[] = {
{ 1024, 0.8 },
{ 2048, 0.4 },
{ 4096, 0.2 },
};
mps_chain_t chain;
@ -107,8 +103,8 @@ Scheduling of collections
-------------------------
The first generation in a pool's chain is the :term:`nursery
generation`. When the nursery's "new size" exceeds its capacity, the
MPS considers collecting the pool. (Whether it actually does so or not
generation`. When the nursery's size exceeds its capacity, the MPS
considers collecting the pool. (Whether it actually does so or not
depends on which other collections on other pools are in progress.)
.. note::
@ -118,31 +114,31 @@ depends on which other collections on other pools are in progress.)
<topic-pattern-ramp>`.
If the MPS decides to collect a pool at all, all generations are
collected below the first generation whose "new size" is less than its
collected below the first generation whose size is less than its
capacity.
For example, suppose that we have a pool with the following generation
structure:
+------------+--------------+----------------------+----------------+
| | Current size | Chain parameters | Predicted size |
| +------+-------+----------+-----------+--------+-------+
| Generation | New | Total | Capacity | Mortality | New | Total |
+============+======+=======+==========+===========+========+=======+
| 0 | 110 | 110 | 100 | 0.8 | 0 | 0 |
+------------+------+-------+----------+-----------+--------+-------+
| 1 | 210 | 210 | 200 | 0.4 | 22 | 22 |
+------------+------+-------+----------+-----------+--------+-------+
| 2 | 260 | 640 | 400 | 0.2 | 386 | 766 |
+------------+------+-------+----------+-----------+--------+-------+
| Generation | Current size | Capacity | Mortality | Predicted size |
+============+==============+==========+===========+================+
| 0 | 110 | 100 | 0.8 | 0 |
+------------+--------------+----------+-----------+----------------+
| 1 | 210 | 200 | 0.4 | 22 |
+------------+--------------+----------+-----------+----------------+
| 2 | 200 | 300 | 0.2 | 326 |
+------------+--------------+----------+-----------+----------------+
The nursery and generation 1 both have "new size" that exceeds their
capacity, so these generations will be collection. Generation 2 will
not be collected (even though its total size exceeds its capacity).
The last two columns give the predicted sizes of each generation after
the collection: the survivors from the nursery will be promoted to
generation 1 and the survivors from generation 1 will be promoted to
generation 2.
The nursery and generation 1 both have size that exceeds their
capacity, so these generations will be collected. Generation 2 will
not be collected this time. The last two columns give the predicted
sizes of each generation after the collection: the survivors from the
nursery will be promoted to generation 1 and the survivors from
generation 1 will be promoted to generation 2.
When the last generation in the chain is collected, the survivors are
promoted into an :term:`arena`\-wide "top" generation.
The predicted mortality is used to estimate how long the collection
will take, and this is used in turn to decide how much work the

View file

@ -104,7 +104,7 @@ either behaviour.
Example: ports in Scheme
------------------------
In Scheme, an open file is represent by a *port*. In the toy Scheme
In Scheme, an open file is represented by a *port*. In the toy Scheme
example, a port is a wrapper around a Standard C file handle::
typedef struct port_s {
@ -114,65 +114,71 @@ example, a port is a wrapper around a Standard C file handle::
} port_s;
The Scheme procedure ``open-input-file`` takes a filename and returns
a port::
a port:
.. code-block:: c
:emphasize-lines: 21
/* (open-input-file filename)
* Opens filename for input, with empty file options, and returns the
* obtained port.
* R6RS Standard Library 8.3.
* See R4RS 6.10.1
*/
static obj_t entry_open_input_file(obj_t env, obj_t op_env, obj_t operator, obj_t operands)
{
obj_t filename;
FILE *stream;
obj_t port;
mps_addr_t port_ref;
eval_args(operator->operator.name, env, op_env, operands, 1, &filename);
unless(TYPE(filename) == TYPE_STRING)
error("%s: argument must be a string", operator->operator.name);
stream = fopen(filename->string.string, "r");
if(stream == NULL)
error("%s: cannot open input file", operator->operator.name);
port = make_port(filename, stream);
obj_t filename;
FILE *stream;
obj_t port;
mps_addr_t port_ref;
eval_args(operator->operator.name, env, op_env, operands, 1, &filename);
unless(TYPE(filename) == TYPE_STRING)
error("%s: argument must be a string", operator->operator.name);
stream = fopen(filename->string.string, "r");
if(stream == NULL)
error("%s: cannot open input file", operator->operator.name);
port = make_port(filename, stream);
port_ref = port;
mps_finalize(arena, &port_ref);
port_ref = port;
mps_finalize(arena, &port_ref);
return port;
return port;
}
Each time around the readevalprint loop, the interpreter polls the
message queue for finalization messages, and when it finds one it
closes the port's underlying file handle::
closes the port's underlying file handle:
.. code-block:: c
:emphasize-lines: 9, 12
mps_message_type_t type;
while (mps_message_queue_type(&type, arena)) {
mps_message_t message;
mps_bool_t b;
b = mps_message_get(&message, arena, type);
assert(b); /* we just checked there was one */
mps_message_t message;
mps_bool_t b;
b = mps_message_get(&message, arena, type);
assert(b); /* we just checked there was one */
if (type == mps_message_type_finalization()) {
mps_addr_t port_ref;
obj_t port;
mps_message_finalization_ref(&port_ref, arena, message);
port = port_ref;
assert(TYPE(port) == TYPE_PORT);
printf("Port to file \"%s\" is dying. Closing file.\n",
port->port.name->string.string);
(void)fclose(port->port.stream);
} else {
/* ... handle other message types ... */
}
if (type == mps_message_type_finalization()) {
mps_addr_t port_ref;
obj_t port;
mps_message_finalization_ref(&port_ref, arena, message);
port = port_ref;
assert(TYPE(port) == TYPE_PORT);
printf("Port to file \"%s\" is dying. Closing file.\n",
port->port.name->string.string);
(void)fclose(port->port.stream);
} else {
/* ... handle other message types ... */
}
mps_message_discard(arena, message);
mps_message_discard(arena, message);
}
Here's an example session showing finalization taking place:
.. code-block:: none
:emphasize-lines: 14
:emphasize-lines: 8
MPS Toy Scheme Example
9960, 0> (open-input-file "scheme.c")
@ -253,26 +259,6 @@ Cautions
Finalization interface
----------------------
.. c:function:: mps_res_t mps_definalize(mps_arena_t arena, mps_addr_t *ref)
Deregister a :term:`block` for :term:`finalization`.
``arena`` is the arena in which the block lives.
``ref`` points to a :term:`reference` to the block to be
deregistered for finalization.
Returns :c:macro:`MPS_RES_OK` if successful, or
:c:macro:`MPS_RES_FAIL` if the block was not previously registered
for finalization.
.. note::
This function receives a pointer to a reference. This is to
avoid placing the restriction on the :term:`client program`
that the C call stack be a :term:`root`.
.. c:function:: mps_res_t mps_finalize(mps_arena_t arena, mps_addr_t *ref)
Register a :term:`block` for :term:`finalization`.
@ -298,6 +284,26 @@ Finalization interface
that the C call stack be a :term:`root`.
.. c:function:: mps_res_t mps_definalize(mps_arena_t arena, mps_addr_t *ref)
Deregister a :term:`block` for :term:`finalization`.
``arena`` is the arena in which the block lives.
``ref`` points to a :term:`reference` to the block to be
deregistered for finalization.
Returns :c:macro:`MPS_RES_OK` if successful, or
:c:macro:`MPS_RES_FAIL` if the block was not previously registered
for finalization.
.. note::
This function receives a pointer to a reference. This is to
avoid placing the restriction on the :term:`client program`
that the C call stack be a :term:`root`.
Finalization messages
---------------------

View file

@ -21,8 +21,7 @@ Reference
location
cache
pattern
frame
debugging
telemetry
frame
low
critical

View file

@ -1,10 +1,11 @@
.. _internals:
Porting
*******
Internals
*********
.. toctree::
:numbered:
plinth
platform
critical

View file

@ -126,9 +126,6 @@ Here's how this looks in operation:
the latest Emacs pretest. All I had done was to remove the
"Garbage collecting" message which people perceive as
slowing Emacs down and tell them that it had been sped up.
It is, somehow, permissible for a program to take a lot of
time doing any other task than administrative duties like
garbage collection.
Message types

View file

@ -1,3 +1,5 @@
.. highlight:: none
.. _topic-telemetry:
Telemetry
@ -84,10 +86,12 @@ program::
The ``sort`` is useful because the events are not necessarily written
to the telemetry file in time order, but each event starts with a
timestamp so sorting makes a time series. The decoded events look like
this, with the timestamp in the first column (in units of
:c:type:`mps_clock_t`, typically 1 µs), the event type in the second
column, and then addresses or other data related to the event in the
remaining columns. All numbers are given in hexadecimal. ::
this, with the timestamp in the first column, the event type in the
second column, and then addresses or other data related to the event
in the remaining columns. The timestamp comes from the high-resolution
processor timer (on IA-32 and x86-64, this is the `Time Stamp Counter
<http://en.wikipedia.org/wiki/Time_Stamp_Counter>`_). All numbers are
given in hexadecimal. ::
000AE03973336E3C 2B 1003FC000 1003FD000 1003FE000
000AE0397333BC6D 2D 1003FC000 1003FD000 1003FE000