什么是C#固定语句含有固定阵列一个管理结构不安全的开销? [英] What is the overhead of C# fixed statement on a managed unsafe struct containing fixed arrays?

查看:114
本文介绍了什么是C#固定语句含有固定阵列一个管理结构不安全的开销?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在试图确定哪些使用C#中的固定语句包含固定阵列管理不安全结构的真实成本。请注意,我不是指非托管结构。

I've been trying to determine what the true cost of using the fixed statement within C# for managed unsafe structs that contain fixed arrays. Please note I am not referring to unmanaged structs.

具体而言,没有任何理由,以避免MultipleFixed下方所示类的格局?是简单的固定数据非零成本,接近零(==成本类似于设置,以及输入/出固定范围时,清除一个标志),或者是不够显著,以避免可能的时候?

Specifically, is there any reason to avoid the pattern shown by 'MultipleFixed' class below? Is the cost of simply fixing the data non zero, near zero (== cost similar to setting & clearing a single flag when entering/exiting the fixed scope), or is it significant enough to avoid when possible?

显然,这些类是人为的,以帮助解释的问题。这是在XNA游戏高使用率的数据结构,其中读取该数据/写性能是至关重要的,所以如果我需要修复的数组并传递给它到处,我会做,但如果在所有我没有什么区别倒是宁愿保持固定的()本地方法,以帮助保持函数签名稍微更容易移植到不支持不安全的代码平台。 (是的,它的一些额外的咕噜代码,但不惜一切代价。)

Obviously these classes are contrived to help explain the question. This is for a high usage data structure in an XNA game where read/write performance of this data is critical, so if I need to fix the array and pass it around everywhere I'll do that but if there is no difference at all I'd prefer to keep the fixed() local to the methods to help with keeping the function signatures slightly more portable to platforms that don't support unsafe code. (Yeah, its some extra grunt code but whatever it takes..)

 

    unsafe struct ByteArray
    {
       public fixed byte Data[1024];
    }

    class MultipleFixed
    {
       unsafe void SetValue(ref ByteArray bytes, int index, byte value)
       {
           fixed(byte* data = bytes.Data)
           {
               data[index] = value;
           }
       }

        unsafe bool Validate(ref ByteArray bytes, int index, byte expectedValue)
        {
           fixed(byte* data = bytes.Data)
           {
               return data[index] == expectedValue;
           }
        }

        void Test(ref ByteArray bytes)
        {
            SetValue(ref bytes, 0, 1);
            Validate(ref bytes, 0, 1);
        }
    }

    class SingleFixed
    {
       unsafe void SetValue(byte* data, int index, byte value)
       {
           data[index] = value;
       }

        unsafe bool Validate(byte* data, int index, byte expectedValue)
        {
           return data[index] == expectedValue;
        }

        unsafe void Test(ref ByteArray bytes)
        {
            fixed(byte* data = bytes.Data)
            {
                SetValue(data, 0, 1);
                Validate(data, 0, 1);
            }
        }
    }



另外,我找了类似的问题和最近我发现了时,但这个问题是因为它仅与纯托管代码和使用固定在这方面的具体费用有关不同

Also, I looked for similar questions and the closest I found was this, but this question is different in that it is concerned only with pure managed code and the specific costs of using fixed in that context.

感谢您的任何信息!

推荐答案

根据经验,开销似乎是,在最好的情况下,〜32位JIT和〜200 270% %在64位(与架空恶化的次数越多你呼固定)。所以我要尽量减少你的固定块如果性能是真正的关键。

Empirically, the overhead appears to be, in the best case, ~270% on 32 bit JIT and ~200% on 64 bit (and the overhead gets worse the more times you "call" fixed). So I'd try to minimise your fixed blocks if performance is really critical.

对不起,我不是固定/不安全的代码非常熟悉,知道为什么是这样的话

Sorry, I'm not familiar enough with fixed / unsafe code to know why that's the case

详细信息

我还添加了一些 TestMore 方法,它调用你的两种试验方法的10倍,而不是2
给出的多种方法更真实的场景被称为你的固定结构。

I also added some TestMore methods which call your two test methods 10 times instead of 2 to give a more real world scenario of multiple methods being called on your fixed struct.

我使用的代码:

class Program
{
    static void Main(string[] args)
    {
        var someData = new ByteArray();
        int iterations = 1000000000;
        var multiple = new MultipleFixed();
        var single = new SingleFixed();

        // Warmup.
        for (int i = 0; i < 100; i++)
        {
            multiple.Test(ref someData);
            single.Test(ref someData);
            multiple.TestMore(ref someData);
            single.TestMore(ref someData);
        }

        // Environment.
        if (Debugger.IsAttached)
            Console.WriteLine("Debugger is attached!!!!!!!!!! This run is invalid!");
        Console.WriteLine("CLR Version: " + Environment.Version);
        Console.WriteLine("Pointer size: {0} bytes", IntPtr.Size);
        Console.WriteLine("Iterations: " + iterations);

        Console.Write("Starting run for Single... ");
        var sw = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            single.Test(ref someData);
        }
        sw.Stop();
        Console.WriteLine("Completed in {0:N3}ms - {1:N2}/sec", sw.Elapsed.TotalMilliseconds, iterations / sw.Elapsed.TotalSeconds);

