SSブログ

サイクルタイムを測定しよう (12) [FMx]このエントリーを含むはてなブックマーク#

FM0+ 評価ボード

前回は、ループの配置アドレスを変えながら、サイクル数を測定しました。 今回は、ループ内の命令数によってサイクル数に差が出るかについて調べました。

ソースコード

ループ内の命令数を変化させるために、ループ内に "nop" 命令を追加します。 以下のコードで、 "nop" 命令の数を調整します。

void func9(reg8_t *reg, uint8_t val0, uint8_t val1) @ ".text.func9" {
    for (;;) {
        __asm(
            "nop\n"     // 29
            "nop\n"     // 28
            "nop\n"     // 27
            "nop\n"     // 26
            "nop\n"     // 25
            "nop\n"     // 24
            "nop\n"     // 23
            "nop\n"     // 22
            "nop\n"     // 21
            "nop\n"     // 20
            "nop\n"     // 19
            "nop\n"     // 18
            "nop\n"     // 17
            "nop\n"     // 16
            "nop\n"     // 15
            "nop\n"     // 14
            "nop\n"     // 13
            "nop\n"     // 12
            "nop\n"     // 11
            "nop\n"     // 10
            "nop\n"     // 9
            "nop\n"     // 8
            "nop\n"     // 7
            "nop\n"     // 6
            "nop\n"     // 5
            "nop\n"     // 4
            "nop\n"     // 3
            "nop\n"     // 2
            "nop\n"     // 1
            "label_2:"
        );
        *reg = val0;
        *reg = val1;
    }
}

このコードでは、ループの配置アドレスは固定されますが、代わりに分岐命令のアドレスが変化していきます。

     50          void func9(reg8_t *reg, uint8_t val0, uint8_t val1) @ ".text.func9" {
   \                     func9: (+1)
   \   00000000   0xB500             PUSH     {LR}
     83              for (;;) {
     84                  __asm(
    110                      "nop\n"     // 4
    111                      "nop\n"     // 3
    112                      "nop\n"     // 2
    113                      "nop\n"     // 1
    114                      "label_2:"
    115                  );
   \                     ??func9_0: (+1)
   \   00000002   0xBF00             nop
   \   00000004   0xBF00             nop
   \   00000006   0xBF00             nop
   \   00000008   0xBF00             nop
    116                  *reg = val0;
   \                     ??label_2: (+1)
   \   0000000A   0x7001             STRB     R1,[R0, #+0]
    117                  *reg = val1;
   \   0000000C   0x7002             STRB     R2,[R0, #+0]
   \   0000000E   0xE7F8             B        ??func9_0
    118              }
    119          }

上記は、 "nop" 命令を4個入れた場合のコードです。 分岐先アドレスは "0002" のままですが、分岐命令は "000E" に移動しています。

測定結果

サイクル数を測定しました。 "nop" ひとつあたり1サイクルほど命令実行時間が増えますので、 "nop" による影響を除いたサイクル数を計算しました。

NOP数サイクル数
(除NOP)
分岐先アドレス分岐命令
040206
140208
24020A
34020C
44020E
560210
660212
760214
860216
960218
106021A
116021C
126021E
1370220
1470222
1570224
1670226
1770228
187022A
197022C
207022E
2180230
2280232
2380234
2480236
2580238
268023A
278023C
288023E
2990240

8命令(16バイト)ごとにサイクル数が一つずつ増えているのが分かります。 言い方を変えると、8個の "NOP" を実行するために9サイクルの時間を要しているのです。 ちょっと、効率が悪くありませんか?

推測するに、16バイト境界を超えるごとに命令フェッチに1サイクルの実行時間が必要となっていると考えられます。 通常、プリフェッチとパイプラインの構造がうまく働いていれば、命令フェッチの時間はパイプラインに隠れてしまうはずです。 しかし、この実験結果からは、命令フェッチが見えてしまっています。 しかも、命令フェッチサイクルが増えるのは、分岐命令アドレスの下4ビットが 0000 になった時です。 本当にプリフェッチしていないのでしょうか?


nice!(0)  コメント(0)  トラックバック(0)  このエントリーを含むはてなブックマーク#

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

トラックバックの受付は締め切りました

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。