경험적으로 오버 헤드는 32 비트 JIT에서 ~ 270 %, 64 비트에서 ~ 200 %로 나타납니다. (오버 헤드는 fixed
을 "호출"하는 횟수가 많을수록 악화됩니다). 그래서 성능이 정말로 중요한 경우 귀하의 블록을 최소화하려고합니다.
미안 해요, 난 그
세부
나는 또한이 시험 방법 (10)를 호출 일부 TestMore
방법을 추가 한 경우의 이유를 알고 고정/안전하지 않은 코드에 충분히 익숙하지 해요 시간 대신 2 대신 fixed
구조체에서 호출되는 여러 메서드에 대한보다 실제적인 시나리오를 제공하십시오.
I가 사용되는 코드 :
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 :
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 :
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
감사합니다 - 좋은 정보! 오버 헤드의 근본적인 원인이 무엇인지 궁금해하지만 좋은 성과를 얻는 것이 주요 목표입니다. –
그래, 나는 "이유"에 대해 Skeet, Lippart 또는 Gravel에게 연기 할 것이다. 그러나 구조체의 크기를 가지고 놀면 런타임에서 구조체의 복사본을 각각 '고정 된'것으로 만드는 지 알 수 있습니다. 내 짐작은 피닝 작업이 전체 구조체를 복사한다는 것입니다. (참조 : http://www.dotnetperls.com/fixed-buffer) – ligos
이 테스트는 정확하지 않습니다. 완전히 비합리적인 방법으로 고침을 사용하고 있습니다. 올바른 사용법은 한 번 수정하여 여러 번 작성하고 수정하지 않는 것입니다. – JakeSays