programar programacion linea desde cpp compilar compilacion como comandos comando c++ performance ubuntu gcc5

c++ - programacion - gcc linux



El programa se ejecuta 3 veces más lento cuando se compila con g++ 5.3.1 que el mismo programa compilado con g++ 4.8.4, el mismo comando (2)

Este es un error en glibc que afecta a las versiones 2.23 (en uso en Ubuntu 16.04) y las versiones anteriores a 2.24 (por ejemplo, Fedora y Debian ya incluyen las versiones parcheadas que ya no están afectadas, Ubuntu 16.10 y 17.04 todavía no).

La desaceleración se debe a la penalización de transición del registro SSE a AVX. Vea el informe de errores de glibc aquí: https://sourceware.org/bugzilla/show_bug.cgi?id=20495

Oleg Strikov escribió un análisis bastante extenso en su informe de error de Ubuntu: https://bugs.launchpad.net/ubuntu/+source/glibc/+bug/1663280

Sin el parche, hay varias soluciones posibles: puede compilar su problema de manera estática (es decir, agregar -static ) o puede deshabilitar el enlace perezoso configurando la variable de entorno LD_BIND_NOW durante la ejecución del programa. Una vez más, más detalles en los informes de errores anteriores.

Recientemente, comencé a usar Ubuntu 16.04 con g ++ 5.3.1 y verifiqué que mi programa se ejecuta 3 veces más lento . Antes de eso he usado Ubuntu 14.04, g ++ 4.8.4. Lo construí con los mismos comandos: CFLAGS = -std=c++11 -Wall -O3 .

Mi programa contiene ciclos, llenos de llamadas matemáticas (sin, cos, exp). Puedes encontrarlo here .

He intentado compilar con diferentes indicadores de optimización (O0, O1, O2, O3, Ofast), pero en todos los casos el problema se reproduce (con Ofast ambas variantes son más rápidas, pero la primera es 3 veces más lenta).

En mi programa utilizo libtinyxml-dev , libgslcblas . Pero tienen las mismas versiones en ambos casos y no toman ninguna parte significativa en el programa (según el código y el perfil de callgrind) en términos de rendimiento.

He realizado el perfilado, pero no me da ninguna idea de por qué sucede. Comparación de Kcachegrind (izquierda es más lenta) . Solo he notado que ahora el programa usa libm-2.23 comparación con libm-2.19 con Ubuntu 14.04.

Mi procesador es i7-5820, Haswell.

No tengo ni idea de por qué se vuelve más lento. ¿Tienes alguna idea?

PS A continuación puede encontrar la función que consume más tiempo:

