Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

347
Visualizações
Cadena SIMD para análisis int sin firmar en la mejora del rendimiento de C#

Implementé un método para analizar una cadena de enteros sin signo de longitud <= 8 usando los intrínsecos SIMD disponibles en .NET de la siguiente manera:

 public unsafe static uint ParseUint(string text) { fixed (char* c = text) { var parsed = Sse3.LoadDquVector128((byte*) c); var shift = (8 - text.Length) * 2; var shifted = Sse2.ShiftLeftLogical128BitLane(parsed, (byte) (shift)); Vector128<byte> digit0 = Vector128.Create((byte) '0'); var reduced = Sse2.SubtractSaturate(shifted, digit0); var shortMult = Vector128.Create(10, 1, 10, 1, 10, 1, 10, 1); var collapsed2 = Sse2.MultiplyAddAdjacent(reduced.As<byte, short>(), shortMult); var repack = Sse41.PackUnsignedSaturate(collapsed2, collapsed2); var intMult = Vector128.Create((short)0, 0, 0, 0, 100, 1, 100, 1); var collapsed3 = Sse2.MultiplyAddAdjacent(repack.As<ushort,short>(), intMult); var e1 = collapsed3.GetElement(2); var e2 = collapsed3.GetElement(3); return (uint) (e1 * 10000 + e2); } }

Lamentablemente, una comparación con una línea de base uint.Parse() da el siguiente resultado, bastante poco impresionante:

Método Significar Error Desv.estándar
Base 15.157 ns 0,0325 ns 0,0304 ns
ParseSimd 3.269 ns 0,0115 ns 0,0102 ns

¿Cuáles son algunas de las formas en que se puede mejorar el código anterior? Mis áreas particulares de preocupación son:

  • La forma en que ocurre un cambio de bit del registro SIMD con un cálculo que involucra text.Length
  • ~~El desempaquetado de datos UTF-16 usando un MultiplyAddAdjacent que involucra un vector de 0 s y 1 ~~
  • La forma en que se extraen los elementos usando GetElement() -- ¿quizás haya alguna llamada a ToScalar() que pueda ocurrir en algún lugar?
over 4 years ago · Santiago Trujillo
1 Respostas
Responde à pergunta

0

En primer lugar, la mejora de 5x no es "bastante poco impresionante".

No haría el último paso con código escalar, aquí hay una alternativa:

 // _mm_shuffle_epi32( x, _MM_SHUFFLE( 3, 3, 2, 2 ) ) collapsed3 = Sse2.Shuffle( collapsed3, 0xFA ); // _mm_mul_epu32 var collapsed4 = Sse2.Multiply( collapsed3.As<int, uint>(), Vector128.Create( 10000u, 0, 1, 0 ) ).As<ulong, uint>(); // _mm_add_epi32( x, _mm_srli_si128( x, 8 ) ) collapsed4 = Sse2.Add( collapsed4, Sse2.ShiftRightLogical128BitLane( collapsed4, 8 ) ); return collapsed4.GetElement( 0 );

La versión C++ será mucho más rápida que lo que sucede en mi PC (.NET Core 3.1). El código generado no es bueno. Ellos inicializan constantes como esta:

 00007FFAD10B11B6 xor ecx,ecx 00007FFAD10B11B8 mov dword ptr [rsp+20h],ecx 00007FFAD10B11BC mov dword ptr [rsp+28h],64h 00007FFAD10B11C4 mov dword ptr [rsp+30h],1 00007FFAD10B11CC mov dword ptr [rsp+38h],64h 00007FFAD10B11D4 mov dword ptr [rsp+40h],1

Usan memoria de pila en lugar de otro registro vectorial. Parece que los desarrolladores de JIT olvidaron que hay 16 registros vectoriales allí, la función completa solo usa xmm0 .

 00007FFAD10B1230 vmovapd xmmword ptr [rbp-0C0h],xmm0 00007FFAD10B1238 vmovapd xmm0,xmmword ptr [rbp-0C0h] 00007FFAD10B1240 vpsrldq xmm0,xmm0,8 00007FFAD10B1245 vpaddd xmm0,xmm0,xmmword ptr [rbp-0C0h]
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda