IF vs SWITCH, prueba de rendimiento

Started by Drumpi, December 11, 2016, 06:00:49 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Drumpi

Hola a todos:

Ya dije en el hilo del "otro proyecto" que sospechaba que SWITCH me estaba ralentizando el juego. Así que he decidido poner a prueba dicha teoría.
Adjunto el código de prueba, pero para el que sea tan vago de no descargarlo, os lo copio aquí:

program test_switch;

function mil_switch ()
private
    int temp;
    int cont;
begin
    for (cont = 0; cont < 10000; cont++)
        temp = rand(0,9);
        switch (temp)
        case 0..2: temp = temp; end
        case 3..4: temp = temp; end
        case 5..7: temp = temp; end
        default: temp = temp; end
        end //switch
    end
end

function mil_switch2 ()
private
    int temp;
    int cont;
begin
    for (cont = 0; cont < 10000; cont++)
        temp = rand(0,9);
        switch (temp)
        case 0: temp = temp; end
        case 1: temp = temp; end
        case 2: temp = temp; end
        case 3: temp = temp; end
        case 4: temp = temp; end
        case 5: temp = temp; end
        case 6: temp = temp; end
        case 7: temp = temp; end
        case 8: temp = temp; end
        case 9: temp = temp; end
        end //switch
    end
end

function mil_if ()
private
    int temp;
    int cont;
