0

Im learning how to use C++ DLLs in C# and made a a c++ function that multiplies two allocated (Marshalled) set of variables. Everything works well in both C# and C++ until I increase the combined size of allocations to 1024 from 512MB. Then visual C# gives error of "protected memory access violation".The source of this is the dll function which fills the buffer with floats. The limit must be something between 512MB and 1024MB. Marshal.alloc accepts only int-sized buffer length so there is actually 2GB limit per allocation but when I try smaller chunks to get past the limit, gives same error.

Question: Is there any directbytebuffer equivalent that is not capped/limited in C# ? Or am I doing some simple pointer error?

Both dll and main projects are 64 bit targeted and can use more than 5-6 GB memory with ordinary arrays.

Here is the c++ function that writes to the buffer:

__declspec(dllexport) void floatOne(long av, int n)
    {
        float * vektor1=(float *)av; 
        _mm256_zeroall();
        __m256 r0=_mm256_setr_ps(1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f);

        for(int i=0;i<n;i+=8)
        {

            _mm256_store_ps(vektor1+i, r0); 

        }
        _mm256_zeroall();
        return;
    }

Here is how its used in C#:

public void one()
        {
            floatOne(bufferAdr.ToInt64() + offset, N);
            // offset here is the properly aligned address to start usage
            // N is private variable of vektor class (vector length) 
        }

Here is how allocation is:

 public vektor(int n /* number of elements*/, int a /* alignmentı*/)
        {
            N = n;
            bufferAdr = Marshal.AllocHGlobal(4*n + 4*a);
            //a-1 was enough but I put a*4 to be sure it doesnt overflow.
            offset = (a - bufferAdr.ToInt64() % a);
        }

Here is the DLL importing:

[DllImport("cpuKullanim.dll", EntryPoint = "floatOne")]
        public static extern void floatOne(long adres1, int n);

Tested RAM of any hardware errors but passed mem tests so there must be a software issue.

Thanks.

windows7-64 bit, cpu 64 bit, target machine 64bit for both projects.

huseyin tugrul buyukisik
  • 11,469
  • 4
  • 45
  • 97
  • So why exactly are you using `Marshal.AllocHGlobal` for this? I'm unsure why you're trying to do this unsafe, can you elaborate on what exactly you are trying to do a bit more? What should the results be, etc. – aevitas Jul 20 '13 at 22:05
  • @aevitas To allocate space as large buffer for dot product function and matrix multiplication. This is faster than Parallel.For version with reduction on ordinary arrays.(6-7 times as fast) It was working perfect on java but Im trying to do same within C#. – huseyin tugrul buyukisik Jul 20 '13 at 22:09
  • Are you getting an `OutOfMemoryException`? – aevitas Jul 20 '13 at 22:11
  • No, memory access violation error. From the c++ function that uses the intrinsic to write on memory. – huseyin tugrul buyukisik Jul 20 '13 at 22:13
  • Looks to me like `offset = (a - bufferAdr.ToInt64() % a);` evaluates to a negative value or something and that's causing your `AccessViolationException`. Put a breakpoint on it while debugging and see what the actual result of that equation is. If you'd under-allocate, you'd get a different exception. – aevitas Jul 20 '13 at 22:19
  • But a is always bigger than buffrAdr % a. – huseyin tugrul buyukisik Jul 20 '13 at 22:24
  • What does the debugger say? Did you step through and check the values of all variables? Are they what you expect? – usr Jul 20 '13 at 22:30
  • Not always. If I allocate 100 bytes using `AllocHGlobal`, I get a pointer to a piece of allocated memory, if I assume *10* for A - just guessing since there's no way to tell from the code you've posted what you are actually passing - and I use the equation in your code, the resulting `offset` will 4/5 times be smaller than `a`. You'll need to give us more to work with if you want a proper answer to this. Your `offset` value is not what it should be, I'm pretty sure of that. – aevitas Jul 20 '13 at 22:30
  • Im using like baseAddress+offset to point the start of aligned access and a is 32 here for avx intrinsics, so it points somewhere between baseaddress and base+32 which is aligned. – huseyin tugrul buyukisik Jul 20 '13 at 22:34

1 Answers1

3
  __declspec(dllexport) void floatOne(long av, int n)

This is a serious bug in your code, the long type is 32-bits in 64-bit mode when compiled with MSVC. That isn't big enough to store a pointer. It will work by accident until you start allocating bigger chunks of memory. The proper argument type for "av" is a pointer type, at least void*. Of course there's no reason to avoid just declaring it float*. Code always work better if you don't try to fool the compiler. You must declare it as IntPtr in your C# code.

What you are trying to do with the alignment is quite inscrutable. The requirement is that the address is aligned to a multiple of 16 for SSE2 code. You could use this helper method:

    static IntPtr AlignAddressForSSE2(IntPtr addr) {
        return new IntPtr((addr.ToInt64() + 15) & unchecked((long)0xfffffffffffffff0L));
    }

Also add 15 to the Marshal.AllocHGlobal() argument (8 is enough actually). Or simply export two functions from your DLL that take care of this by using _aligned_malloc() and _aligned_free().

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Thank you very much, this solved my bug. Using (void *) in DLL and using IntPtr in C#. I also tried malloc/free wrapper to see how it works but malloc did not allocate(or it wasnt showing in windows manager) for some reason but worked fine and free worked fine also without any warnings. – huseyin tugrul buyukisik Jul 21 '13 at 11:47