Cualquier idea de por qué este código:¿Por qué vería ~ 20% de aumento de velocidad usando código nativo?
extern "C" __declspec(dllexport) void Transform(double x[], double y[], int iterations, bool forward)
{
long n, i, i1, j, k, i2, l, l1, l2;
double c1, c2, tx, ty, t1, t2, u1, u2, z;
/* Calculate the number of points */
n = (long)pow((double)2, (double)iterations);
/* Do the bit reversal */
i2 = n >> 1;
j = 0;
for (i = 0; i < n - 1; ++i)
{
if (i < j)
{
tx = x[i];
ty = y[i];
x[i] = x[j];
y[i] = y[j];
x[j] = tx;
y[j] = ty;
}
k = i2;
while (k <= j)
{
j -= k;
k >>= 1;
}
j += k;
}
/* Compute the FFT */
c1 = -1.0;
c2 = 0.0;
l2 = 1;
for (l = 0; l < iterations; ++l)
{
l1 = l2;
l2 <<= 1;
u1 = 1;
u2 = 0;
for (j = 0; j < l1; j++)
{
for (i = j; i < n; i += l2)
{
i1 = i + l1;
t1 = u1 * x[i1] - u2 * y[i1];
t2 = u1 * y[i1] + u2 * x[i1];
x[i1] = x[i] - t1;
y[i1] = y[i] - t2;
x[i] += t1;
y[i] += t2;
}
z = u1 * c1 - u2 * c2;
u2 = u1 * c2 + u2 * c1;
u1 = z;
}
c2 = sqrt((1.0 - c1)/2.0);
if (forward)
c2 = -c2;
c1 = sqrt((1.0 + c1)/2.0);
}
/* Scaling for forward transform */
if (forward)
{
for (i = 0; i < n; ++i)
{
x[i] /= n;
y[i] /= n;
}
}
}
se ejecuta un 20% más rápido que el código?
public static void Transform(DataSet data, Direction direction)
{
double[] x = data.Real;
double[] y = data.Imag;
data.Direction = direction;
data.ExtremeImag = 0.0;
data.ExtremeReal = 0.0;
data.IndexExtremeImag = 0;
data.IndexExtremeReal = 0;
long n, i, i1, j, k, i2, l, l1, l2;
double c1, c2, tx, ty, t1, t2, u1, u2, z;
/* Calculate the number of points */
n = (long)Math.Pow(2, data.Iterations);
/* Do the bit reversal */
i2 = n >> 1;
j = 0;
for (i = 0; i < n - 1; ++i)
{
if (i < j)
{
tx = x[i];
ty = y[i];
x[i] = x[j];
y[i] = y[j];
x[j] = tx;
y[j] = ty;
}
k = i2;
while (k <= j)
{
j -= k;
k >>= 1;
}
j += k;
}
/* Compute the FFT */
c1 = -1.0;
c2 = 0.0;
l2 = 1;
for (l = 0; l < data.Iterations; ++l)
{
l1 = l2;
l2 <<= 1;
u1 = 1;
u2 = 0;
for (j = 0; j < l1; j++)
{
for (i = j; i < n; i += l2)
{
i1 = i + l1;
t1 = u1 * x[i1] - u2 * y[i1];
t2 = u1 * y[i1] + u2 * x[i1];
x[i1] = x[i] - t1;
y[i1] = y[i] - t2;
x[i] += t1;
y[i] += t2;
}
z = u1 * c1 - u2 * c2;
u2 = u1 * c2 + u2 * c1;
u1 = z;
}
c2 = Math.Sqrt((1.0 - c1)/2.0);
if (direction == Direction.Forward)
c2 = -c2;
c1 = Math.Sqrt((1.0 + c1)/2.0);
}
/* Scaling for forward transform */
if (direction == Direction.Forward)
{
for (i = 0; i < n; ++i)
{
x[i] /= n;
y[i] /= n;
if (Math.Abs(x[i]) > data.ExtremeReal)
{
data.ExtremeReal = x[i];
data.IndexExtremeReal = (int)i;
}
if (Math.Abs(y[i]) > data.ExtremeImag)
{
data.ExtremeImag = y[i];
data.IndexExtremeImag = (int)i;
}
}
}
}
FFT http://www.rghware.com/fft.png
creé la caída de la CPU se ve en el centro de la gráfica mediante la selección del “nativo DLL FFT” en mi aplicación:
http://www.rghware.com/InstrumentTuner.zip (código fuente)
Creo que esto funcionará en la mayoría de las PC. Tendrá que tener DirectX instalado. Tuve algunos problemas al usar la configuración de captura para cierto hardware. Se suponía que la configuración de captura era configurable, pero el desarrollo de la aplicación se ha visto desviado por este hallazgo interesante.
De todos modos, ¿por qué estoy viendo un aumento del 20% en la velocidad con el código nativo? Esto parece ir en contra de algunas de las suposiciones que tenía previamente.
ACTUALIZACIÓN
Después de la conversión de la función a un método inseguro y fijación de la cuestión de largo/int. El nuevo método inseguro en realidad se ejecuta más rápido que el método nativo (muy bueno).
Profile http://www.rghware.com/profile.png
Es obvio que la matriz de comprobación ligados es la causa del 20% lento en el presente método FFT. Debido a su naturaleza, los bucles for en este método no se pueden optimizar.
Gracias a todos por la ayuda.
He cargado la fuente de nuevo (esta vez con las bibliotecas de clase. –
¿Cómo está haciendo la prueba de comparación de velocidad? ¿Se ejecuta en versión fuera de un depurador (importante) y se ejecuta varias veces (para asegurarse de que no tiene problemas de JIT)? –
Lo estoy ejecutando en versión fuera del IDE. Estoy usando System.Diagnostics.Stopwatch para probar la velocidad de estas funciones. Puse los resultados en el formulario para poder verlos y alternar entre los botones de opción. La función se realiza básicamente de forma continua en intervalos de medio segundo en los datos que ingresan a la tarjeta de sonido. He realizado la prueba muchas, muchas veces. –