> > 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