本文へスキップ

豊富な経験と実績を背景に、RFID製品やFPGA/LSI、通信システム等の開発・設計から試作・製品化までお客様の御要望にお応え致します。

TEL. 042-378-5999

〒206-0804 東京都稲城市百村1623-1 
パストラルハイム稲城ビル

コラム:C6Xシリーズにおける高速化の効果

前提

  • この文書はTIのDSP、C6400シリーズを使ってプログラムを書いたときに どういう点に気を使うと高級言語で高速なコードを書くことができるかについて、 その効果を記述したものである。 全てのサンプルは社内実験実装部からの引用である。 記事中に出現する数値は測定時の条件で得られる値であり、関数名などは変更してある。

Memory配置の差

  • ある処理においてデータ領域を内部RAMに配置するか外部RAMに配置するかで8.4倍の差がみられた。一般的にMemory配置はプログラムに影響を及ぼさないので、このMemory配置は最初に考慮すべき項目である。しかも簡単な変更で大きな効果が得られる。どのデータを内部RAMに配置するかなど、使用頻度による調査など熟考を要するが、それだけのメリットがある
       総和 母数   平均
     外部RAM配置  1326572  300  4422
     内部RAM配置  1488974  2850  522
         

関数呼び出しコストの削減修正

  • ある関数をインライン化して計測した。関数本体の高速化としては僅かな差が確認できた。関数呼び出し時のブランチ命令に付随するnop命令の削除効果と考えられる。関数本体の高速化ではなく、呼び出し元の高速化に繋がるため、ループ内で呼ばれるような関数は積極的にインライン化すべきである。また、内部処理の軽い関数では関数呼び出しとする事のデメリットを削減できるためインライン化すべきである。局所的にしか利用されないstaticな関数もインライン化する事で呼び出し元関数と連続的なレジスタの共用利用が促進されるため(多数のレジスタデータのスタックへのコピーを避けて)高速化が期待できる。
     実装比較  総和  母数 平均 
     関数版  37387  410  91
     インライン版  31753  350  91

    分岐コストの削減修正

    • if-else文は5スロットのディレイを伴うブランチ命令を生成するため、if-else文を減らす事は処理速度の向上に繋がる。一方、単文if文は条件に合えばif文の中身を実行して、合わなければnopを生成するだけなので、if-else文は可能な限り単文if文に置き換えるべきである。2重・3重のif文でも条件式の評価値を変数に入れておき、可能な限り単文if文に置き換える策が通用する。

    restrictの有無の差

    • restrictの有無が大きな差を生むケースは2つのポインタ間のデータコピーである。restrictの原義は制限の厳しい使い方をしたポインタという意味で、この修飾子の付くポインタは以下の2点の要件を満たしていなければならない。
      • 他のポインタの別名定義でない事
      • ポインタの指す範囲がオーバーラップしない事
      コンパイラはこの情報を得る事でより的確な並列命令を作る為の判定基準を持てる。 より具体的な例を挙げるとするならば、memmove()は一般的にオーバーラップしたアドレスを渡す事もあるのでrestrict指定不能であり、異なるデータ領域でのmemcopy()はrestrict指定可能である。 以下にある関数で実験したときの値を示す。
       Restrict指定  総和  母数  平均
       なし  3577498  3863 926
       あり  601240  3773  159
      コンパイラの出力ファイルの1つを見ると判るのだが、restrict指定が無いときには並列化に失敗したループが生成され、restrict指定が有るときには7つの命令がループ内で並列化されている。なお、memset(a,b,c)のような定数をポインタへ書き込む場合には書き込まれる側のrestrict指定は意味を持たない。

    アドレス参照コストの削減修正

    • 大きなデータや構造体が配列になっている場合、データ1つ当たりのサイズでオフセットを取る事で次のデータ位置が判る。これは構造体のメンバを参照する場合でも、構造体のメンバをドットや右矢印を使う参照よりも、予め構造体サイズを参照するデータサイズに合わせてオフセット計算した方が余程高速である。構造体のメンバを参照する事はどうしても構造体データのアドレスを先に計算する事に繋がってしまうので、予め構造体メンバに応じたアドレス変数を用意して+=演算でアクセスアドレスを得る方が高速なのである。

    ディレイスロットのある命令の削減修正

    • ディレイスロットのある命令を多用するとそれだけ高速な命令をスケジューリングするための自由度が小さくなる。ブランチ命令は5、ロード/ストア系の命令は4、マルチプライ系の命令は1のディレイスロットがあり、高速化を阻む要因である。これらの命令を使わないといった事は現実には不可能であるが、これらの命令があっても高速化を阻む要因として低く見積もる事が可能な手法がある。それはディレイが発生している部分にnop命令を挿入するのではなく、他の命令を実行させる事である。さらに、ディレイスロットの大きいブランチ命令とロード/ストア系命令を近くに配置すると複数箇所で配置しなければならないnop命令をまとめる事ができ、効果がある。
       ディレイスロット  総和  母数  平均
       考慮なし  11302  30  384
       考慮あり  10440  31  337

    ループ形式比較

    • ループはパイプライン化されることで最も高速化の効果が現れる部分である。実験では以下のようになった。 僅かながらループの突入条件がないぶんdo…whileは高速である。for/whiledo…whileに書き換えることによってその処理は(呼び出し回数)×6クロックの効果を得ることができる。do…while()を使うことの効果はループ突入条件の省略である。for(), while()との差はループ突入条件のチェックによるブランチ命令がないことでしかない。しかし、ブランチ命令はディレイスロット5を持つのでこの差は大きい。
       形式  総和 母数   平均
       for  177340  2524  70
       while  177550  2527  70
       do…while  170358  2478  69

    MUST_ITERATEの有無の差

    • MUST_ITERATEはループの最少回数が既知である場合に有効なCCS固有のプラグマである。パイプライン化されるループの最少ループ回数をコンパイラが把握できるとコンパイラは平行実行可能なループとパイプラインのプロローグ・エピローグの生成を最適化するためのヒントとしてこれを用いる。ループが2回しか回らない時に3つのループを並行実行する処理を生成しても無駄である事が明らかであるように、コンパイラに対して生成するコードが無駄にならない最少ループ回数を知らせることは有効である。との情報があるが、手元のコード(A)で確認したところ、MUST_ITERATEプラグマの有無だけによる差は確認できなかった。平均して0.04の差は誤差範囲と考えるのが自然である。
       MUST_ITERATEの有無  総和  母数 平均 
       あり  1199840  3030  396
       なし  1176286  2970  396

    リニアアセンブラ化によるコスト削減

    • リニアアセンブラに書き換えると、高級言語で高速化という趣旨から外れてしまいます。ここでは、その手法は社外秘とさせて頂き、受託案件として承りたいと考えております。ご興味のある方は是非当社の担当窓口にご相談下さい。
         

バナースペース

株式会社シーデックス

リストicon 本社
〒206-0804
東京都稲城市百村1623-1
パストラルハイム稲城ビル2階

TEL 042-378-5999(代)
FAX 042-378-5998

リストicon 仙台開発部
〒980-0811
宮城県仙台市青葉区一番町3-3-5
仙台青葉通ビル8階

TEL 022-217-1993(代)
FAX 022-217-1994