benchmarksgame benchmark alioth c++ performance gcc

c++ - benchmark - Función no utilizada cambia el rendimiento.



benchmarksgame alioth debian (1)

Primero te mostraré un truco mágico para lograr esto sin la función de basura. Entonces te mostraré por qué funciona la función de basura. Así que truco:

Original inefectivo (note mi máquina aproximadamente dos veces más rápido):

g++ -g -pipe -march=native -pedantic -std=c++11 -W -Wall -Wextra -Werror -O3 -o bin/inserter src/inserter.cc --param inline-unit-growth=200 && time ./bin/inserter real 0m2.197s user 0m2.200s sys 0m0.000s

Ahora va truco (tu definir sigue inactivo):

g++ -g -pipe -march=native -pedantic -std=c++11 -W -Wall -Wextra -Werror -O3 -o bin/inserter src/inserter.cc --param inline-min-speedup=2 && time ./bin/inserter real 0m1.114s user 0m1.100s sys 0m0.010s

Nota: la diferencia está en el argumento de aspecto extraño --param inline-min-speedup=2

Ahora resumiré brevemente la investigación:

  1. ¿Cuál es la diferencia entre rápido y lento? En la versión lenta, tenemos una llamada ineficaz a emplace_back_aux dentro de la bar() , que está mágicamente en línea cuando tu foo no está comentado. Así que podemos concluir, que la barra es muy caliente y la línea es crushial aquí. Y lo más probable es que todo este error se trata de alinear.

  2. Ahora, con la opción -fdump-ipa-inline-details veamos los volcados en línea. Verá diferentes consideraciones de tiempo / tamaño. Es difícil de leer y no quiero pegar aquí todos los detalles. Pero el resultado general del estudio de esta información: GCC piensa que el crecimiento en el tamaño de los módulos (en porcentajes) no vale la pena como aceleración estimada.

  3. ¿Qué hacer? Dos posibilidades:

    3.1. Aumente el tamaño del módulo y las estimaciones de aceleración en general con el código foo no utilizado, es decir, usar tipos correctos como insert_iterator para llamar emplace_back y mover la relación para ser más grande y alcanzar el límite de la línea de entrada (tenga en cuenta que esta forma es muy inestable; todo puede explotar en otras versiones de compiladores con algoritmos de alineación mejorados, y también debes tener mucha suerte de adivinar el código para que funcione.

    3.2. O mover el límite en línea. Lo que le dije a GCC con el parámetro provisto es "considerar para incluir incluso funciones grandes con menos aceleración, por favor".

Es decir. Hay muchos otros parámetros dentro de GCC y otros trucos que puedes hacer con ellos.

Mientras trato de estimar la diferencia de rendimiento entre push_back y std::inserter push_back me encuentro con un problema de rendimiento muy extraño.

Consideremos el siguiente código:

#include <vector> using container = std::vector<int>; const int size = 1000000; const int count = 1000; #ifdef MYOWNFLAG void foo(std::insert_iterator<container> ist) { for(int i=0; i<size; ++i) *ist++ = i; } #endif void bar(container& cnt) { for(int i=0; i<size; ++i) cnt.push_back(i); } int main() { container cnt; for (int i=0; i<count; ++i) { cnt.clear(); bar(cnt); } return 0; }

En este caso, no importa si se define o no MYOWNFLAG , no se llama a la función foo. Sin embargo, el valor de esta bandera tiene un impacto en las ejecuciones:

$ g++ -g -pipe -march=native -pedantic -std=c++11 -W -Wall -Wextra -Werror -O3 -o bin/inserter src/inserter.cc && time ./bin/inserter ./bin/inserter 4,73s user 0,00s system 100% cpu 4,728 total $ g++ -g -pipe -march=native -pedantic -std=c++11 -W -Wall -Wextra -Werror -O3 -o bin/inserter src/inserter.cc -DMYOWNFLAG && time ./bin/inserter ./bin/inserter 2,09s user 0,00s system 99% cpu 2,094 total

Tenga en cuenta que si cambio el protopyte de foo para usar std::back_insert_iterator obtengo un rendimiento similar como si no hubiera establecido la bandera.

¿Qué está pasando con las optimizaciones del compilador?

EDITAR

Uso gcc 4.9.2 20150304 (versión preliminar)

Reproducido

  • reproducido por stefan en ideone
  • reproducido por mí en otra máquina con gcc 4.9.2
  • no reproducido por mí en otra máquina con gcc 4.6.3 y flag -std = c ++ 0x