.net - must - inline en matlab 2017
¿Por qué F#inline causa una mejora de rendimiento 11x (2)
Tipo de especialización
Sin inline
, estás usando una comparación genérica que es muy ineficiente. Con inline
, se elimina la genéricoidad y se usa la comparación int
directamente.
Estoy trabajando en un problema de cpu pesado pesado. Veo una gran mejora en el rendimiento cuando uso la palabra clave en inline
. Creo un diccionario de la biblioteca .net estándar que pasa en un comparador de clave personalizado. Vea el código y los resultados de tiempo a continuación.
https://gist.github.com/4409734
sin palabra clave en línea en Eq_cmp
> perf_run 10000000 ;;
Real: 00:00:11.039, CPU: 00:00:11.029, GC gen0: 771, gen1: 3, gen2: 1
val it : unit = ()
usando palabras clave en línea en Eq_cmp
perf_run 10000000 ;;
Real: 00:00:01.319, CPU: 00:00:01.388, GC gen0: 1, gen1: 1, gen2: 1
val it : unit = ()
>
También noté la gran diferencia en la cantidad de Gen 0 GC con el código en línea y el código sin línea.
¿Alguien podría explicar por qué hay una gran diferencia?
Puedo reproducir el comportamiento en mi máquina con un aumento de rendimiento 3x después de agregar una palabra clave en inline
.
La descompilación de dos versiones una al lado de otra bajo ILSpy proporciona un código C # casi idéntico. La notable diferencia está en dos pruebas de igualdad:
// Version without inline
bool IEqualityComparer<Program.Pair<a>>.System-Collections-Generic-IEqualityComparer(Program.Pair<a> x, Program.Pair<a> y)
{
a v@ = x.v@;
a v@2 = y.v@;
if (LanguagePrimitives.HashCompare.GenericEqualityIntrinsic<a>(v@, v@2))
{
a w@ = x.w@;
a w@2 = y.w@;
return LanguagePrimitives.HashCompare.GenericEqualityIntrinsic<a>(w@, w@2);
}
return false;
}
// Version with inline
bool IEqualityComparer<Program.Pair<int>>.System-Collections-Generic-IEqualityComparer(Program.Pair<int> x, Program.Pair<int> y)
{
int v@ = x.v@;
int v@2 = y.v@;
if (v@ == v@2)
{
int w@ = x.w@;
int w@2 = y.w@;
return w@ == w@2;
}
return false;
}
La igualdad genérica es mucho menos eficiente que la versión especializada.
También noté la gran diferencia en la cantidad de Gen 0 GC con el código en línea y el código sin línea.
¿Alguien podría explicar por qué hay una gran diferencia?
Echando un vistazo a la función GenericEqualityIntrinsic
en el código fuente de F # :
let rec GenericEqualityIntrinsic (x : ''T) (y : ''T) : bool =
fsEqualityComparer.Equals((box x), (box y))
Hace boxeo en argumentos, lo que explica la cantidad significativa de basura en su primer ejemplo. Cuando GC entra en juego con demasiada frecuencia, ralentizará dramáticamente el cálculo. El segundo ejemplo (usando inline
) casi no produce basura cuando Pair
es struct.
Dicho esto, es el comportamiento esperado de la palabra clave en inline
cuando se usa una versión especializada en el sitio de la llamada. Mi sugerencia es siempre tratar de optimizar y medir su código en los mismos puntos de referencia.
Puede estar interesado en un hilo muy similar ¿Por qué este código F # es tan lento? .