>
> Implementing COW is a bit harder, although now that we have a DOD pass, a
> lot easier. We can update counts in there...it's just not very easy to see
> how we're going to keep track of refcounts.
>

I made two assumptions for my test implementation of COW strings:
1) we need to be able to share substrings as well as complete strings
2) COW must survive garbage collection
Without these two, I believe the overhead probably outweighs the benefits

However, these assumptions then led to a few implementation difficulties:

1) The string header has to reference both the start of the buffer and the
start of the string i.e. we need to add either a second pointer or an
offset. This impacts on all code using bufstart as the start of the string.
2) Some sort of flag or counter is required during garbage collection to
ensure that a given buffer is only copied once. Since the current version of
Parrot_allocate always makes the buffer larger than the requested size, I
just used the byte after buflen. To make sure I always have space for the
relocation address, I changed string_make to round the buffer size up to one
less than the next multiple of 16; _allocate will then go one bigger, which
will be the flag byte.
[Incidentally, this makes sense anyway if any in-place string alterations
occur, as the otherwise-wasted padding can be used to grow the string]
(go_collect currently uses a different rounding rule, which incidentally
makes zero-length buffers end up pointing to the same location as the next
non-zero length buffer; for COW purposes I changed this to work the same as
_allocate)

The flag byte needs three values:
a) Uncopied buffer (set when buffer is allocated)
b) Copied once, not referenced again
c) Copied once and referenced by at least one other header

I was originally thinking of a separate pass to find buffers in state (b)
and reset their (header's) COW flag; an alternative would be to store the
address of the first header in the old buffer (need to ensure that a
minimum-size buffer can hold two pointers as well as the flag byte!) and
clear its COW flag regardless; if another reference to the same buffer is
found, then set the COW flag in the first header. This removes the second
pass at a slightly increased cost for the normal GC pass.

Before Dan put his memory allocation / garbage collection system in place,
COW gave a significant performance increase on string-intensive processing,
due to the overheads of using the system memory allocator and to the
ever-increasing memory utilisation. In my latest tests, COW seemed to make
very little difference; however, I have not yet implemented the clearing of
the COW flag as discussed above, so "once a cow, always a cow", which will
have some negative impact.

--
Peter Gibbs
EmKel Systems


Reply via email to