2009年08月14日
ARM11のパフォーマンスモニタを利用した簡単な実行時間の計測方法
ARM11のCP15にパフォーマンスモニタがあり、そのサイクルカウンタを利用して簡単にプログラムの2点間の時間を計測することができます。
計測用の関数を手軽に使えるようにソースコードを一つのヘッダファイルにまとめてみました。
ある関数を複数の方法で実装して、どちらが速いかを比較する場合に便利です。
ソースコード
カウンタの読み出しの時のオーバーヘッドを少なくするためインライン関数にしています。
gccの拡張記法を使用しています。
#ifndef __KMC_PMON_ARM11_H
#define __KMC_PMON_ARM11_H
/* Performance Monitor Control Register of ARM1136*/
#define CMCR_ECC 6
#define CMCR_D 3
#define CMCR_C 2
#define CMCR_E 0
volatile __inline__ static unsigned long __attribute__((always_inline))
pmon_start_cycle_counter()
{
unsigned long x;
asm volatile("mrc p15, 0, %0, c15, c12, 0" : "=r" (x));
x |= ((1 << CMCR_D) | (1 << CMCR_C) | (1 << CMCR_E));
x &= ~(1 << CMCR_ECC);
asm volatile("mcr p15, 0, %0, c15, c12, 0" :: "r" (x));
asm volatile("mrc p15, 0, %0, c15, c12, 1" : "=r" (x));
return x;
}
volatile __inline__ static unsigned long __attribute__((always_inline))
pmon_read_cycle_counter()
{
unsigned long x;
asm volatile ("mrc p15, 0, %0, c15, c12, 1": "=r" (x));
return x;
}
#endif /* __KMC_PMON_ARM11_H */
使用方法
pmon_arm1136.h をインクルードし、(#include "pmon_arm11.h")
最初にpmon_start_cycle_counter()を呼んでカウントをスタートさせます。
その後は任意のところでpmon_read_cycle_counter()でサイクルカウンタを読み出し、その差分で時間を計ります。
ライブラリなどを追加する必要がないので、Makefile等の変更が不要です。
計測したい部分のソースファイルだけの変更で使えます。
使用例
#include <stdio.h>
#include "pmon_arm11.h"
int func(int x)
{
int sum = 0;
int i;
for (i = 1; i <= x; i++) {
sum += i;
}
return sum;
}
int
main()
{
unsigned long start, end;
int x;
start = pmon_start_cycle_counter();
x = func(1000);
end = pmon_read_cycle_counter();
printf("time = %ld, x = %d\n", end - start, x);
return x;
}
注意事項
- ARM1136では特権モードでしか使用できません。これはサイクルカウンタのレジスタが特権モードでないと呼び書きできないためです。ARM1176ではSecure User and Non-secure Access Validation Control Register の設定でユーザーモードでも使用できるようになります。
- CortexA8,A9ではPerformance Monitor Control Registerの位置が違うのでmrc, mcr命令の修正が必要。
- 64分周するモードでカウンタを使用していますが、それでも約8分半ほどで32bitのカウンタは一周していまします。(KZM-ARM11ボードの場合)