void InclinedSum::prepare3D() { double buf1, buf2; double sum_prev1 = 0.0, sum_prev2 = 0.0; int break_idx1, break_idx2; int arr_idx; for(int seg_idx = 0; seg_idx < props->K; seg_idx++) { const Point& r = well->segs[seg_idx].r_bhp; for(int k = 0; k < props->K; k++) { arr_idx = seg_idx * props->K + k; F[arr_idx] = 0.0; break_idx2 = 0; for(int m = 1; m <= props->M; m++) { break_idx1 = 0; for(int l = 1; l <= props->L; l++) { buf1 = ((cos(M_PI * (double)(m) * well->segs[k].r1.x / props->sizes.x - M_PI * (double)(l) * well->segs[k].r1.z / props->sizes.z) - cos(M_PI * (double)(m) * well->segs[k].r2.x / props->sizes.x - M_PI * (double)(l) * well->segs[k].r2.z / props->sizes.z)) / ( M_PI * (double)(m) * tan(props->alpha) / props->sizes.x + M_PI * (double)(l) / props->sizes.z ) + (cos(M_PI * (double)(m) * well->segs[k].r1.x / props->sizes.x + M_PI * (double)(l) * well->segs[k].r1.z / props->sizes.z) - cos(M_PI * (double)(m) * well->segs[k].r2.x / props->sizes.x + M_PI * (double)(l) * well->segs[k].r2.z / props->sizes.z)) / ( M_PI * (double)(m) * tan(props->alpha) / props->sizes.x - M_PI * (double)(l) / props->sizes.z ) ) / 2.0; buf2 = sqrt((double)(m) * (double)(m) / props->sizes.x / props->sizes.x + (double)(l) * (double)(l) / props->sizes.z / props->sizes.z); for(int i = -props->I; i <= props->I; i++) { F[arr_idx] += buf1 / well->segs[k].length / buf2 * ( exp(-M_PI * buf2 * fabs(r.y - props->r1.y + 2.0 * (double)(i) * props->sizes.y)) - exp(-M_PI * buf2 * fabs(r.y + props->r1.y + 2.0 * (double)(i) * props->sizes.y)) ) * sin(M_PI * (double)(m) * r.x / props->sizes.x) * cos(M_PI * (double)(l) * r.z / props->sizes.z); } if( fabs(F[arr_idx] - sum_prev1) > F[arr_idx] * EQUALITY_TOLERANCE ) { sum_prev1 = F[arr_idx]; break_idx1 = 0; } else break_idx1++; if(break_idx1 > 1) { //std::cout << "l=" << l << std::endl; break; } } if( fabs(F[arr_idx] - sum_prev2) > F[arr_idx] * EQUALITY_TOLERANCE ) { sum_prev2 = F[arr_idx]; break_idx2 = 0; } else break_idx2++; if(break_idx2 > 1) { std::cout << "m=" << m << std::endl; break; } } } } }

Investigación adicional . Escribí el siguiente programa simple:

#include <cmath> #include <iostream> #include <chrono> #define CYCLE_NUM 1E+7 using namespace std; using namespace std::chrono; int main() { double sum = 0.0; auto t1 = high_resolution_clock::now(); for(int i = 1; i < CYCLE_NUM; i++) { sum += sin((double)(i)) / (double)(i); } auto t2 = high_resolution_clock::now(); microseconds::rep t = duration_cast<microseconds>(t2-t1).count(); cout << "sum = " << sum << endl; cout << "time = " << (double)(t) / 1.E+6 << endl; return 0; }

Realmente me pregunto por qué este sencillo programa de ejemplo es 2.5 más rápido en g ++ 4.8.4 libc-2.19 (libm-2.19) que en g ++ 5.3.1 libc-2.23 (libm-2.23).

El comando de compilación fue:

g++ -std=c++11 -O3 main.cpp -o sum

El uso de otros indicadores de optimización no cambia la proporción.

¿Cómo puedo entender quién, gcc o libc, ralentiza el programa?


Para una respuesta realmente precisa, probablemente necesitará un mantenedor de libm para ver su pregunta. Sin embargo, aquí está mi opinión: tómela como borrador, si encuentro algo más, la añadiré a esta respuesta.

Primero, observe el asm generado por GCC, entre gcc 4.8.2 y gcc 5.3 . Solo hay 4 diferencias:

  • al principio un xorpd se transforma en un pxor , para los mismos registros
  • se pxor xmm1, xmm1 un pxor xmm1, xmm1 antes de la conversión de int a double ( cvtsi2sd )
  • un movsd fue movido justo antes de la conversión
  • la adición ( addsd ) se movió justo antes de una comparación ( ucomisd )

Es probable que todo esto no sea suficiente para la disminución del rendimiento. Tener un buen perfilador (por ejemplo, inteligencia) podría permitir ser más concluyente, pero no tengo acceso a uno.

Ahora, hay una dependencia en el sin , así que veamos qué ha cambiado. Y el problema es primero identificar qué plataforma usas ... Hay 17 subcarpetas diferentes en sysdeps de glibc (donde se define el pecado), así que fui por la x86_64 .

Primero, la forma en que se manejan las capacidades del procesador, por ejemplo, glibc/sysdeps/x86_64/fpu/multiarch/s_sin.c solía hacer la comprobación de FMA / AVX en 2.19, pero en la 2.23 se realiza externamente. Puede haber un error en el que las capacidades no se informan correctamente, lo que puede resultar en no utilizar FMA o AVX. Sin embargo, no creo que esta hipótesis sea muy plausible.

En segundo lugar, en .../x86_64/fpu/s_sinf.S , las únicas modificaciones (aparte de una actualización de derechos de autor) cambian el desplazamiento de la pila, alineándolo a 16 bytes; Idem para los sincos. No estoy seguro de que haría una gran diferencia.

Sin embargo, la versión 2.23 agregó muchas fuentes para versiones vectorizadas de funciones matemáticas, y algunas usan AVX512, que probablemente su procesador no admita porque es realmente nuevo. Tal vez libm intenta usar dichas extensiones y, como no las tiene, ¿retrocede en la versión genérica?

EDITAR: Intenté compilarlo con gcc 4.8.5, pero para ello necesito recompilar glibc-2.19. Por el momento no puedo enlazar, por esto:

/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libm.a(s_sin.o): in function « __cos »: (.text+0x3542): undefined reference to « _dl_x86_cpu_features » /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libm.a(s_sin.o): in function « __sin »: (.text+0x3572): undefined reference to « _dl_x86_cpu_features »

Trataré de resolver esto, pero antes se debe notar que es muy probable que este símbolo sea el responsable de elegir la versión optimizada correcta basada en el procesador, que puede ser parte del impacto del rendimiento.