Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unsafe C# trick to improve speed

Tags:

c#

unsafe

I am not used to code with pointers (e.g. C++), nor with unsafe islands: only "safe" C#. Now I'd like to implement a function in C# for the .Net Micro Framework, where the compactness and the performance are very important. Basically, I would to collect 4-ples of shorts and thus fill a buffer (e.g. byte-array). Let's say that every sample is such:

struct MyStruct
{
    public short An1;
    public short An2;
    public short An3;
    public short An4;
}

Each sample is collected via a timer-event, so that I can't loop (there are several reasons). I have tries many way to efficiently do that, but the most performing seems to be this one:

unsafe struct MyStruct2
{
    public fixed byte Buffer[Program.BufferSize];
}


unsafe class Program
{
    public const int BufferSize = 0x1000;
    public const int ArraySize = BufferSize / 8;

    static MyStruct2 _struct2 = new MyStruct2();
    static MyStruct* _structPtr;


    unsafe static void Main(string[] args)
    {
        int iter = 5000;  //just for simulate many cycles

        for (int i = 0; i < iter; i++)
        {
            //let's make a trick!
            fixed (byte* ptr = _struct2.Buffer)
                _structPtr = (MyStruct*)ptr;

            _structIndex = 0;
            do
            {
                Test5();
            } while (++_structIndex < ArraySize);
        }


        Console.ReadKey();
    }


    unsafe static void Test5()
    {
        _structPtr->An1 = (short)An1();
        _structPtr->An2 = (short)An2();
        _structPtr->An3 = (short)An3();
        _structPtr->An4 = (short)An4();
        _structPtr++;
    }


    //simulations of ADC reading
    static int An1()
    {
        return 0x1111;
    }

    static int An2()
    {
        return 0x2222;
    }

    static int An3()
    {
        return 0x3333;
    }

    static int An4()
    {
        return 0x4444;
    }
}

The improvement over this following safer way -for example- is not so high (177ms vs 224ms), but it is significant anyway.

    static MyStruct Test3()
    {
        var data = new MyStruct();
        data.An1 = (short)An1();
        data.An2 = (short)An2();
        data.An3 = (short)An3();
        data.An4 = (short)An4();
        return data;
    }

Note: I have cut some code, but I think it's clear enough.

My question is: the "trick" I have made by copying the "fixed" pointer to another unfixed could be reliable or not?...However you can assume that all the data is statically allocated, so should be pinned. Thank you in advance. Cheers

like image 876
Mario Vernari Avatar asked Mar 14 '11 17:03

Mario Vernari


People also ask

What is unsafe code C?

Unsafe code in C# is the part of the program that runs outside the control of the Common Language Runtime (CLR) of the . NET frameworks. The CLR is responsible for all of the background tasks that the programmer doesn't have to worry about like memory allocation and release, managing stack etc.

What does unsafe mean in programming?

What Does Unsafe Mean? Unsafe is a C programming language (C#) keyword used to denote a section of code that is not managed by the Common Language Runtime (CLR) of the . NET Framework, or unmanaged code. Unsafe is used in the declaration of a type or member or to specify block code.

Why is C not memory safe?

For example, Java is said to be memory-safe because its runtime error detection checks array bounds and pointer dereferences. In contrast, C and C++ allow arbitrary pointer arithmetic with pointers implemented as direct memory addresses with no provision for bounds checking, and thus are potentially memory-unsafe.

What is type unsafe language?

On the other hand, a type unsafe language would allow the insertion of int to a char variable by overwriting existing data in 3 more adjacent bytes of memory. This way, we'll get undefined behavior in our program when other components try to interpret the adjacent three memory locations.


1 Answers

I don't think the code is safe. After _structPtr = (MyStruct*)ptr which is within the fixed scope, you then go on to put data into _structPtr on the assumption that _struct2 won't move. Whilst you are correct that it won't be GCed, that doesn't mean that the GC won't move it during memory compaction. The .NET Compact Framework still garbage collects, and I assume it compacts memory rather than leaving it fragmented.

If, for instance, a transient (non static) object allocated on the heap prior to _struct2 is removed by the GC then the memory in use by that struct may be shifted into the free space used by that transient object. At that point _structPtr is pointing to unused memory.

Would modifying Test3() to take a ref MyStruct data help?

Also, checkout [StructLayout(LayoutKind.Explicit)] and [FieldOffset(...)] which will allow you to have a single struct with multiple ways of accessing the same data within it. In your case either as 4 bytes or 1 int or (possibly) 1 array of 4 bytes.

like image 53
Josh Gallagher Avatar answered Sep 24 '22 16:09

Josh Gallagher