        Console.Write("Starting run for More Single... ");
        sw = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            single.Test(ref someData);
        }
        sw.Stop();
        Console.WriteLine("Completed in {0:N3}ms - {1:N2}/sec", sw.Elapsed.TotalMilliseconds, iterations / sw.Elapsed.TotalSeconds);


        Console.Write("Starting run for Multiple... ");
        sw = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            multiple.Test(ref someData);
        }
        sw.Stop();
        Console.WriteLine("Completed in {0:N3}ms - {1:N2}/sec", sw.Elapsed.TotalMilliseconds, iterations / sw.Elapsed.TotalSeconds);

        Console.Write("Starting run for More Multiple... ");
        sw = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            multiple.TestMore(ref someData);
        }
        sw.Stop();
        Console.WriteLine("Completed in {0:N3}ms - {1:N2}/sec", sw.Elapsed.TotalMilliseconds, iterations / sw.Elapsed.TotalSeconds);


        Console.ReadLine();
    }
}

unsafe struct ByteArray
{
    public fixed byte Data[1024];
}

class MultipleFixed
{
    unsafe void SetValue(ref ByteArray bytes, int index, byte value)
    {
        fixed (byte* data = bytes.Data)
        {
            data[index] = value;
        }
    }

    unsafe bool Validate(ref ByteArray bytes, int index, byte expectedValue)
    {
        fixed (byte* data = bytes.Data)
        {
            return data[index] == expectedValue;
        }
    }

    public void Test(ref ByteArray bytes)
    {
        SetValue(ref bytes, 0, 1);
        Validate(ref bytes, 0, 1);
    }
    public void TestMore(ref ByteArray bytes)
    {
        SetValue(ref bytes, 0, 1);
        Validate(ref bytes, 0, 1);
        SetValue(ref bytes, 0, 2);
        Validate(ref bytes, 0, 2);
        SetValue(ref bytes, 0, 3);
        Validate(ref bytes, 0, 3);
        SetValue(ref bytes, 0, 4);
        Validate(ref bytes, 0, 4);
        SetValue(ref bytes, 0, 5);
        Validate(ref bytes, 0, 5);
    }
}

class SingleFixed
{
    unsafe void SetValue(byte* data, int index, byte value)
    {
        data[index] = value;
    }

    unsafe bool Validate(byte* data, int index, byte expectedValue)
    {
        return data[index] == expectedValue;
    }

    public unsafe void Test(ref ByteArray bytes)
    {
        fixed (byte* data = bytes.Data)
        {
            SetValue(data, 0, 1);
            Validate(data, 0, 1);
        }
    }
    public unsafe void TestMore(ref ByteArray bytes)
    {
        fixed (byte* data = bytes.Data)
        {
            SetValue(data, 0, 1);
            Validate(data, 0, 1);
            SetValue(data, 0, 2);
            Validate(data, 0, 2);
            SetValue(data, 0, 3);
            Validate(data, 0, 3);
            SetValue(data, 0, 4);
            Validate(data, 0, 4);
            SetValue(data, 0, 5);
            Validate(data, 0, 5);
        }
    }
}

和.NET中的结果4.0,32位JIT:

And the results in .NET 4.0, 32 bit JIT:

CLR Version: 4.0.30319.239
Pointer size: 4 bytes
Iterations: 1000000000
Starting run for Single... Completed in 2,092.350ms - 477,931,580.94/sec
Starting run for More Single... Completed in 2,236.767ms - 447,073,934.63/sec
Starting run for Multiple... Completed in 5,775.922ms - 173,132,528.92/sec
Starting run for More Multiple... Completed in 26,637.862ms - 37,540,550.36/sec

和在.NET 4.0中,64位JIT:

And in .NET 4.0, 64 bit JIT:

CLR Version: 4.0.30319.239
Pointer size: 8 bytes
Iterations: 1000000000
Starting run for Single... Completed in 2,907.946ms - 343,885,316.72/sec
Starting run for More Single... Completed in 2,904.903ms - 344,245,585.63/sec
Starting run for Multiple... Completed in 5,754.893ms - 173,765,185.93/sec
Starting run for More Multiple... Completed in 18,679.593ms - 53,534,358.13/sec

这篇关于什么是C#固定语句含有固定阵列一个管理结构不安全的开销?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