Visual C++ 2008 vs Visual C++ 2017

Tal vez recordéis Sieve en PowerBASIC Console Compiler 6 donde comparaba la última versión de PowerBasic Console Compiler (6.04) de 2011, con la anterior (5.0) de 2008.

Continuando con el artículo de WinAPI contra C, intrínsecas, C++ y ensamblador donde evaluábamos diferentes mecanismos de hacer lo mismo sobre Windows, hoy compararemos la evolución que ha tenido Microsoft Visual C++ en estos 11 años.

Pues aprovechando que me he encontrado de casualidad con los ejecutables de Visual C++ 2008 que publiqué en x86 vs x64 he procedido a comparar el rendimiento con el último Visual C++ 2017. Me hubiera gustado hacerlo sobre Sieve en C, pero creo que este ejemplo mucho más sencillo y en C portable será más claro.

El código fuente original, era bien sencillo, un bucle que se ejecuta 10.000.000.000 veces y realiza una suma y un decremento:

#include 
#include 

void __cdecl main (void)
{
	unsigned __int64 iCount, iRes;
	unsigned int iInicio, iFin;

	iInicio = clock();

	iRes = 0;
	for (iCount = 1; iCount <= 10000000000; iCount++)
	{
			iRes += iCount;
			iRes--;
	}
	iFin = clock();
	printf("%I64d %d\n", iRes, iFin - iInicio);
	getchar();
}

Los resultados han sido magníficos:

Compilador Tamaño ejecutable (bytes) Tiempo de ejecución (ms)
Visual C++ 2008 (9.0) 66.048 7.531
Visual C++ 2017 (14.14) 116.736 4.984

Visual C++ 2008 vs Visual C++ 2017

La velocidad del ejecución del código generado con Visual C++ 14.1 (2017) casi dobla a la del que generaba 11 años antes. Desgraciadamente también el tamaño del ejecutable ha crecido en la misma proporción. Obviamente el auge x64 es en donde mayores mejoras vamos a notar, pero no deja de ser curioso que el mismo código que escribiéramos hace 10 años, pueda correr el doble de rápido con sólo recompilarlo.

Analicemos un poco más en detalle lo que ha ocurrido. Visual C++ 2008 lo convertía al siguiente código ensamblador:

xor	ebx, ebx
mov	ecx, 1
mov	edi, eax
mov	rax, 10000000000
$LL3@main:
lea	rbx, QWORD PTR [rbx+rcx-1]
inc	rcx
cmp	rcx, rax
jbe	SHORT $LL3@main

Y en Visual C++ 2017 es así:

xor	ebx, ebx
mov	rax, 10000000000
mov	ecx, 1
$LL4@main:
dec	rbx
add	rbx, rcx
inc	rcx
cmp	rcx, rax
jbe	SHORT $LL4@main

Viéndolo así, se entiende fácilmente. Porque Visual C++ 2017 es mucho más listo y evita el uso de LEA para realizar el cálculo. Aunque es eficiente, es poco paralelizable en la pipeline, en donde triunfan las instrucciones sencillas tipo RISC.

Como siempre hago, puedes descargarte el código fuente y los ejecutables aquí (90 Kb. en formato ZIP).

9 comentarios en “Visual C++ 2008 vs Visual C++ 2017”

  1. ¿Os cobran espacio a los programadores de C si en lugar de en una líneas, hacéis lo mismo en tres? Es un gran misterio que no se si algún día se resolverá. O quiza es que los teclados para C++ no llevan barra espaciadora…

    Mucho mejor C++ 2008, al hacer ejecutables más compactos. Supongo que si alguien quisiera un ensamblador más efectivo, lo haría directamente en ensamblador, no? (claro, hoy en día no hay valor, que lo haga C++ XD)

  2. bianamaran creo que el problema del tamaño es porque son sólo unas pocas lineas de código, supongo que si fueran un centenar de líneas podríamos comprobar que la diferencia de tamaño no es tanta.

  3. Javier Gutiérrez Chamorro (Guti)

    bianamaran, no entiendo lo de los espacios. Te refieres a espacios o saltos de linea? De espacios, suelo poner bastantes, salvo después de los paréntesis que no me gusta mucho. De saltos de linea o returns, también creo que hay bastantes, la excepción es este post, donde para facilitar que quepa en la pantalla he ahorrado algunos retornos de carro.

    ¿Quizás te molesta la forma de indentar las llaves?

  4. La verdad es que si el código está bien estructurado e identado no suelo fijarme en los detalles del estilo.
    Personalmente prefiero identar las llaves de esta manera
    while (true) {
    $i++;
    }
    Pero como digo, he leído tanto código de extraños que me adapto automáticamente a cualquier estilo que se pueda considerar “correcto”: limpio y ordenado.

    Creo que bianamaran se refiere a la forma de declarar las variables, personalmente no me convence declarar varias variables en una línea, pero también lo he visto mucho y es una forma de saber de forma rápida que variables son de un tipo y cuales de otro.

  5. Javier Gutiérrez Chamorro (Guti)

    Los que indentamos como yo en C Fernando somos minoría. La mayoría lo hacen como tu. En cualquier caso estamos empatados, a fuerza de ir viendo código y manteniéndolo, estoy habituado a manejarlo independientemente del formato. Lo importante es como dices que esté bien escrito y bien pensado.

    Declarar variables de ese modo me ayuda a agruparlas por tipo, es algo que suelo hacer, aunque efectivamente todo se compensa. Sin embargo declarándolas una por linea, si lo haces a principio del método o función, conlleva que se llena la pantalla de variables y a la hora de leer el código pierdes el contexto que la usa.

    Al final no existe el sistema perfecto…

Deja un comentario