Frage

Ich mag die FFTW C-Bibliothek von Delphi 2009 verwenden und nach dieser Dokumentation;

http://www.fftw.org/install/fftw_usage_from_delphi.txt

die Leistung innerhalb der FFTW Bibliothek zu erhöhen Arrays in entweder Einzel geführt (so dass es SIMD-Erweiterungen verwenden können) (float) oder Doppel (double) müssen ausgerichtet werden, entweder bei 4 oder 8 Byte-Grenzen. Ich fand Dokumentation über die Ausrichtung von Satzstrukturen zu sprechen, aber nichts Konkretes über Arrays. Gibt es eine Möglichkeit, dies in Delphi 2009 zu tun.

So ist der Code (aus der obigen Dokumentation kopiert) wird wie folgt aussehen würde;

var
      in, out : Array of Single; // Array aligned at 4 byte boundary
      plan : Pointer;

    {$APPTYPE CONSOLE}

    begin

      ...  

      SetLength(in, N);
      SetLength(out, N);

      plan := _fftwf_plan_dft_1d(dataLength, @in[0], @out[0],
                                 FFTW_FORWARD, FFTW_ESTIMATE);

Auch in der obigen Dokumentation sprechen sie über 8 und 16 Grenzen Byte, aber es scheint mir, soll es 4 und 8 Byte-Grenzen, wenn überhaupt, dass der aufklären könnte, wäre toll.

Danke, Bruce

War es hilfreich?

Lösung

Delphi bietet keine Möglichkeit, die Ausrichtung eines Speichers zu steuern es zuordnet. Sie sind entweder für den Speichermanager, die derzeit installiert auf dem dokumentierten Verhalten verlassen links oder Speicher zuweisen mit etwas schlaff Raum und es dann selbst ausrichten, als mghie zeigt .

Wenn Sie befürchten, dass Delphi-Speicher-Manager die gewünschte Ausrichtung für dynamische Arrays nicht bieten, können Sie voran gehen und die Speicherfunktionen von der DLL bereitgestellt verwenden. Die Notiz, die Sie zitieren erwähnt _fftwf_malloc und _fftwf_free, aber dann gibt es eine Art, die aus _fftwf_malloc zugewiesenen Speicher Warnung „kann nicht direkt von Delphi zugegriffen werden.“ Das kann nicht sein, was die Autoren sagen wollte, aber, weil das nicht ist, wie Speicher in Windows funktioniert. Die Autoren wahrscheinlich, dass der Speicher von _fftwf_malloc zugewiesen sagen wollte nicht von Delphi FreeMem befreit und Speicher von Delphi GetMem zugeordnet werden kann, nicht durch _fftwf_free befreit werden. Das ist nichts Besonderes, obwohl; Sie immer benötigen Speicher-Management-Funktionen gepaart zusammen zu halten.

Wenn Sie _fftwf_malloc verwenden Ihren Array zu bekommen, dann können Sie es durch einen gewöhnlichen Zeigertyp zugreifen. Zum Beispiel:

var
  dataIn, dataOut: PDouble;
begin
  dataIn := _fftwf_malloc(...);
  dataOut := _fftwf_malloc(...);
  _fftwf_plan_dft_1d(dataLength, dataIn, dataOut,
                     FFTW_FORWARD, FFTW_ESTIMATE);

Wie von Delphi 2009, können Sie sogar die Array-Syntax auf diesem Zeiger verwenden:

dataIn[0] := 3.5;
dataIn[2] := 7.3;

Um das zu ermöglichen, die {$POINTERMATH ON} Compiler-Direktive verwenden; es wird nicht standardmäßig mit Ausnahme der Zeichen-Zeigertypen aktiviert.

