Optimización del código SSE

Actualmente estoy desarrollando un módulo C para una aplicación Java que necesita algunas mejoras de rendimiento (consulte Mejora del rendimiento de la encoding de encoding de red para un segundo plano). He intentado optimizar el código usando SSE-intrinsics y se ejecuta algo más rápido que la versión de Java (~ 20%). Sin embargo, todavía no es lo suficientemente rápido.

Desafortunadamente mi experiencia con la optimización del código C es algo limitada. Por lo tanto, me encantaría obtener algunas ideas sobre cómo mejorar la implementación actual.

El bucle interno que constituye el punto caliente se ve así:

for (i = 0; i < numberOfGFVectorsInFragment; i++) { // Load the 4 GF-elements from the message-fragment and add the log of the coefficeint to them. __m128i currentMessageFragmentVector = _mm_load_si128 (currentMessageFragmentPtr); __m128i currentEncodedResult = _mm_load_si128(encodedFragmentResultArray); __m128i logSumVector = _mm_add_epi32(coefficientLogValueVector, currentMessageFragmentVector); __m128i updatedResultVector = _mm_xor_si128(currentEncodedResult, valuesToXor); _mm_store_si128(encodedFragmentResultArray, updatedResultVector); encodedFragmentResultArray++; currentMessageFragmentPtr++; } 

Incluso sin mirar el ensamblaje, puedo decir de inmediato que el cuello de botella proviene del acceso a la memoria de la recostackción de 4 elementos y de las operaciones de embalaje _mm_set_epi32 . Internamente, _mm_set_epi32 , en su caso, probablemente se implementará como una serie de unpacklo/hi de unpacklo/hi .

La mayor parte del “trabajo” en este bucle proviene de empaquetar estos 4 accesos de memoria. En ausencia de SSE4.1, me atrevería a decir que el bucle podría ser más rápido no vectorizado, pero desenrollado.

Si estás dispuesto a usar SSE4.1, puedes probar esto. Podría ser más rápido, no podría:

  int* logSumArray = (int*)(&logSumVector); __m128i valuesToXor = _mm_cvtsi32_si128(expTable[*(logSumArray++)]); valuesToXor = _mm_insert_epi32(valuesToXor, expTable[*(logSumArray++)], 1); valuesToXor = _mm_insert_epi32(valuesToXor, expTable[*(logSumArray++)], 2); valuesToXor = _mm_insert_epi32(valuesToXor, expTable[*(logSumArray++)], 3); 

Sugiero desenrollar el bucle al menos 4 iteraciones e intercalar todas las instrucciones para dar a este código la posibilidad de un buen desempeño.

Lo que realmente necesita son las instrucciones de recostackción / dispersión AVX2 de Intel. Pero eso es un par de años en el camino …

Tal vez intente http://web.eecs.utk.edu/~plank/plank/papers/CS-07-593/ . Las funciones con “región” en sus nombres son supuestamente rápidas. Parece que no usan ningún tipo de conjuntos de instrucciones especiales, pero tal vez hayan sido optimizados de otras maneras …