Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

354
Vistas
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 Respuestas
Responde la pregunta

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 Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda