sábado, 20 de agosto de 2011

Reduciendo iteraciones

music: AEROSMITH -"Beyond Beautiful"- / -"She's On Fire"-

Partamos de la siguiente base: el bloque de código más rápido es aquel que nunca se ejecuta. Con esta premisa es evidente que nos interesa lograr, de una forma u otra, reducir la cantidad de veces que ciertos bloques de código se ejecutan para mejorar el rendimiento, si ello es posible. Independientemente de lo mejor o peor implementados (y optimizados) que estén dichos bloques.

Una de las razones por las que no he podido llegar a mucho en términos de optimización es porque concebía la optimización exclusivamente como la "aceleración" de la ejecución de ciertas partes de código particularmente costosas computacionalmente, concentrándome demasiado en este enfoque. No se trata de olvidar esto ni mucho menos, sino de anteponer una política de reducción de iteraciones en ciertos puntos clave. Y en el caso de Super Pong, estos puntos clave son los Componentes.

Existen compomentes que no necesitan ser ejecutados todo el tiempo, en cada tick (la IA o la visión de la raqueta, por ejemplo). Desgraciadamente, el engine no estaba preparado para poder establecer una política así, en la que se establezca que un determinado componente no va a ejecutar su método Update en cada iteración, sino sólamente cada vez que haya transcurrido un determinado espacio de tiempo. Y eso es a lo que me he estado dedicando durante los últimos días.

El punto clave de todo esto es la clase IComponent, de la cual heredan TODAS las demás clases componente. El siguiente resúmen explica los puntos más importantes:

AÑADIDOS en IComponent:

Atributo m_fElapsedTime_Max: El Elapsed Time Establecido para el compoente (en ms, pero expresado en segundos). Representa el intervalo de tiempo que debe transcurrir para dar permiso al componente para ejecutar su método Update_Exec. Se asignará en TODOS los componentes un valor para m_fElapsedTime_Max en el método Init del componente. Asignando 0.0f vamos a hacer hacemos que el componente ejecute Update_Exece en cada tick.

Atributo m_fElapsedTime_Acum: El Elapsed Time (en ms, pero expresado en segundos) actualmente acumulado en el componente. Cuando se alcance el Elapsed Time Establecido, se ejecutará el método Update_Exec del componente.

Método virtual Update_Exec() vacío. Este será, como tal, el antiguo método Update. Todos los componentes heredarán este método vacío, sin código; se sobreescribirá en TODOS los componentes (salvo en aquellos que no tengan elementos que actualizar), y se ejecutará cuando se haya alcanzado el Elapsed Time Establecido para el componente.

MODIFICACIONES en IComponent:

IComponent::Update deja de ser un método virtual vació para pasar a ser no virtual y albergar el bloque de código que comprueba que, si se ha alcanzado el Elapsed Time establecido para ese componente, se ordene ejecutar sú método Update_Exec.

(** TO-DO: ya me acordaré algún día de cómo se tabulaba esto... **)

void IComponent::Update(const float& fDelta)
{
m_fElapsedTime_Acum += fDelta;
if ( m_fElapsedTime_Acum >= m_fElapsedTime_Max )
{
m_fElapsedTime_Acum = 0.0f;
this->Update_Exec(fDelta);
}
}

Este método es heredado por todos los componentes, y cuando la Entidad ordena a sus componentes que se actualicen (manda hacer Update a todos sus componentes, vamos), está llamando a este Update heredado de IComponent.

Tras esto, se puede comenzar a pensar un plan de "presupuestos" (Budget es la palabra) de tiempo para cada componente... y el engine está preparado. Por el momento, tengo establecido que los componentes Vista e IANPC ejecuten el método Update_Exec cada 500 ms (sus m_fElapsedTime_Max tendrán almacenado 0.5f, al estar expresado en segundos).

Hice una prueba loca y asigné 10 segundos a los componentes Vista e IANPC, y el framerate no aumentó respecto del caso anterior. Pero hice una segunda prueba loca asignando también 10 segundos al componente LógicaPelota... ¡¡¡y el framerate aumentó en casi VEINTE FRAMES!!!. El componente LogicaPelota, por lo tanto, está suponiendo un cuello de botella importante (como ya sospechaba). Habrá que optimizarlo acelerando su ejecución... y antes de ello reduciendo el número de iteraciones. ; )

Hasta otra. :P

No hay comentarios:

Publicar un comentario