0

以下のコードを検討してください。このコードは、固定レートで 1 秒のバッチでデータを処理することになっています。これは全体的なシステムの一部であり、あまり時間がかかることはありません。

1 秒相当のデータを 100 ロット以上実行すると、プログラムは 35 秒 (または 35%) かかり、この関数をループで実行します。テスト ループは、特に Ada.RealTime でタイミングが調整されます。データは事前​​に生成されるため、実行時間の大部分は間違いなくこのループにあります。

処理時間を最小限に抑えるためにコードを改善するにはどうすればよいですか?

コードは、SSE2 を備えた P3 である Intel Pentium-M で実行されます。

package FF is new Ada.Numerics.Generic_Elementary_Functions(Float);

N : constant Integer := 820;
type A is array(1 .. N) of Float;
type A3 is array(1 .. 3) of A;

procedure F(state  : in out A3;
            result :    out A3;
            l      : in     A;
            r      : in     A) is
   s : Float;
   t : Float;
begin
   for i in 1 .. N loop
      t := l(i) + r(i);
      t := t / 2.0;
      state(1)(i) := t;
      state(2)(i) := t * 0.25 + state(2)(i) * 0.75;
      state(3)(i) := t * 1.0 /64.0 + state(2)(i) * 63.0 /64.0;
      for r in 1 .. 3 loop
         s := state(r)(i);
         t := FF."**"(s, 6.0) + 14.0;
         if t > MAX then
            t := MAX;
         elsif t < MIN then
            t := MIN;
         end if;
         result(r)(i) := FF.Log(t, 2.0);
      end loop;
   end loop;
end;

テスト用の擬似コード

create two arrays of 80 random A3 arrays, called ls and rs;
init the state and result A3 array
record the realtime time now, called last
for i in 1 .. 100 loop
   for j in 1 .. 80 loop
      F(state, result, ls(j), rs(j));
   end loop;
end loop;
record the realtime time now, called curr
output the duration between curr and last
4

5 に答える 5

1

t := FF."**"(s, 6.0) + 14.0; を に置き換えた方が速いかもしれません t := s ** 6 + 14.0; 。浮動小数点の累乗は、おそらく log と exp で行われます。-- ジョナサン

于 2010-03-26T14:42:11.807 に答える
1

ここで Marc C をバックアップします (彼は一般的に自分のことを知っています)。以前、Gnat でgprofを使用したことがあります。セットアップは難しいかもしれませんが、チャンピオンのように機能します。必要に応じて、上記のコードのすべての行で使用されるランタイムの % を取得するために使用できます。

いくつかの提案 (63.0/64.0 の事前計算など) を行うことはできますが、優れたオプティマイザーは既にそれらのほとんどを実行しているはずです。特に CPU を消費する行で何が行われていないかを把握し、それを高速化する必要があります。

コードを調べてみると、累乗と対数演算が時間の大部分を占めていることがプロファイラーによって示されると思います。そのようなもののいくつかを事前に計算する方法を見つけることができれば、役立つかもしれません. しかし、それは自分より進んでいます。プロフィール

于 2010-03-26T13:59:09.100 に答える
0

次のコードの改善により、実行時間が 8 秒に短縮されました。

次に、コマンド ライン オプション -O3 と -mtune=pentium-m と -msse2 を追加すると、実行時間が 0.8 秒に短縮されました。

私の疑いは次のとおりです。

  • Log(x, y) は Log(x) / Log(y) として実装されますが、これは y が定数の場合に高価になります。(7秒)
  • Power(x, y) はループとして実装されます。条件とジャンプは高価です。(20秒)

手順「**」は...

r := x; for i in 2 .. y loop; r := r * x; end loop; return r;

改訂された機能

package FF is new Ada.Numerics.Generic_Elementary_Functions(Float); 

N : constant Integer := 820; 
type A is array(1 .. N) of Float; 
type A3 is array(1 .. 3) of A; 

procedure F(state  : in out A3; 
            result :    out A3; 
            l      : in     A; 
            r      : in     A) is 
   -- Keep the Log of 2 so it is not recalculated
   ONE_ON_LOG_TWO : constant Float := 1 / FF.Log(2.0); 
   M1 : constant Float := 1.0 / 64.0;
   M2 : constant Float := 63.0 / 64.0;
   s : Float; 
   t : Float; 
begin 
   for i in 1 .. N loop 
      t := l(i) + r(i); 
      -- Multiply Not Divide
      t := t * 0.5; 
      state(1)(i) := t; 
      state(2)(i) := t * 0.25 + state(2)(i) * 0.75; 
      state(3)(i) := t * M1 + state(2)(i) * M2; 
      for r in 1 .. 3 loop 
         s := state(r)(i);
         -- Since we know the power hared code the multiply.
         t := s * s * s * s * s * s + 14.0; 
         if t > MAX then 
            t := MAX; 
         elsif t < MIN then 
            t := MIN; 
         end if; 
         -- Don't use Log(x,y) in a loop when y is constant. '
         result(r)(i) := FF.Log(t) * ONE_ON_LOG_TWO; 
      end loop; 
   end loop; 
end; 
于 2010-03-31T01:32:40.813 に答える
0

あなたは作ることを検討したいかもしれません

タイプ A3 は Float の配列 (1 .. N, 1 .. 3) です。

こうすることで、外側のループの各操作が隣接するメモリ ロケーションにアクセスし、キャッシュからより優れたサポートを得ることができます。

  state(i)(1) := t; 
  state(i)(2) := t * 0.25 + state(i)(2) * 0.75; 
  state(i)(3) := t * M1 + state(i)(2) * M2; 

名前の変更を次のように使用する

  cur_state : array (1..3) of Float renames state(i);

その後

  cur_state := (t, t * 0.25 + cur_state(2) * 0.75, t * M1 + cur_state(2) * M2)

コンパイラに最適化のためのヒントを与えるかもしれません。

于 2010-04-14T11:23:51.623 に答える