GC allocation issue

2014-03-20 Thread Etienne
I'm running some tests on a cache store where I planned to use only 
Malloc for the values being stored, I'm hoping to eliminate the GC in 
95% of the program, but to keep it only for actively used items..


My problem is: when the program reaches 40MB it suddenly goes down to 
0.9MB and blocks.


From every resource I've read, the understanding that came out is that 
the GC will stop all threads and search for pointers for data that was 
allocated only by the GC (using addRange or addRoot to extend its 
reach). This means that in the worst case scenario, there could be 
leaks, but I'm seeing the data being deleted by the GC so I'm a little 
stomped here. What am I missing?


I'm using FreeListAlloc from here:
https://github.com/rejectedsoftware/vibe.d/blob/master/source/vibe/utils/memory.d#L152
in here:
https://github.com/globecsys/cache.d/blob/master/chd/table.d#L1087
and this is how I made it crash:
https://github.com/globecsys/cache.d/blob/master/chd/connection.d#L550

I know it's the GC because using GC.disable() fixes it, so I'm only 
really asking if the GC has a habit of deleting mallocated data like this.


Re: GC allocation issue

2014-03-20 Thread Rene Zwanenburg

On Thursday, 20 March 2014 at 20:48:18 UTC, Etienne wrote:
I'm running some tests on a cache store where I planned to use 
only Malloc for the values being stored, I'm hoping to 
eliminate the GC in 95% of the program, but to keep it only for 
actively used items..


My problem is: when the program reaches 40MB it suddenly goes 
down to 0.9MB and blocks.


From every resource I've read, the understanding that came out 
is that the GC will stop all threads and search for pointers 
for data that was allocated only by the GC (using addRange or 
addRoot to extend its reach). This means that in the worst case 
scenario, there could be leaks, but I'm seeing the data being 
deleted by the GC so I'm a little stomped here. What am I 
missing?


I'm using FreeListAlloc from here:
https://github.com/rejectedsoftware/vibe.d/blob/master/source/vibe/utils/memory.d#L152
in here:
https://github.com/globecsys/cache.d/blob/master/chd/table.d#L1087
and this is how I made it crash:
https://github.com/globecsys/cache.d/blob/master/chd/connection.d#L550

I know it's the GC because using GC.disable() fixes it, so I'm 
only really asking if the GC has a habit of deleting mallocated 
data like this.


The strings returned by to!string are owned by the GC. Since the 
GC doesn't scan malloc'ed memory, the GC thinks all your 'values' 
are unreferenced. The keys are still referenced in the keys array.


So, it's GC-owned memory referenced only through malloc'ed memory 
that is being freed. Not the malloc'ed memory itself.


Also, not relevant for your current problem, but keep in mind 
that structs defined inside a function will have access to the 
function's locals. To avoid corruption when the function returns 
the stack frame will be allocated on the GC heap when an instance 
is created. Make your 'A' struct static to avoid this.


Re: GC allocation issue

2014-03-20 Thread bearophile

Etienne:

I'm running some tests on a cache store where I planned to use 
only Malloc for the values being stored, I'm hoping to 
eliminate the GC in 95% of the program, but to keep it only for 
actively used items..


Usually 95%-100% of a D program uses the GC and the 0%-5% uses 
malloc :-)


Bye,
bearophile


Re: GC allocation issue

2014-03-20 Thread Etienne

On 2014-03-20 8:39 PM, bearophile wrote:

Etienne:


I'm running some tests on a cache store where I planned to use only
Malloc for the values being stored, I'm hoping to eliminate the GC in
95% of the program, but to keep it only for actively used items..


Usually 95%-100% of a D program uses the GC and the 0%-5% uses malloc :-)

Bye,
bearophile


I'm trying to store a copy of strings for long-running processes with 
malloc. I tried using emplace but the copy gets deleted by the GC. Any 
idea why?


Re: GC allocation issue

2014-03-20 Thread Adam D. Ruppe

On Friday, 21 March 2014 at 00:56:22 UTC, Etienne wrote:
I tried using emplace but the copy gets deleted by the GC. Any 
idea why?


That's extremely unlikely, the GC doesn't know how to free 
manually allocated things. Are you sure that's where the crash 
happens?