Der Nachteil manuell Zuweisung Arrays wie dieser ist, dass Sie die Bereichsprüfung verlieren. Wenn Sie Index über das Ende eines Arrays, Sie werden nicht leicht zu erkennen ERangeError Ausnahme mehr bekommen. Sie werden beschädigte Speicher, Zugriffsverletzungen erhalten, oder auf mysteriöse Weise Programme statt abstürzt.

Andere Tipps

Beachten Sie, dass Datenstrukturen mit beliebigen benutzerdefinierten Ausrichtung erstellen können Sie benötigen. Zum Beispiel Ihrer FFT-Daten auf 128-Byte-Grenzen auszurichten:

procedure TForm1.Button1Click(Sender: TObject);
type
  TFFTData = array[0..63535] of double;
  PFFTData = ^TFFTData;
var
  Buffer: pointer;
  FFTDataPtr: PFFTData;
  i: integer;
const
  Alignment = 128; // needs to be power of 2
begin
  GetMem(Buffer, SizeOf(TFFTData) + Alignment);
  try
    FFTDataPtr := PFFTData((LongWord(Buffer) + Alignment - 1)
                           and not (Alignment - 1));

    // use data...
    for i := Low(TFFTData) to High(TFFTData) do
      FFTDataPtr[i] := i * pi;

  finally
    FreeMem(Buffer);
  end;
end;

Edit:

In Bezug auf den Kommentar über die doppelten Speicher zugewiesen werden: Der Stapel Variable FFTData ist vom Typ PFFTData, nicht von TFFTData, so ist es ein Zeiger. Es ist nicht so offensichtlich, weil die Syntax Erweiterung kann die wegzulassen ^ für dereferencing den Zeiger. Der Speicher ist mit GetMem () zugeordnet ist, und mit der richtigen Art anstelle des nicht typisierte Speicherblock zu arbeiten, um die Typumwandlung verwendet wird. Ich habe es wahrscheinlich FFTDataPtr genannt habe.

Heap-Blöcke werden iirc immer ausgerichtet auf 16-Byte bounderies von FastMM (alten D7 memmanager bis 8 ausgerichtet). Ich weiß nicht, über ShareMem, da ich es nicht verwenden.

Und dynamischer Arrays sind Heap-basierten Strukturen. OTOH dyn Arrays könnten vielleicht nicht ausgerichtet werden (16-8), weil es eine Länge und ref Zählung vorangestellt. Der einfachste ist, einfach drucken

ptruint (@in [0]) in hex und sehen, ob das Ende 0 oder 8 (*)

Beachten Sie, dass es fftw Header in FPC. (Pakete / fftw), afaik es kürzlich für 64-Bit-Fest wurde sogar.

Ich bin mir nicht bewusst Stapel Ausrichtung Richtlinien in Delphi. Vielleicht werden sie automatisch „natürlich“ ausgerichtet though.

(*) ptruint ist FPC für eine ganze Zahl ohne Vorzeichen Typ sprechen, die sizeof (Zeiger) groß ist. Kardinal auf 32-bit, QWORD auf 64-Bit.

Dies ist eine weitere mögliche Variante von mghie 's Lösung :

procedure TForm1.Button1Click(Sender: TObject);
type
  TFFTData = array [0..0] of Double;
  PFFTData = ^TFFTData;
var
  AllocatedBuffer: Pointer;
  AlignedArray: PFFTData;
  i: Integer;
const
  cFFTDataSize=63536;
begin

  GetMem(AllocatedBuffer, cFFTDataSize*SizeOf(Double) + 16);  // e.g 16 Bytes boudaries alignement

  try
    AlignedArray := PFFTData((Integer(AllocatedBuffer) and $FFFFFFF0) + 16);

    // use data...

    for i := 0 to cFFTDataSize-1 do
      AlignedArray[i] := i * Pi;
  finally
    FreeMem(AllocatedBuffer);
  end;
end;

Ich habe das Stück Code Refactoring, um es meaningfull zu machen und die Verwendung einer ähnlichen manuellen Ausrichtung repariert Technik zu machen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top