performance - sacar - ¿Qué tan lento(cuántos ciclos) está calculando una raíz cuadrada?
raiz cuadrada de 630 (3)
De las tablas de instrucciones de Agner Fog:
En Core2 65nm, FSQRT toma de 9 a 69 cc (con un rendimiento recíproco casi igual), según el valor y los bits de precisión. Para comparación, FDIV toma de 9 a 38 cc (con un rendimiento recíproco casi igual), FMUL toma 5 (recíproco = 2) y FADD toma 3 (recíprocamente = 1). El rendimiento de SSE es casi igual, pero parece más rápido porque no puede hacer matemáticas de 80 bits. SSE tiene un sqrt recíproco aproximado súper rápido aproximado y aproximado sin embargo.
En Core2 45nm, la división y la raíz cuadrada se aceleraron; FSQRT toma de 6 a 20 cc, FDIV toma de 6 a 21 cc, FADD y FMUL no han cambiado. Una vez más, el rendimiento del SSE es casi el mismo.
Puede obtener los documentos con esta información de su sitio web .
¿Qué tan lento (cuántos ciclos) está calculando una raíz cuadrada? Esto surgió en un curso de dinámica molecular en el que la eficiencia es importante y la toma de raíces cuadradas innecesarias tuvo un impacto notable en el tiempo de ejecución de los algoritmos.
La raíz cuadrada toma varios ciclos, pero tarda más en acceder a la memoria si no está en el caché. Por lo tanto, tratar de evitar los cálculos mediante la obtención de resultados precalculados de la memoria puede ser perjudicial para el rendimiento.
Es difícil decir en el resumen si puedes ganar o no, así que si quieres estar seguro, prueba y compara ambos enfoques.
Aquí hay una gran charla sobre el tema por Eric Brummer, desarrollador de compiladores en MSVC: http://channel9.msdn.com/Events/Build/2013/4-329
La raíz cuadrada es aproximadamente 4 veces más lenta que la adición usando -O2
, o aproximadamente 13 veces más lenta sin usar -O2
. En otras partes de la red encontré estimaciones de 50-100 ciclos que pueden ser ciertas, pero no es una medida relativa del costo, lo que es muy útil, así que junté el código a continuación para hacer una medida relativa. Déjame saber si ves algún problema con el código de prueba.
El siguiente código se ejecutó en un Intel Core i3 bajo el sistema operativo Windows 7 y se compiló en DevC ++ (que usa GCC). Su experiencia puede ser diferente.
#include <cstdlib>
#include <iostream>
#include <cmath>
/*
Output using -O2:
1 billion square roots running time: 14738ms
1 billion additions running time : 3719ms
Press any key to continue . . .
Output without -O2:
10 million square roots running time: 870ms
10 million additions running time : 66ms
Press any key to continue . . .
Results:
Square root is about 4 times slower than addition using -O2,
or about 13 times slower without using -O2
*/
int main(int argc, char *argv[]) {
const int cycles = 100000;
const int subcycles = 10000;
double squares[cycles];
for ( int i = 0; i < cycles; ++i ) {
squares[i] = rand();
}
std::clock_t start = std::clock();
for ( int i = 0; i < cycles; ++i ) {
for ( int j = 0; j < subcycles; ++j ) {
squares[i] = sqrt(squares[i]);
}
}
double time_ms = ( ( std::clock() - start ) / (double) CLOCKS_PER_SEC ) * 1000;
std::cout << "1 billion square roots running time: " << time_ms << "ms" << std::endl;
start = std::clock();
for ( int i = 0; i < cycles; ++i ) {
for ( int j = 0; j < subcycles; ++j ) {
squares[i] = squares[i] + squares[i];
}
}
time_ms = ( ( std::clock() - start ) / (double) CLOCKS_PER_SEC ) * 1000;
std::cout << "1 billion additions running time : " << time_ms << "ms" << std::endl;
system("PAUSE");
return EXIT_SUCCESS;
}