2015-02-12 5 views
1

Бенчмаркинг следующего на удивление дает лучшие результаты для управляемых массивов (на 10% быстрее, последовательно). Я тестирую в Unity, так что, возможно, это относится к Mono?C# (Mono), управляемый против неуправляемых массивов: управляемость эталоном?

unsafe void Bench() 
{ 
    //Locals 
    int i, j; 
    const int bufSize   = 1024 * 1024; 
    const int numIterations = 1000; 
    const float gain   = 1.6745f; 

    float[] managedBuffer; 

    IntPtr ptr; 
    float * unmanagedBuffer; 

    Stopwatch stopwatch; 

    // Allocations 
    managedBuffer = new float[ bufSize ]; 
    for(i = 0; i < bufSize; i++) 
    { 
     managedBuffer[ i ] = UnityEngine.Random.value; 
    } 

    ptr    = Marshal.AllocHGlobal(bufSize * sizeof(float)); 
    unmanagedBuffer = (float *)ptr.ToPointer(); 

    Marshal.Copy(managedBuffer, 0, ptr, bufSize); 

    stopwatch = new Stopwatch(); 
    stopwatch.Start(); 

    // Unmanaged array iterations 
    for(i = 0; i < numIterations; i++) 
    { 
     for(j = 0; j < bufSize; j++) 
     { 
      unmanagedBuffer[ j ] *= gain; 
     } 
    } 

    UnityEngine.Debug.Log(stopwatch.ElapsedMilliseconds); 

    stopwatch.Reset(); 
    stopwatch.Start(); 

    // Managed array iterations 
    for(i = 0; i < numIterations; i++) 
    { 
     for(j = 0; j < bufSize; j++) 
     { 
      managedBuffer[ j ] *= gain; 
     } 
    } 

    UnityEngine.Debug.Log(stopwatch.ElapsedMilliseconds); 

    Marshal.FreeHGlobal(ptr); 
} 

Я экспериментирую с небезопасным кодом для аудио приложения, которое является весьма критичным для производительности. Я надеюсь увеличить производительность и уменьшить/устранить сбор мусора.

Любое понимание оценено!

+0

Бенчмаркинг является сложным искусство, легко сделать ошибки и заметны небольшие различия в машинных кодах. Различия менее 15% не являются статистически значимыми. Назовите этот код не менее 10 раз, ниже * numIterations *, так что вам не нужно так долго ждать. Обратите внимание на значительное изменение результатов. Когда я пытаюсь использовать .NET, код работает с одинаковой скоростью. Как это должно. –

ответ

0

Не совсем ответ, но требуется больше места, чем комментарий.

Если вы используете ILSpy наблюдать IL-код, то разница в том (выпуск, настройки по умолчанию, мой компьютер: Windows 7 64):

 // unmanaged   
     IL_005a: ldloc.s unmanagedBuffer 
     IL_005c: ldloc.1 
     IL_005d: conv.i 
     IL_005e: ldc.i4.4 
     IL_005f: mul 
     IL_0060: add 
     IL_0061: dup 
     IL_0062: ldind.r4 
     IL_0063: ldc.r4 1.6745 
     IL_0068: mul 
     IL_0069: stind.r4 
     IL_006a: ldloc.1 
     IL_006b: ldc.i4.1 
     IL_006c: add 
     IL_006d: stloc.1 

     // managed 
     IL_00a4: ldloc.2 
     IL_00a5: ldloc.1 
     IL_00a6: ldelema [mscorlib]System.Single 
     IL_00ab: dup 
     IL_00ac: ldobj [mscorlib]System.Single 
     IL_00b1: ldc.r4 1.6745 
     IL_00b6: mul 
     IL_00b7: stobj [mscorlib]System.Single 
     IL_00bc: ldloc.1 
     IL_00bd: ldc.i4.1 
     IL_00be: add 
     IL_00bf: stloc.1 

Я не знаю, сколько машинный код соответствует каждому IL но это может быть проблема оптимизации (см., сколько работы требуется для расчета индекса в случае неуправляемого буфера).


я заметил нелинейную корреляцию между числом итераций и времени:

Первый столбец numIterations, вторая unamanged времени (мс), последний - удалось времени (мс) ,

До 170 это не линейное, а затем что-то начинает происходить (пренебрегает прироста, на экране 10, я попытался 5 она также хорошо до 170). Это меня задевает, и я действительно хочу получить реальный ответ.

+0

Просто попробовал арифметику указателя вместо индексатора при повторении по неуправляемому массиву, это еще хуже ... – Gregzo

0

Не ответ, но мне нужно пространство. Используя C# nad VS13, я увидел другую сборку для умножения.

неуправляемого

00007FFC013555D9 movsxd  rcx,dword ptr [rbp+0D8h] 
00007FFC013555E0 mov   rax,qword ptr [rbp+0C0h] 
00007FFC013555E7 lea   rax,[rax+rcx*4] 
00007FFC013555EB mov   qword ptr [rbp+50h],rax 
00007FFC013555EF mov   rax,qword ptr [rbp+50h] 
00007FFC013555F3 movss  xmm0,dword ptr [7FFC013558A0h] 
00007FFC013555FB mulss  xmm0,dword ptr [rax] 
00007FFC013555FF mov   rax,qword ptr [rbp+50h] 
00007FFC01355603 movss  dword ptr [rax],xmm0 

УДАЛСЯ

00007FFC01355722 movsxd  rcx,dword ptr [rbp+0D8h] 
00007FFC01355729 mov   rax,qword ptr [rbp+0D0h] 
00007FFC01355730 mov   rax,qword ptr [rax+8] 
00007FFC01355734 mov   qword ptr [rbp+78h],rcx 
00007FFC01355738 cmp   qword ptr [rbp+78h],rax 
00007FFC0135573C jae   00007FFC01355748 
00007FFC0135573E mov   rax,qword ptr [rbp+78h] 
00007FFC01355742 mov   qword ptr [rbp+78h],rax 
00007FFC01355746 jmp   00007FFC0135574D 
00007FFC01355748 call  00007FFC60E86590 
00007FFC0135574D mov   rcx,qword ptr [rbp+0D0h] 
00007FFC01355754 mov   rax,qword ptr [rbp+78h] 
00007FFC01355758 lea   rax,[rcx+rax*4+10h] 
00007FFC0135575D mov   qword ptr [rbp+80h],rax 
00007FFC01355764 mov   rax,qword ptr [rbp+80h] 
00007FFC0135576B movss  xmm0,dword ptr [7FFC013558A0h] 
00007FFC01355773 mulss  xmm0,dword ptr [rax] 
00007FFC01355777 mov   rax,qword ptr [rbp+80h] 
00007FFC0135577E movss  dword ptr [rax],xmm0 

Очевидно, что большой код медленного выполнения ...