vectorizar vectorizacion tipos rapida programas para imagenes imagen illustrator gratis corel performance language-agnostic vectorization low-level

performance - vectorizacion - ¿Por qué la vectorización, más rápida en general, que los bucles?



vectorizar imagen inkscape (3)

La vectorización (como se usa normalmente el término) se refiere a la operación SIMD (instrucción única, datos múltiples).

Eso significa, en esencia, que una instrucción realiza la misma operación en varios operandos en paralelo. Por ejemplo, para multiplicar un vector de tamaño N por un escalar, llamemos a M el número de operandos de ese tamaño que puede operar simultáneamente. Si es así, entonces el número de instrucciones que necesita ejecutar es aproximadamente N / M, donde (con operaciones puramente escalares) tendría que llevar a cabo N operaciones.

Por ejemplo, el conjunto de instrucciones AVX 2 actual de Intel utiliza registros de 256 bits. Se pueden usar para mantener (y operar) un conjunto de 4 operandos de 64 bits cada uno, u 8 operandos de 32 bits cada uno.

Entonces, asumiendo que está tratando con números reales de precisión simple de 32 bits, eso significa que una sola instrucción puede hacer 8 operaciones (multiplicaciones, en su caso) a la vez, así que (al menos en teoría) puede terminar N multiplicaciones usando Sólo instrucciones de multiplicación N / 8. Al menos, en teoría, esto debería permitir que la operación termine aproximadamente 8 veces más rápido de lo que permitiría ejecutar una instrucción a la vez.

Por supuesto, el beneficio exacto depende de cuántos operandos admita por instrucción. Los primeros intentos de Intel solo admitían registros de 64 bits, por lo que para operar con 8 elementos a la vez, esos elementos solo podrían ser de 8 bits cada uno. Actualmente admiten registros de 256 bits y han anunciado compatibilidad con 512 bits (e incluso pueden haberlo enviado en unos pocos procesadores de gama alta, pero no en los procesadores de consumo normales, al menos todavía). Hacer un buen uso de esta capacidad también puede ser no trivial, por decirlo suavemente. Programar instrucciones para que realmente tenga N operandos disponibles y en los lugares correctos en los momentos correctos no es necesariamente una tarea fácil (en absoluto).

Para poner las cosas en perspectiva, el (ahora antiguo) Cray 1 ganó mucha de su velocidad exactamente de esta manera. Su unidad vectorial operaba en conjuntos de 64 registros de 64 bits cada uno, por lo que podía realizar 64 operaciones de doble precisión por ciclo de reloj. En el código vectorizado de manera óptima, estaba mucho más cerca de la velocidad de una CPU actual de lo que cabría esperar basándose únicamente en su (mucho menor) velocidad de reloj. Aprovechar al máximo eso no siempre fue fácil (y aún no lo es).

Sin embargo, tenga en cuenta que la vectorización no es la única forma en que una CPU puede realizar operaciones en paralelo. También existe la posibilidad de un paralelismo a nivel de instrucción, que permite que una sola CPU (o el núcleo único de una CPU) ejecute más de una instrucción a la vez. La mayoría de las CPU modernas incluyen hardware para (teóricamente) ejecutar hasta aproximadamente 4 instrucciones por ciclo de reloj si las instrucciones son una mezcla de cargas, tiendas y ALU. De manera rutinaria, pueden ejecutar cerca de 2 instrucciones por reloj en promedio, o más en bucles bien ajustados cuando la memoria no es un cuello de botella.

Luego, por supuesto, hay subprocesos múltiples, que ejecutan múltiples flujos de instrucciones en (al menos lógicamente) procesadores / núcleos separados.

Por lo tanto, una CPU moderna podría tener, digamos, 4 núcleos, cada uno de los cuales puede ejecutar 2 multiplicaciones de vectores por reloj, y cada una de esas instrucciones puede operar en 8 operandos. Entonces, al menos en teoría, se pueden realizar 4 * 2 * 8 = 64 operaciones por reloj.

