single must fun expressions example bodies .net performance struct f# inline

.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? .