Taking a really quick look at your code, this line raises a red 
flag:

https://github.com/globecsys/cache.d/blob/master/chd/table.d#L55

Class destructors in D aren't allowed to reference GC allocated 
memory through their members. Accessing that string in the dtor 
could be a problem that goes away with GC.disable too.


Re: GC allocation issue

2014-03-20 Thread Etienne Cimon

On 2014-03-20 21:08, Adam D. Ruppe wrote:

On Friday, 21 March 2014 at 00:56:22 UTC, Etienne wrote:

I tried using emplace but the copy gets deleted by the GC. Any idea why?


That's extremely unlikely, the GC doesn't know how to free manually
allocated things. Are you sure that's where the crash happens?

Taking a really quick look at your code, this line raises a red flag:
https://github.com/globecsys/cache.d/blob/master/chd/table.d#L55

Class destructors in D aren't allowed to reference GC allocated memory
through their members. Accessing that string in the dtor could be a
problem that goes away with GC.disable too.


Yes, you're right I may have a lack of understanding about destructors, 
I'll review this. I managed to generate a VisualD projet and the 
debugger confirms the program crashes on the GC b/c it has a random call 
stack for everything under fullcollect().


cache-d_d.exe!gc@gc@Gcx@mark() C++
cache-d_d.exe!gc@gc@Gcx@fullcollect()  C++
> 
cache-d_d.exe!std@array@Appender!string@Appender@ensureAddable(unsigned 
int this) Line 2389	C++

[External Code] 

cache-d_d.exe!std@array@Appender!string@Appender@ensureAddable(unsigned 
int this) Line 2383	C++




I have no methodology for debugging under these circumstances, do you 
know of anything else I can do than manually review the pathways in the 
source code?


Re: GC allocation issue

2014-03-20 Thread Etienne Cimon

On 2014-03-20 21:46, Etienne Cimon wrote:

On 2014-03-20 21:08, Adam D. Ruppe wrote:

On Friday, 21 March 2014 at 00:56:22 UTC, Etienne wrote:

I tried using emplace but the copy gets deleted by the GC. Any idea why?


That's extremely unlikely, the GC doesn't know how to free manually
allocated things. Are you sure that's where the crash happens?

Taking a really quick look at your code, this line raises a red flag:
https://github.com/globecsys/cache.d/blob/master/chd/table.d#L55

Class destructors in D aren't allowed to reference GC allocated memory
through their members. Accessing that string in the dtor could be a
problem that goes away with GC.disable too.


Yes, you're right I may have a lack of understanding about destructors,
I'll review this. I managed to generate a VisualD projet and the
debugger confirms the program crashes on the GC b/c it has a random call
stack for everything under fullcollect().

  cache-d_d.exe!gc@gc@Gcx@mark()C++
  cache-d_d.exe!gc@gc@Gcx@fullcollect()C++
 >
cache-d_d.exe!std@array@Appender!string@Appender@ensureAddable(unsigned
int this) Line 2389C++
  [External Code]

cache-d_d.exe!std@array@Appender!string@Appender@ensureAddable(unsigned
int this) Line 2383C++



I have no methodology for debugging under these circumstances, do you
know of anything else I can do than manually review the pathways in the
source code?


It seems to be crashing somewhere here in druntime's gc.d :