Algunas instrucciones tienen mejor o peor rendimiento. Por ejemplo, FP agrega que el rendimiento es menor que FMA o se multiplica en Intel antes de Skylake (1 vector por reloj en lugar de 2). Pero la lógica booleana como AND o XOR tiene 3 vectores por rendimiento de reloj; No se necesitan muchos transistores para construir una unidad de ejecución AND / XOR / OR, por lo que las CPU los replican. Los cuellos de botella en el ancho total de la tubería (el extremo frontal que se decodifica y emite en la parte fuera de orden del núcleo) son comunes cuando se usan instrucciones de alto rendimiento, en lugar de cuellos de botella en una unidad de ejecución específica.

¿Por qué, en el nivel más bajo de las operaciones de ejecución del hardware y las operaciones subyacentes generales involucradas (es decir, las cosas generales de las implementaciones reales de todos los lenguajes de programación cuando se ejecuta el código), la vectorización es tan dramáticamente más rápida que el bucle?

¿Qué hace la computadora cuando hace un bucle que no hace cuando usa la vectorización (estoy hablando de los cálculos reales que realiza la computadora, no lo que escribe el programador), o qué hace de manera diferente?

No he podido convencerme de por qué la diferencia debería ser tan significativa. Probablemente podría convencerme de que el código vectorizado elimina cierta sobrecarga de bucle en algún lugar, pero la computadora todavía tiene que realizar el mismo número de operaciones, ¿no es así? Por ejemplo, si estamos multiplicando un vector de tamaño N por un escalar, tendremos N multiplicaciones para realizar cualquier forma, ¿no?


La vectorización es un tipo de procesamiento paralelo. Permite que se dedique más hardware informático a realizar el cálculo, por lo que el cálculo se realiza más rápido.

Muchos problemas numéricos, especialmente la solución de ecuaciones diferenciales parciales, requieren que se realice el mismo cálculo para un gran número de celdas, elementos o nodos. La vectorización realiza el cálculo para muchas celdas / elementos / nodos en paralelo.

La vectorización utiliza hardware especial. A diferencia de una CPU multinúcleo, para la cual cada una de las unidades de procesamiento paralelo es un núcleo de CPU completamente funcional, las unidades de procesamiento de vectores pueden realizar solo operaciones simples, y todas las unidades realizan la misma operación al mismo tiempo, operando en una secuencia de valores de datos ( un vector) simultáneamente.


La vectorización tiene dos beneficios principales.

  1. El beneficio principal es que el hardware diseñado para admitir instrucciones vectoriales generalmente tiene hardware que es capaz de realizar múltiples operaciones ALU en general cuando se usan instrucciones vectoriales. Por ejemplo, si le pide que realice 16 adiciones con una instrucción de vector de 16 elementos, puede tener 16 sumadores paralelos que pueden hacer todas las adiciones a la vez. La única forma de acceder a todos esos sumadores 1 es a través de la vectorización. Con instrucciones escalares, solo obtienes el sumador solitario.

  2. Por lo general, se ahorra algo de sobrecarga utilizando instrucciones vectoriales Usted carga y almacena datos en grandes porciones (hasta 512 bits a la vez en algunas CPU Intel recientes) y cada iteración de bucle hace más trabajo, por lo que la sobrecarga del bucle es generalmente más baja en un sentido relativo 2 , y necesita menos instrucciones para hacerlo. el mismo trabajo por lo que la sobrecarga de la CPU es menor, etc.

Finalmente, tu dicotomía entre bucles y vectorización es impar. Cuando tomas un código no vectorial y lo vectorizas, generalmente terminarás con un bucle si antes había un bucle, o no si no lo había. La comparación es realmente entre instrucciones escalares (no vectoriales) e instrucciones vectoriales.

1 O al menos 15 de los 16, quizás uno sea usado también para realizar operaciones escalares.

2 Probablemente podría obtener un beneficio similar de sobrecarga de bucle en el caso escalar a costa de una gran cantidad de desenrollado de bucle.