¿Con qué frecuencia te sorprende una optimización de rendimiento?

Prácticamente nunca, pero si fuera por intuición, me equivocaría más a menudo.
El problema probablemente radica en tratar de asignar costos a la programación de abstracciones de modelos.

La cuestión de cómo hacer que el código se ejecute rápido puede dividirse en

  • como es el problema
  • ¿Cómo es el modelo de programación ?
  • ¿Cómo es el modelo de procesamiento ?
  • ¿Cómo es la arquitectura ejecutora ?

Saber que el problema no suele ser un problema una vez que ya ha escrito un código e intenta optimizarlo, así que omita eso.

Un modelo de programación proporciona un conjunto de operaciones para expresar el problema. El conjunto seleccionado no es inherentemente rápido o lento, es correcto o incorrecto. Adjuntar costos a las operaciones en este nivel solo va a causar sorpresas cuando la tecnología cambie por debajo.

Un modelo de procesamiento es un nombre para la idea de alto nivel de cómo se implementan las operaciones en el modelo de programación. El detalle de este modelo mental puede variar desde “se ejecuta en la caja” hasta “este bucle se traduce en operaciones vectoriales porque tengo un compilador que reconoce la independencia de las iteraciones y un procesador con registros vectoriales de 4 valores de ancho” . Confiando en lo primero, el rendimiento estará lleno de sorpresas. Con algo como esto último, se puede elaborar un modelo de rendimiento , que es un conjunto de ecuaciones que relacionan las operaciones de software con las operaciones de hardware mediante el cálculo de qué familia de operaciones de hardware resultan de algunas de las operaciones del modelo de programación. Combine esto con pruebas sintéticas que se aproximen estadísticamente al costo de las operaciones de hardware particulares utilizadas, y comienza a parecer una estimación de las interacciones que tendrá el programa con la máquina en la que se está ejecutando.

La arquitectura de ejecución requiere conocimientos para saber qué operaciones de hardware están disponibles, determinar cuáles son utilizadas por el compilador y, por último, pero no menos importante, derivar los puntos de referencia que determinan las estimaciones de costos para las operaciones básicas.

Mi receta de libro de cocina iría:

  • primero, lea sobre las operaciones de hardware de la arquitectura en ejecución,
  • a continuación, muestree el rendimiento de un rango adecuado de sus primitivas usando varios patrones de acceso a memoria diferentes,
  • luego, pruebe algunas construcciones simples para saber en qué lenguaje primitivo y compilador las asigna,
  • derivar estimaciones de costos para programar primitivas de modelos como funciones que son paramétricas en el uso de la memoria y las instrucciones del procesador (quizás también comportamientos de tiempo de ejecución y del sistema operativo),
  • y finalmente , mapee el problema en la opción más económica de primitivas del modelo de programación según las estimaciones.

(… además, mida qué tan bien funcionó al final …)

Los efectos de las operaciones de alto nivel siempre serán una sorpresa si espera que tengan un costo inherente, su costo siempre es el resultado de lo que está ejecutando su código, y eso no es una constante trivial. Al hacerlo de abajo hacia arriba, no hay sorpresas, porque más o menos planeaste lo que va a suceder.

Sin embargo, hacer todo esto es demasiado trabajo para una aplicación grande completa, así que primero escriba un código lento y correcto, haga un perfil de lo que lo detiene más y bucee con todo detalle solo en esa parte.

Es más problema, pero saca las sorpresas.

Siempre me ha fascinado la optimización del código, y he leído el libro de Michael Abrash sobre el tema muchas veces.

En los primeros días, la optimización de las instrucciones de la CPU solía valer la pena y los compiladores no eran tan inteligentes.
A medida que los chips se han vuelto más rápidos, últimamente se ha visto que el ancho de banda de la memoria es quizás el factor más crítico para la optimización: la mayoría de los algoritmos cuyo conjunto de trabajo es más grande que los cachés están limitados principalmente por la cantidad de datos leídos y escritos.

Hoy en día es difícil superar a los compiladores con un ensamblador codificado a mano, ¡excepto en algunas circunstancias excepcionales!

