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:
¿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 labar()
, 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.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.¿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