[D-runtime] Extending pages in GC
Steve Schveighoffer
schveiguy at yahoo.com
Wed Jul 14 04:40:58 PDT 2010
Currently, in the GC, there is this routine:
extend(void * p, size_t minsize, size_t maxsize)
The parameters are the pointer to extend, the minimum number of bytes to add to
the block, and the maximum number of bytes to add.
This only works if the block is page size or greater. It essentially queries
the pool for pages that are "committed" and "free" that are after the currently
allocated block, and adds them to the block.
If the minimum number of pages required to satisfy extend are not free and
comitted, then it uses a Pool method:
extendPages(uint n)
Which will "commit" up to n pages if it has that many uncomitted pages, or it
will return an error.
The issue is, what argument do you pass to extendPages? The only sane value to
pass is minsize, because if you pass maxsize and it fails, then you didn't get
anything.
But why shouldn't extendPages commit as many pages as possible? If that was the
case, then you could get closer to your desired maxsize.
Here is the syndrome I'm trying to fix. When using appending on an array to add
one element at a time, the array append code will use a function newCapacity to
add a certain percentage of memory to a block (the size varies, from something
like 300% of the current size for small arrays to 20% for very large arrays).
If it can use extend, it will. But it will only use newCapacity if completely
reallocating. I recently change it to try extend with the minimum size needed
to append as minsize, and the result of newCapacity as the maxsize.
What I found was happening is, even though the maxsize requested was hundreds,
even thousands, of pages, I would get a single page, then 15 pages, then a
single page, then 15 pages, etc. So clearly the pages are available, but the
routine doesn't add all it can. What happens is the "commit" size must be a
multiple of 16 pages. So when extend cannot get any free pages, it calls
extendPages to get enough pages to cover minsize (usually 1). extendPages must
commit a multiple of 16 pages, so it commits 16. extend gets its one page, and
returns. There are now 15 free pages, so the next append adds 15 more. But
this defeats the algorithm which tries to pre-allocate a proportional amount of
data while appending.
What I want to have is a function that tries its best to get to maxsize, using
any means possible, including comitting pages. I plan to add such
functionality. What I'm not sure of is, should I modify the existing functions,
or add new ones?
My proposed changes would be to add a new extendPagesUpTo(n) (name to be worked
on) which may extend *up to* n pages, and then modify extend to use this
function instead. I don't want to change extendPages(n) because some code may
rely on the current behavior of returning an error if it cannot extend to *at
least* n pages. However, I think extend can be changed because it already is
expected to return some value between minsize and maxsize or 0 if it couldn't do
it.
What do you think?
-Steve
More information about the D-runtime
mailing list