Jede Idee, warum dieser Code:Warum sollte ich ~ 20% Geschwindigkeitssteigerung mit nativem Code sehen?
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;
}
}
}
20% als dieser Code schneller läuft?
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
habe ich den Rückgang der CPU in der Mitte des Graphen gesehen durch die „native DLL FFT“ in meiner app Auswahl:
http://www.rghware.com/InstrumentTuner.zip (Quellcode)
Ich denke, das wird auf den meisten PCs laufen. Sie müssen DirectX installiert haben. Ich hatte einige Probleme mit den Aufnahmeeinstellungen für bestimmte Hardware. Die Aufnahmeeinstellungen sollten konfigurierbar sein, aber die Entwicklung der App wurde durch diesen interessanten Fund abgelenkt.
Wie auch immer, warum sehe ich eine 20% ige Steigerung der Geschwindigkeit mit dem nativen Code? Dies scheint angesichts einiger der Annahmen, die ich vorher hatte, zu fliegen.
UPDATE
Nachdem die Funktion auf ein unsicheres Verfahren der Umwandlung und das lang/int Problem beheben. Die neue unsichere Methode läuft tatsächlich schneller als die native Methode (ziemlich cool).
Profile http://www.rghware.com/profile.png
Es ist offensichtlich, dass die Array Prüfung gebunden ist, die Ursache für das 20% Verlangsamung in dieser FFT-Methode. Aufgrund seiner Natur können die For-Schleifen in dieser Methode nicht optimiert werden.
Danke allen für die Hilfe.
Ich habe die Quelle erneut hochgeladen (dieses Mal mit den Klassenbibliotheken. –
Wie machen Sie den Test für den Geschwindigkeitsvergleich? Laufen Sie in der Veröffentlichung außerhalb eines Debuggers (wichtig) und laufen Sie mehrmals (um sicherzustellen, dass Sie keine JIT-Probleme bekommen)? –
Ich führe es in Release außerhalb der IDE. Ich verwende System.Diagnostics.Stopwatch, um die Geschwindigkeit dieser Funktion zu testen. Ich lege die Ergebnisse auf das Formular, damit ich sie sehen und über Radioknöpfe hin und her schalten kann. Die Funktion wird im Wesentlichen kontinuierlich in Halb-Sekunden-Intervallen auf den Daten ausgeführt, die auf die Soundkarte kommen. Ich habe den Test viele, viele Male ausgeführt. –