2

このドキュメントによると、Delphi2009のFFTWCライブラリを使用したいと思います。

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

FFTWライブラリ内のパフォーマンスを向上させるには(SIMD拡張命令を使用できるように)、シングル(浮動小数点)またはダブル(ダブル)のいずれかで渡される配列は、4バイトまたは8バイトの境界で整列する必要があります。レコード構造の配置について説明しているドキュメントを見つけましたが、配列については特に何もありません。Delphi2009でこれを行う方法はありますか。

したがって、コード(上記のドキュメントからコピー)は次のようになります。

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);

また、上記のドキュメントでは、8バイトと16バイトの境界について説明していますが、それまでは4バイトと8バイトの境界である必要があります。

ありがとう、ブルース

4

4 に答える 4

6

必要に応じて、任意のカスタム配置でデータ構造を作成できることに注意してください。たとえば、FFTデータを128バイト境界に揃えるには:

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;

編集:

割り当てられているメモリの2倍に関するコメントについて:スタック変数FFTDataは、TFFTDataではなくPFFTData型であるため、ポインターです。ポインタを逆参照するために^を省略できる構文拡張のため、それほど明白ではありません。メモリはGetMem()で割り当てられ、型なしメモリブロックの代わりに適切な型で動作するために、型キャストが使用されます。私はおそらくそれをFFTDataPtrと呼ぶべきでした。

于 2009-05-11T07:16:08.320 に答える
4

Delphiは、割り当てるメモリの配置を制御する方法を提供していません。Mghieが示すように、現在インストールされているメモリマネージャの文書化された動作に依存するか、メモリに余裕のあるスペースを割り当ててから自分で調整する必要があります。

Delphiのメモリマネージャがダイナミックアレイに必要な配置を提供していないことが心配な場合は、DLLが提供するメモリ機能を使用してください。あなたが引用するメモはとに言及_fftwf_mallocしていますが、それは「Delphiから直接アクセスできないかもしれない」_fftwf_freeから割り当てられたメモリについてのある種の警告を与えます。_fftwf_mallocしかし、それはWindowsでのメモリの動作方法ではないため、作成者が意図したことではありません。著者はおそらく、によって割り当てられたメモリ_fftwf_mallocはDelphiによって解放できず、DelphiFreeMemによって割り当てられたメモリはによってGetMem解放できないと言うつもりでした_fftwf_free。しかし、それは特別なことではありません。常にメモリ管理機能をペアにしておく必要があります。

配列を取得するために使用する場合は_fftwf_malloc、通常のポインタ型を介して配列にアクセスできます。例えば:

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

Delphi 2009の時点では、これらのポインタで配列構文を使用することもできます。

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

これを有効にするには、{$POINTERMATH ON}コンパイラ指令を使用します。文字ポインタタイプを除いて、デフォルトでは有効になっていません。

このように配列を手動で割り当てることの欠点は、範囲チェックが失われることです。配列の終わりを超えてインデックスを作成すると、認識しやすいERangeError例外が発生しなくなります。代わりに、メモリの破損、アクセス違反、または不思議なクラッシュプログラムが発生します。

于 2009-05-11T08:11:02.550 に答える
3

ヒープブロックは、FastMMによって常に16バイトの境界に整列されます(古いD7 memmanagerは8に整列されます)。私はsharememを使用していないので、それについては知りません。

また、動的配列はヒープベースの構造です。長さと参照カウントのプレフィックスが付いているため、OTOH dyn配列が整列しなくなる可能性があります(16から8)。最も簡単なのは単に印刷することです

16進数のptruint(@in [0])で、末尾が0か8かを確認します。(*)

FPCにはfftwヘッダーがあることに注意してください。(packages / fftw)、afaik最近64ビットでも修正されました。

Delphiのスタックアライメントディレクティブを認識していません。たぶん、それらは自動的に「自然に」整列されます。

(*)ptruintは、sizeof(pointer)が大きい符号なし整数型を表すFPCです。32ビットではcardinal、64ビットではqword。

于 2009-05-11T07:00:13.587 に答える
1

これは、mghieソリューションのもう1つの可能な変形です。

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;

コードをリファクタリングして、より意味のあるものにし、同様の手動アライメント修正手法を利用しました。

于 2012-02-21T14:02:40.047 に答える