begin
    for (cont = 0; cont < 10000; cont++)
        temp = rand(0,9);
        if (temp < 3)    temp = temp;
        elsif (temp < 5) temp = temp;
        elsif (temp < temp = temp;
        else temp = temp;
        end
    end
end

function mil_if2 ()
private
    int temp;
    int cont;
begin
    for (cont = 0; cont < 10000; cont++)
        temp = rand(0,9);
        if (temp == 0)    temp = temp;
        elsif (temp == 1) temp = temp;
        elsif (temp == 2) temp = temp;
        elsif (temp == 3) temp = temp;
        elsif (temp == 4) temp = temp;
        elsif (temp == 5) temp = temp;
        elsif (temp == 6) temp = temp;
        elsif (temp == 7) temp = temp;
        elsif (temp == temp = temp;
        elsif (temp == 9) temp = temp;
        else temp = temp;
        end
    end
end

BEGIN
    set_mode(320,240,16);
    set_fps(0,0);
    write_int(0,10,10,0, &fps);
   
    while (!key(_ESC))
        //mil_switch2();    //215
        //mil_if();            //280
        //mil_if2();        //234
        mil_switch();        //230
        frame;
    end
   
    delete_text(all_text);
END


El código tiene 4 pruebas diferentes:
- mi_switch2: hace 10000 comprobaciones por frame. Obtiene un valor aleatorio entre 0 y 9, y usa un case diferente por cada valor, en donde hace una asignación en una variable (por hacer algo).
- mi_if: hace 10000 comprobaciones por frame. Obtiene un valor aleatorio entre 0 y 9, y usa cuatro comparaciones (if, elsif, elsif y else) en donde hace una asignación en una variable (por hacer algo).
- mi_if2: hace 10000 comprobaciones por frame. Obtiene un valor aleatorio entre 0 y 9, y usa un elsif diferente por cada valor, donde hace una asignación en una variable (por hacer algo).
- mi_switch: hace 10000 comprobaciones por frame. Obtiene un valor aleatorio entre 0 y 9, y usa 4 rangos de valores en el switch, en donde hace una asignación en una variable (por hacer algo).

Resultados en FPS:
- 215
- 280
- 234
- 230

Conclusiones: IF puede dar hasta un 20% más de velocidad que SWITCH en el mejor de los casos ¿Es porque hace menos comprobaciones? Probablemente, porque en el caso de los 10 posibles valores diferenciados, IF todavía da más velocidad, pero por poco.
Usar rangos de valores aumenta la velocidad del switch, pero aun así, usar elsif con valores individuales es ligeramente más rápido.

¿Cuándo usar uno u otro? en caso de problemas de rendimiento, siempre IF. SWITCH es mejor usarlo cuando queramos que el código sea fácilmente legible, o bien cuando queramos comparar con valores muy específicos, pero la mejor política es intentar agrupar todos los valores que vayan a desempeñar una función concreta.

Así que ahora me tocará tirarme unas cuantas tardes modificando el detector de tiles de durezas de los enemigos, sustituyendo los 200 switchs que hay por IF+OR, a ver si gano algo de rendimiento.
Y aquí concluye otro capítulo de "curiosidades internas de Bennu sin haberme leido el código fuente" :D

UPDATE:
He hecho un par de pruebas más, intentando seguir el código que estoy modificando para "el otro proyecto" y ¡horror! los resultados son peores.
Primero el cñodigo que he añadido a la prueba:
function mil_if3 ()
private
    int temp;
    int cont;
begin
    for (cont = 0; cont < 10000; cont++)
        temp = rand(0,9);
        if (temp < 3)    temp = temp;
        elsif ((temp >= 3) && (temp < 5)) temp = temp;
        elsif (((temp >= 5) && (temp < 8)) || (temp == 9)) temp = temp;
        else temp = temp;
        end
    end
end

function mil_if4 ()
private
    int temp;
    int cont;
begin
    for (cont = 0; cont < 10000; cont++)
        temp = rand(0,9);
        if ((temp == 0) || (temp == 1) || (temp == 2) || (temp == 3)) temp = temp;
        elsif ((temp == 4) || (temp == 5) || (temp == 6) || (temp == 7) || (temp == 8)) temp = temp;
        else temp = temp;
        end
    end
end


Los resultados en FPS han sido:
- mil_if3: 204
- mil_if4: 175

Definitivamente es algo que tiene que ver con las comprobaciones que se hacen internamente, los resultados obtenidos son mucho peores que con el switch, y eso significa que, previsiblemente, pierda rendimiento cuando acabe de escribir el nuevo código de comprobación de durezas. Voy a comprobarlo de todas formas, hice una copia de seguridad antes de hacer los cambios (por aquello que dije hace tiempo de volver atrás), así que no hay pegas.
Hala, como con 1001 procesos sólo va a 9 FPS, vamos a meterle 32 veces más, a ver si revienta.
(Drumpi epic moment)

SplinterGU

Download Lastest BennuGD Release: http://www.bennugd.org/node/2

Drumpi

Vale, he añadido un par de pruebas más que hice ayer, con resultados desastrosos. Desastrosos porque el código de prueba se parecen más al que estoy reescribiendo que lo otro, y la velocidad es mucho peor que los anteriores resultados.
Pero bueno, como digo, es sólo una prueba, siempre puedo volver atrás y hacer las cosas con más cabeza ^^U

PD: Tranquilo, Splinter, que esto no lo hago para buscar bugs en Bennu. Es simplemente para que la gente sepa qué es más rápido, por si desea optimizar sus códigos ;)
Hala, como con 1001 procesos sólo va a 9 FPS, vamos a meterle 32 veces más, a ver si revienta.
(Drumpi epic moment)

Noivern

Revisando que hay de nuevo en bennu vi este tema...

Creo que tienes que hacer tus pruebas de nuevo, ya que los switch estan mal hechos, ninguno tiene el break, lo que significa que SIEMPRE va a ejecutar el caso en el que caiga primero y todos los de abajo.

Saludos

SplinterGU

Quote from: Noivern on May 15, 2017, 05:09:53 AM
Revisando que hay de nuevo en bennu vi este tema...

Creo que tienes que hacer tus pruebas de nuevo, ya que los switch estan mal hechos, ninguno tiene el break, lo que significa que SIEMPRE va a ejecutar el caso en el que caiga primero y todos los de abajo.

Saludos

bennugd es un poco diferente a otros lenguajes, el end en cada case tiene un break implicito.
Download Lastest BennuGD Release: http://www.bennugd.org/node/2