void mark(void *pbot, void *ptop, int nRecurse)
{
//import core.stdc.stdio;printf("nRecurse = %d\n", nRecurse);
void **p1 = cast(void **)pbot;
void **p2 = cast(void **)ptop;

Considering it's an access violation of a root that was probably added 
by phobos, could this be an issue with these libraries?


Re: GC allocation issue

2014-03-20 Thread monarch_dodra

On Friday, 21 March 2014 at 00:56:22 UTC, Etienne wrote:
I'm trying to store a copy of strings for long-running 
processes with malloc. I tried using emplace but the copy gets 
deleted by the GC. Any idea why?


Could you show the snippet where you used "emplace"? I'd like to 
know how you are using it. In particular, where you are 
emplacing, and *what*: the slice, or the slice contents?


Re: GC allocation issue

2014-03-21 Thread Etienne

On 2014-03-21 2:53 AM, monarch_dodra wrote:

On Friday, 21 March 2014 at 00:56:22 UTC, Etienne wrote:

I'm trying to store a copy of strings for long-running processes with
malloc. I tried using emplace but the copy gets deleted by the GC. Any
idea why?


Could you show the snippet where you used "emplace"? I'd like to know
how you are using it. In particular, where you are emplacing, and
*what*: the slice, or the slice contents?


https://github.com/globecsys/cache.d/blob/master/chd/table.d#L1089
This line does the copying

I don't think it's the memory copying algorithm anymore however. The GC 
crashes altogether during fullcollect(), the logs give me this:


>	cache-d_d.exe!gc@gc@Gcx@mark(void * this, void * nRecurse, int ptop) 
Line 2266	C++

cache-d_d.exe!gc@gc@Gcx@mark(void * this, void * ptop) Line 2249
C++
cache-d_d.exe!gc@gc@Gcx@fullcollect() Line 2454 C++
 	cache-d_d.exe!gc@gc@GC@mallocNoSync(unsigned int this, unsigned int 
alloc_size, unsigned int * alloc_size) Line 458	C++
 	cache-d_d.exe!gc@gc@GC@malloc(unsigned int this, unsigned int 
alloc_size, unsigned int * bits) Line 413	C++

...


With ptop= 03D8F030, pbot= 03E4F030

They both point invalid memory. It looks like a really wide range too, 
the usual would be 037CCB80 -> 037CCBA0 or such. I don't know how to 
find out where they come from... Maybe I could do an assert on that 
specific value in druntime


Re: GC allocation issue

2014-03-21 Thread Etienne

On 2014-03-21 9:36 AM, Etienne wrote:

With ptop= 03D8F030, pbot= 03E4F030

They both point invalid memory. It looks like a really wide range too,
the usual would be 037CCB80 -> 037CCBA0 or such. I don't know how to
find out where they come from... Maybe I could do an assert on that
specific value in druntime


Looks like the range of the string[] keys array, it gets pretty big 
after adding 1s of strings.


+GC.addRange(p = 03EA0AB0, sz = 0x38), p + sz = 03EA0AE8
set: 209499732595 => ¨98303126
+GC.addRange(p = 03EA0B40, sz = 0x38), p + sz = 03EA0B78
set: 6491851329 => ¨50107378
+GC.addRange(p = 03EA0BD0, sz = 0x38), p + sz = 03EA0C08
set: 262797465895 => ¨14438090
+GC.addRange(p = 03EA0C60, sz = 0x38), p + sz = 03EA0C98
set: 95992076217 => ¨65000864
+GC.addRange(p = 03EA0CF0, sz = 0x38), p + sz = 03EA0D28
+GC.addRange(p = 03EA0D50, sz = 0x3), p + sz = 03ED0D50

It crashes when sz approaches 0x18, it looks like (my best guess) 
the resized array doesn't get allocated but the GC still tries to scan it.


Re: GC allocation issue

2014-03-21 Thread Etienne

On 2014-03-21 10:34 AM, Etienne wrote:

It crashes when sz approaches 0x18, it looks like (my best guess)
the resized array doesn't get allocated but the GC still tries to scan it.


Ok I found it in the manual implementation of a malloc-based HashMap.

The right way to debug this was, sadly, to add a lot of printf and a few 
asserts in druntime, and redirecting the stdout to a file from the shell 
(./exe > logoutput.txt). The druntime win32.mak doesn't have a debug 
build so I had to add -debug -g in there to add symbols and make the 
sources show up instead of the disassembly in VisualD.


In this case, the logs showed gc's mark() was failing on wide ranges, so 
I added an assert in addRange to make it throw when that range was 
added, and it finally gave me the call stack of the culprit.


The issue was that a malloc range was (maybe) not being properly 
initialized before being added to the GC.


https://github.com/rejectedsoftware/vibe.d/blob/master/source/vibe/utils/hashmap.d#L221

https://github.com/rejectedsoftware/vibe.d/blob/master/source/vibe/utils/memory.d#L153

In this case, ptr isn't null and the range existed, but there's still an 
access violation from the GC for some reason. I'll keep searching for 
the root cause but it doesn't seem to be a GC issue anymore; though the 
debugging procedure could use some documentation.


Thanks