Keywords:
Cc:wilson@cs.utexas.edu
Paul Wilson writes:
> The fact that this system could run for a day or more without
> accumulating pathological fragmentation is a good sign, up to a point.
I think you have misunderstood me - my earlier message stated:
> Without compaction, the system would rapidly become unusable and have to
> be rebooted. With compaction it would run for a (small) number of days.
That is *terminal* fragmentation set in in about an hour of usage if the
compaction algorithm was not in use. With the compaction algorithm, it
would in principle run indefinitely (given that users who exceeded their
allocated resources could be killed). However there was a bug somewhere in
the system (we suspected the hardware) which resulted in a mean time
between failure of something over 1 day. Even programs like the Boyer-Moore
prover, whose data-usage was mostly list-cells, would cause fragmentation as
they were incrementally re-compiled during debugging because the code-blocks
were of disparate sizes
It is possible that Multipop will be revived in the Royal Scottish
Museum, which has acquired the necessary hardware to do so. The (paper)
tapes of at least one version of the system also exist, so
the performance can possibly be verified.
Paul Wilson also writes:
> I find this pretty interesting. I take it this was a unified heap,
> like in a Lisp machine system, where you don't have the usual process
> memory boundaries, but unlike a Lisp machine in that you seldom do
> compaction very often.
....
From (my wetware) memory (this could in principle be verified from
extant listings):
The memory belonging to each process was NOT segregated. Security
depended solely on the fact that the one compiler (for POP-2) generated
well behaved code of a quality roughly comparable to a simple LISP
compiler. Store usage by a user was accounted for by the garbage collector,
which starting from process records, added the size of each marked object
to a variable. A user exceeding his/her allocation could be killed by the
machine operator (!) setting a sense-key on the console; this was
generally done if the machine seemed to be g.c. thrashing.
> Unified heaps for multiple processes are interesting, because nobody
> knows whether the intermixing of objects created and used for different
> concurrent processes tends to increase fragmentation, or reduce it,
> or what. (And I think that's likely to be very allocator dependent.)
The earliest design for Multipop68 called for a "zoo of objects in
cages", i.e. each class of object would be held in a separate area of
store, so that type could be determined by location. Thus user-specific
data-types would have been separated, though common types (e.g. lists,
strings) would have been put in the same cage. This "zoo" was abandoned in
favour of the "key cell" system (q.v.), due to Mike Foster, partly because
of the greater complication of the zoo, and partly because we suspected
that any savings arising from the encoding of type in the address would be
lost in the existence of unusable space in partly-full cages.
A more conventional time sharing system (Multipop 70) was
developed for the target machine. It was universally disliked
for bad performance. However that arose from the limitations of the discs,
combined with a small main memory, so has no relevance to the
fragmentation issue.
> Is there a more detailed description of the allocator strategy? (E.g.,
> did the allocator attempt to separte objects created by different
> processes, or just mix them together in allocation order, or what?)
The allocator maintained separate free lists for small objects (up to about
five words in length I recall). Longer objects were allocated by searching
a free list until one of the right length or larger was found. These free
lists were global to the system. If no object was found, a garbage
collection was started. (This meant of course that a user who turned over
store rapidly got an unfair share of machine resources).
I recall that we used a dedicated area of store to hold the
old-address->new address map for the purposes of compaction - thus more
than one compaction might be needed to recover severely fragmented space.
Each object in memory had one pointer to a "key cell" which contained
data-class-common information, including two methods needed by the garbage
collector, a mark-and-trace method and a relocate method (we did not call
them methods of course...). A data-class whose members varied in length
(e.g. strings) had an additional field in each instance which specified the
length. Users could define their own data-classes.
A process record contained (a) 2 stacks for each user (b) a dictionary
mapping identifiers to store locations (all variables were in the LISP
sense special, with closures done by what was later to be called "lambda
lifting") (c) a copy of the special variables of the compiler. A context
switch involved saving the special variables (including the PC) of the user
being swapped out, and restoring those of the user being swapped in.
Thus each user had one process. Later (around 1970) continuations were
added to POP-2, but were never used as the basic process mechanism of
Multipop, being decidedly inefficient given the non-lexical nature of
variables.
The allocation was complicated by boundaries in the machine architecture -
references (variable-value slots) had to be in the 1st 32k words, and
program within the 1st 64k. In effect, this was a partial revival of the
"zoo" architecture.
Interrupt handling in Multipop was conventionally coded in assembly
language. The interface to the operating system used function-closures to
provide security. For example, a disc-file was presented as a closure whose
data-part was a buffer, and whose function part was the code to extract
characters from the buffer.
Robin Popplestone.
|