Почему установщики свойств индексатора не встроены? - PullRequest
2 голосов
/ 02 апреля 2019

У меня есть класс, который упаковывает неуправляемое выделение в массив.Вы можете увидеть источник здесь, на Github , но вот его основная суть:

public unsafe class ArrayReference<T> : Reference, IArrayReference<T>
  where T : unmanaged
{

  private T* typedPointer_;

  public T this[ int index ]
  {
    [MethodImpl( MethodImplOptions.AggressiveInlining )]
    get => typedPointer_[ index ];
    [MethodImpl( MethodImplOptions.AggressiveInlining )]
    set => typedPointer_[ index ] = value;
  }

}

Это довольно просто, а для операций чтения он обеспечивает высокую производительность (измеряется с помощью BenchmarkDotNet).):

Array size: 128
Managed byte[] ranged-for get: 69.8046 ns
ArrayReference ranged-for get: 66.7340 ns
Managed byte[] ranged-for set: 66.1855 ns
ArrayReference ranged-for set: 68.4863 ns

И код теста:

[GlobalSetup]
public void Setup()
{
  median = AllocationSize / 2;
  alloc_ = new Allocation( AllocationSize );
  array_ = new ArrayReference<byte>( alloc_.Address, AllocationSize );
  managedArray_ = new byte[ AllocationSize ];
}

[Benchmark]
public void ManagedArray_ranged_for_get()
{
  var counter = 0;
  for ( var i = 0; i < AllocationSize; i++ )
    counter += managedArray_[ i ];
}

[Benchmark]
public void ArrayReference_ranged_for_get()
{
  var counter = 0;
  for ( var i = 0; i < AllocationSize; i++ )
    counter += array_[ i ];
}

[Benchmark]
public void ManagedArray_ranged_for_set()
{
  for ( var i = 0; i < AllocationSize; i++ )
    managedArray_[ i ] = ( byte ) i;
}

[Benchmark]
public void ArrayReference_ranged_for_set()
{
  for ( var i = 0; i < AllocationSize; i++ )
    array_[ i ] = ( byte ) i;
}

Как видите, чтение с ArrayReference немного быстрее, поскольку оно не выполняет проверку диапазона и егоимеет прямой доступ к указателю массива.Однако запись медленнее в ArrayReference, чем в управляемом byte[] массиве , и похоже, что проблема заключается в том, что установщик не является встроенным.

JIT x86для управляемого байта [] set:

managedArray_[ median ] = 0;
00007FFA237A216C  mov         rax,qword ptr [rbp+10h]  
00007FFA237A2170  mov         rax,qword ptr [rax+18h]  
00007FFA237A2174  mov         rdx,qword ptr [rbp+10h]  
00007FFA237A2178  mov         edx,dword ptr [rdx+24h]  
00007FFA237A217B  cmp         rdx,qword ptr [rax+8]  
00007FFA237A217F  jb          00007FFA237A2186  
00007FFA237A2181  call        00007FFA833DF110  
00007FFA237A2186  lea         rax,[rax+rdx+10h]  
00007FFA237A218B  mov         byte ptr [rax],0  

JIT x86 для ArrayReference :: set:

typedPointer_[ index ] = value;
00007FFA237A20BC  mov         rcx,qword ptr [rbp+10h]  
00007FFA237A20C0  mov         rcx,qword ptr [rcx+10h]  
00007FFA237A20C4  mov         rdx,qword ptr [rbp+10h]  
00007FFA237A20C8  mov         edx,dword ptr [rdx+24h]  
00007FFA237A20CB  xor         r8d,r8d  
00007FFA237A20CE  cmp         dword ptr [rcx],ecx  
00007FFA237A20D0  call        00007FFA237A1738  
 -> 
    00007FFA237A20F0  push        rbp  
    00007FFA237A20F1  sub         rsp,20h  
    00007FFA237A20F5  lea         rbp,[rsp+20h]  
    00007FFA237A20FA  mov         qword ptr [rbp+10h],rcx  
    00007FFA237A20FE  mov         dword ptr [rbp+18h],edx  
    00007FFA237A2101  mov         dword ptr [rbp+20h],r8d  
    00007FFA237A2105  cmp         dword ptr [7FFA23688310h],0  
    00007FFA237A210C  je          00007FFA237A2113  
    00007FFA237A210E  call        00007FFA833DD3E0  
    00007FFA237A2113  mov         rax,qword ptr [rbp+10h]  
    00007FFA237A2117  mov         rax,qword ptr [rax+20h]  
    00007FFA237A211B  mov         edx,dword ptr [rbp+18h]  
    00007FFA237A211E  movsxd      rdx,edx  
    00007FFA237A2121  mov         ecx,1  
    00007FFA237A2126  movsxd      rcx,ecx  
    00007FFA237A2129  imul        rdx,rcx  
    00007FFA237A212D  mov         ecx,dword ptr [rbp+20h]  
    00007FFA237A2130  mov         byte ptr [rax+rdx],cl  

Я не понимаю, почему это не встраивается.Он делает то же самое, что и управляемый массив, за исключением указателя на неуправляемую память.Нарушает ли это одно из встроенных правил CLR или, возможно, оно не является встроенным, потому что T является общим, хотя и ограниченным?

Windows 10 Pro, 64-разрядная версия .Net Core 2.2, Release Mode 64Бит РюДЖИТ

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...