Lo que debe recordar es que las CPU modernas tienen múltiples unidades de ejecución, por lo que el código de ensamblaje más rápido es algo que parece que dos o más cosas independientes están sucediendo a la vez. Intente no utilizar los mismos registros o variables en instrucciones sucesivas, de modo que las unidades de ejecución puedan ejecutar las instrucciones una al lado de la otra.

Una sorpresa que me atrapó:
La localización de la memoria es una gran victoria. Una estructura similar a una matriz pequeña será más rápida que una lista, simplemente porque los valores son contiguos (lo que permite la captación previa), incluso si la inserción y eliminación son matemáticamente mucho más costosas en una matriz que en una lista.

Otro :
Se supone que el código de la plantilla de C ++ debe ser súper optimizado, estaba un poco escéptico sobre lo bien que podría hacerlo. Escribí una clase de secuencia con plantilla que representa un rango de valores y actúa como si fuera un contenedor. Entonces pude sumar el rango (1, 100000] usando std :: acumular en lugar de un bucle, por ejemplo. La sorpresa fue que generó el mismo código que un bucle for: el compilador pudo “ver a través” de todas las plantillas e iteradores e indirecciones y generan el mejor código posible!
Ver: C ++ y más allá: el poder de las abstracciones

Bueno, como programador de C ++, casi todo el tiempo; es decir, cada vez que realmente realizo un código de perfil siempre hay algo sorprendente.

Creo que muchos programadores, incluyéndome a mí, del código que se compila en nativo son malos al razonar sobre el “código amigable de caché”. Creo que este es el caso por muchas razones, pero lo más importante porque las mejores prácticas formales de la informática pretenden que las arquitecturas de memoria modernas no existen. En la escuela aprendes que todo lo que importa es la complejidad Big-O de un algoritmo, pero dadas las arquitecturas de memoria modernas, es Big-O lo que a menudo no importa. Para los tamaños de datos no grandes, el algoritmo incorrecto Big-O fumará el algoritmo correcto Big-O si el algoritmo correcto Big-O no permite el almacenamiento en caché eficiente y el otro sí.

La nota clave de Bjarne Stroustrup en Going Native el año pasado (creo) tocó esto. Presentó datos de perfil que muestran que, básicamente, siempre es más rápido usar std :: vectors en lugar de std :: lists porque los vectores (el nombre de la biblioteca estándar de C ++ para matrices redimensionables) almacenan datos en la memoria contigua proporcionando la localidad de referencia y, por lo tanto, la capacidad de almacenamiento en caché.

More Interesting

¿Cuáles son algunas de las mejores prácticas para que un gerente de producto se ocupe de la ingeniería de software?

¿Cuáles son los ejemplos de ágil?

¿Cómo se implementa la GUI en el software?

¿Qué es Borg en Google?

¿Cuáles son algunos mini proyectos en big data que podría hacer con un equipo de dos o tres personas en un mes o dos? Soy un estudiante de tercer año de ingeniería informática de la India.

He estado sentado en mi escritorio sin hacer nada en una gran empresa tecnológica y me siento increíblemente poco inspirado. Tengo ganas de dejarlo. ¿Esto es normal?

¿Qué tan difícil es programar un software como Facebook?

Para convertirse en un experto en seguridad de la información, ¿qué debe hacer un desarrollador de software con experiencia de 6 años?

¿Cuál es un escenario en el que ha utilizado un patrón de fábrica en el desarrollo de aplicaciones de software?

¿Cuál es un mejor trabajo: ser gerente o ingeniero de software?

Procesamiento de imágenes: ¿Podemos realmente calcular el nivel de estrés de una persona que usa video en tiempo real?

¿Estás en programación o ingeniería de software principalmente por el salario y el estilo de vida?

Tengo 15 años y estoy intrigado por la codificación, las pruebas de seguridad y la ingeniería de software. Siento que tengo la capacidad de entender la codificación, ¿por dónde debo comenzar?

¿Dónde puedo encontrar un buen programador / desarrollador europeo por menos de 10 USD / hora?

¿Es una buena idea tener revisiones de código obligatorias antes de enviarlas?