Necesitas saber dónde poner el cero



Algunas optimizaciones requieren estructuras de datos complejas y miles de líneas de código. En otros casos, un aumento serio en la productividad produce un cambio mínimo: a veces solo necesita establecer cero. Esto es como una vieja historia sobre un patrón que conoce el lugar correcto para golpear con un martillo, y luego le cobra al cliente: $ 0.50 por un golpe en la válvula y $ 999.50 por saber dónde golpear.

Personalmente, encontré varios errores de rendimiento que se corrigieron al ingresar un cero, y en este artículo quiero compartir dos historias.

La importancia de la medición.


En los días de la Xbox original, ayudé a optimizar muchos juegos. En uno de ellos, el generador de perfiles señaló la función de transformación de la matriz, que consumió el 7% del tiempo de la CPU, el mayor salto en el gráfico. Así que me puse a trabajar diligentemente para optimizar esta función.

Se puede ver que no fui el primero en intentar hacer esto. La función ya ha sido reescrita en ensamblador. Encontré varias mejoras potenciales en el lenguaje ensamblador e intenté medir su efecto. Este es un paso importante, de lo contrario es fácil hacer una "optimización", que no cambiará nada ni empeorará la situación.

Sin embargo, la medición fue difícil. Ejecuté el juego, jugué un poco con perfiles paralelos y luego estudié el perfil: ¿el código se hizo más rápido? Parecía que había una ligera mejoría, pero era imposible decirlo con certeza.

Entonces apliqué el método científico . Escribió una colección de pruebas para administrar versiones antiguas y nuevas de código para medir con precisión las diferencias de rendimiento. Esto no tomó mucho tiempo: como se esperaba, el nuevo código fue aproximadamente un 10% más rápido que el anterior.

Pero resultó que una aceleración del 10% no tiene sentido.

Es mucho más interesante que dentro del código de prueba se ejecutó aproximadamente 10 veces más rápido que en el juego. Este fue un descubrimiento emocionante.

Después de verificar los resultados, miré en el vacío por un tiempo, pero luego me di cuenta.

Función de almacenamiento en caché


Para dar a los desarrolladores de juegos un control total y un rendimiento máximo, las consolas de juegos te permiten asignar memoria con varios atributos. En particular, la Xbox original le permite asignar memoria no almacenable en caché. Este tipo de memoria (de hecho, el tipo de etiqueta en las tablas de páginas) es útil al escribir datos en la GPU. Dado que la memoria no está en caché, la escritura irá a la RAM casi de inmediato sin demoras ni contaminación de caché con el mapeo "normal".

Por lo tanto, la memoria no almacenada en caché es una optimización importante, pero debe usarse con cuidado. En particular, es extremadamente importante que los juegos nunca intenten leer de la memoria no almacenada en caché, de lo contrario su rendimiento disminuirá seriamente. Incluso la CPU relativamente lenta de 733 MHz en la Xbox original necesita sus propios cachés para proporcionar un rendimiento de lectura suficiente.

Ahora queda claro lo que está sucediendo. Aparentemente, para esta función, los datos se asignan en memoria no almacenada en caché, por lo tanto, bajo rendimiento. Una pequeña prueba confirmó esta hipótesis, por lo que es hora de solucionar el problema. Encontré la línea donde se asigna la memoria, hice doble clic en el valor del indicador y apunté a cero.

En lugar de aproximadamente el 7% del tiempo del procesador, la función comenzó a consumir aproximadamente el 0,7% y ya no era un problema.

Al final de la semana, mi informe se veía así: "39,999 horas de investigación, 0.001 horas de programación es un gran éxito".

Los desarrolladores generalmente no necesitan preocuparse por asignar accidentalmente memoria no almacenada en caché: en la mayoría de los sistemas operativos, esta opción no está disponible en el espacio del usuario utilizando métodos estándar. Pero si está interesado en cuánta memoria no almacenable en caché puede ralentizar el programa, pruebe los indicadores PAGE_NOCACHE o PAGE_WRITECOMBINE en VirtualAlloc .

0 GiB es mejor que 4 GiB


Quiero contarte otra historia. Se trata de un error que encontré, y alguien más lo solucionó. Hace un par de años, noté que la memoria caché del disco en mi computadora portátil se borra con demasiada frecuencia. Seguí que esto sucede cuando se alcanza la línea de 4 GiB, y al final resultó que el controlador para mi nuevo disco duro de respaldo establece SectorSize en 0xFFFFFFFF (o −1) cuando apunta a un tamaño de sector desconocido. El kernel de Windows interpreta este valor como 4 GiB y asigna el bloque de memoria correspondiente, lo que causó el problema.

No tengo contactos en Western Digital, pero puedo suponer con seguridad que solucionaron este error reemplazando la constante 0xFFFFFFFF (o −1) con cero. Un personaje ingresó y resolvió un grave problema de rendimiento.

(Lea más sobre este estudio en el artículo "Retardar Windows: Explorando e Identificando" )

Observaciones


  • En ambos casos, el problema es el almacenamiento en caché
  • Decisivo fue el uso de un perfilador para identificar el problema.
  • Si el parche no se verifica mediante mediciones, no necesariamente ayudará.
  • Podría escribir sobre muchos otros casos, pero son demasiado secretos o demasiado aburridos.
  • La decisión correcta no tiene que ser complicada. A veces una gran mejora da un pequeño cambio. Todo lo que necesitas saber es dónde

Por casualidad optimicé el código al descomentar #define y por otros cambios triviales. Cuéntanos en los comentarios si tienes tales historias.

Source: https://habr.com/ru/post/es434056/


All Articles