digitalmars.D - BigInt -- a challenge for std.allocator
- Joseph Rushton Wakeling (39/39) Oct 29 2013 Hello all,
- bearophile (5/6) Oct 29 2013 It seems you refer to:
- Froglegs (2/8) Oct 29 2013 Does BigInt not have overloaded operators for adding normal
- Don (7/17) Oct 29 2013 Yes, it has overloaded operators, but that's not relevant. The
- Dmitry Olshansky (7/26) Oct 29 2013 Can't it use ref-counted COW? Then since there is only 1 reference to
- Joseph Rushton Wakeling (4/8) Oct 29 2013 Yes, that's pretty much what I was thinking of. The question is how to
- inout (3/14) Oct 29 2013 This has almost nothing to do with an allocator.
- Joseph Rushton Wakeling (7/8) Oct 30 2013 My impression was that std.allocator as-is was designed to create a tool...
- Dicebot (6/13) Oct 30 2013 "memory allocation strategy" != "memory management strategy",
- Andrei Alexandrescu (5/13) Oct 30 2013 Reference counting comes somewhere on top of allocators. (For a long
- Joseph Rushton Wakeling (6/9) Oct 30 2013 Ahh, OK. That makes more sense. It rather baffled me to hear people sa...
- Dmitry Olshansky (5/15) Oct 30 2013 Like others said - just use allocator.alloc/allocator.free instead of
- Andrei Alexandrescu (8/24) Oct 30 2013 Well actually there are things that can be done at the allocator level
- Dmitry Olshansky (12/19) Oct 30 2013 That would entail some work to tie-up refcounts and bigint internal
- Kagamin (7/18) Oct 30 2013 Implement a pool of bigints as an allocator: when refcount
Hello all, First up -- please understand that this is written by someone whose practical experience of memory allocation is limited to either malloc/free or new/delete, and who is used to programming in scenarios where typically the amount of memory required can be allocated at the start of a program and freed at the end -- so, the rationale or use-cases of most of the content in std.allocator is not obvious to me. So, in writing this, I'm looking to be educated ... :-) As part of the work I've been doing towards getting David Simcha's std.rational module into Phobos, I've been looking inside std.bigint. One aspect of how it works is its memory management: it has an internally-allocated data store (at its core, an array of words of some appropriate size, typically the same as the machine word size) which is stored by reference inside the user-facing object. By default, when you copy a BigInt, this data is not duplicated -- the reference is copied instead, and BigInt copies only on write. So: BigInt m = 100; BigInt n = m; // just copies the reference m = 50; // creates a new data store and writes to it However, this has the unfortunate effect that it copies on write _regardless of whether multiple BigInts are pointing to the same data_. So, you can do something like: BigInt n = 100; n += 10; ++n; ... and both the 2nd and 3rd lines will result in a reallocation even though there is no need for it, because only n is referencing the memory it wraps. So, a better approach would be for BigInt write to ask, if (/* I'm the only person referencing this memory */) { // just write straight to the memory } else { // allocate new memory and write to it } But, how would one go about implementing that using std.allocator? Or ... am I overthinking this, and std.typecons.RefCounted would be a better approach? Thanks & best wishes, -- Joe
Oct 29 2013
Joseph Rushton Wakeling:if (/* I'm the only person referencing this memory */)It seems you refer to: http://en.wikipedia.org/wiki/Uniqueness_typing Bye, bearophile
Oct 29 2013
BigInt n = 100; n += 10; ++n; ... and both the 2nd and 3rd lines will result in a reallocation even though there is no need for it, because only n is referencing the memory it wraps.Does BigInt not have overloaded operators for adding normal integers? Is it converting 10 to a BigInt prior to adding it to n?
Oct 29 2013
On Tuesday, 29 October 2013 at 11:26:45 UTC, Froglegs wrote:Yes, it has overloaded operators, but that's not relevant. The issue is that initially n points to an block of memory, containing [100]. Then, if you use COW, n+= 10 isn't in-place. It has to create a new array, containing [110]. Then ++n creates a third array. [111].BigInt n = 100; n += 10; ++n; ... and both the 2nd and 3rd lines will result in a reallocation even though there is no need for it, because only n is referencing the memory it wraps.Does BigInt not have overloaded operators for adding normal integers? Is it converting 10 to a BigInt prior to adding it to n?
Oct 29 2013
29-Oct-2013 16:22, Don пишет:On Tuesday, 29 October 2013 at 11:26:45 UTC, Froglegs wrote:Can't it use ref-counted COW? Then since there is only 1 reference to the original block it may mutate it in-place else it creates new chunk with refs=1 and decrements the original count. Maybe I'm missing something but it shouldn't be that hard. -- Dmitry OlshanskyYes, it has overloaded operators, but that's not relevant. The issue is that initially n points to an block of memory, containing [100]. Then, if you use COW, n+= 10 isn't in-place. It has to create a new array, containing [110]. Then ++n creates a third array. [111].BigInt n = 100; n += 10; ++n; ... and both the 2nd and 3rd lines will result in a reallocation even though there is no need for it, because only n is referencing the memory it wraps.Does BigInt not have overloaded operators for adding normal integers? Is it converting 10 to a BigInt prior to adding it to n?
Oct 29 2013
On 29/10/13 15:58, Dmitry Olshansky wrote:Can't it use ref-counted COW? Then since there is only 1 reference to the original block it may mutate it in-place else it creates new chunk with refs=1 and decrements the original count. Maybe I'm missing something but it shouldn't be that hard.Yes, that's pretty much what I was thinking of. The question is how to implement it in terms of std.allocator -- or is that the wrong base to build ref=counted memory upon?
Oct 29 2013
On Tuesday, 29 October 2013 at 21:59:38 UTC, Joseph Rushton Wakeling wrote:On 29/10/13 15:58, Dmitry Olshansky wrote:This has almost nothing to do with an allocator.Can't it use ref-counted COW? Then since there is only 1 reference to the original block it may mutate it in-place else it creates new chunk with refs=1 and decrements the original count. Maybe I'm missing something but it shouldn't be that hard.Yes, that's pretty much what I was thinking of. The question is how to implement it in terms of std.allocator -- or is that the wrong base to build ref=counted memory upon?
Oct 29 2013
On 30/10/13 01:38, inout wrote:This has almost nothing to do with an allocator.My impression was that std.allocator as-is was designed to create a toolkit for developers to build different memory management strategies into their applications. Is there any reason why that should exclude implementing ref-counting approaches? As I said at the start, I'm looking to be educated, so I'd appreciate you explaining why something is wrong rather than just telling me.
Oct 30 2013
On Wednesday, 30 October 2013 at 12:39:18 UTC, Joseph Rushton Wakeling wrote:On 30/10/13 01:38, inout wrote:"memory allocation strategy" != "memory management strategy", though those can be possibly coupled. Ref-counting can be done on top of any allocation strategy that support deterministic deallocattion.This has almost nothing to do with an allocator.My impression was that std.allocator as-is was designed to create a toolkit for developers to build different memory management strategies into their applications. Is there any reason why that should exclude implementing ref-counting approaches?
Oct 30 2013
On 10/30/13 5:39 AM, Joseph Rushton Wakeling wrote:On 30/10/13 01:38, inout wrote:Reference counting comes somewhere on top of allocators. (For a long time I thought they should be fused; now I think they can be neatly separated.) Allocators know how to manage void[] and that's about it. AndreiThis has almost nothing to do with an allocator.My impression was that std.allocator as-is was designed to create a toolkit for developers to build different memory management strategies into their applications. Is there any reason why that should exclude implementing ref-counting approaches? As I said at the start, I'm looking to be educated, so I'd appreciate you explaining why something is wrong rather than just telling me.
Oct 30 2013
On 30/10/13 16:21, Andrei Alexandrescu wrote:Reference counting comes somewhere on top of allocators. (For a long time I thought they should be fused; now I think they can be neatly separated.) Allocators know how to manage void[] and that's about it.Ahh, OK. That makes more sense. It rather baffled me to hear people saying, "This has nothing to do with an allocator." My impression is that std.typecons.RefCounted has some issues, and that we might expect better reference counting solutions to be built on top of std.allocator -- otherwise I'd just have used the existing RefCounted.
Oct 30 2013
30-Oct-2013 01:59, Joseph Rushton Wakeling пишет:On 29/10/13 15:58, Dmitry Olshansky wrote:Like others said - just use allocator.alloc/allocator.free instead of malloc/free nothing stellar. -- Dmitry OlshanskyCan't it use ref-counted COW? Then since there is only 1 reference to the original block it may mutate it in-place else it creates new chunk with refs=1 and decrements the original count. Maybe I'm missing something but it shouldn't be that hard.Yes, that's pretty much what I was thinking of. The question is how to implement it in terms of std.allocator -- or is that the wrong base to build ref=counted memory upon?
Oct 30 2013
On 10/30/13 9:35 AM, Dmitry Olshansky wrote:30-Oct-2013 01:59, Joseph Rushton Wakeling пишет:Well actually there are things that can be done at the allocator level to explicitly help reference counting: 1. The refcount could be an affix to the allocated block. 2. Small refcounts can be kept together in a compact block a la HeapBlock. 3. Or refcounts can be kept in a freelist. So refounting can be helped by an allocator built especially for it. AndreiOn 29/10/13 15:58, Dmitry Olshansky wrote:Like others said - just use allocator.alloc/allocator.free instead of malloc/free nothing stellar.Can't it use ref-counted COW? Then since there is only 1 reference to the original block it may mutate it in-place else it creates new chunk with refs=1 and decrements the original count. Maybe I'm missing something but it shouldn't be that hard.Yes, that's pretty much what I was thinking of. The question is how to implement it in terms of std.allocator -- or is that the wrong base to build ref=counted memory upon?
Oct 30 2013
30-Oct-2013 22:02, Andrei Alexandrescu пишет:Well actually there are things that can be done at the allocator level to explicitly help reference counting: 1. The refcount could be an affix to the allocated block.Yup. I seriously underappreciated this one.2. Small refcounts can be kept together in a compact block a la HeapBlock.That would entail some work to tie-up refcounts and bigint internal array, but it sounds interesting.3. Or refcounts can be kept in a freelist.Doubtful. That would amount to extra pointer stored per BigInt AND extra indirection to get at ref-count unless I'm missing the details completely.So refounting can be helped by an allocator built especially for it.Agreed. BTW AffixAllocator is quite a feat, I think I wanted it countless times while working on std.regex/std.uni. I expect massive code performance and clarity improvements when {core,std}.allocator comes in.Andrei-- Dmitry Olshansky
Oct 30 2013
On Tuesday, 29 October 2013 at 21:59:38 UTC, Joseph Rushton Wakeling wrote:On 29/10/13 15:58, Dmitry Olshansky wrote:Implement a pool of bigints as an allocator: when refcount reaches zero, return the bigint buffer to the pool - a simple bump the pointer algorithm, when you need a new buffer, request it from the pool. A pool is a stack with fixed capacity, and buffers go in and out.Can't it use ref-counted COW? Then since there is only 1 reference to the original block it may mutate it in-place else it creates new chunk with refs=1 and decrements the original count. Maybe I'm missing something but it shouldn't be that hard.Yes, that's pretty much what I was thinking of. The question is how to implement it in terms of std.allocator -- or is that the wrong base to build ref=counted memory upon?
Oct 30 2013