2010年08月10日
Cortex-A9のサイクルカウンタを利用した簡単な実行時間の計測方法
計測用の関数を手軽に使えるようにソースコードを一つのヘッダファイルにまとめています。
ある関数を複数の方法で実装して、どちらが速いかを比較する場合に便利です。
ソースコード
カウンタの読み出しの時のオーバーヘッドを少なくするためインライン関数にしています。
gccの拡張記法を使用しています。
#ifndef __KMC_PMON_CA9_H #define __KMC_PMON_CA9_H /* Performance Monitor Control Register of Cortex A9*/ #define PMCR_D 3 #define PMCR_C 2 #define PMCR_E 0 #define PMCNTENSET_C 31 volatile __inline__ static unsigned long __attribute__((always_inline)) pmon_start_cycle_counter() { unsigned long x; x = 1 << PMCNTENSET_C; asm volatile("mcr p15, 0, %0, c9, c12, 1" :: "r" (x)); asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (x)); x |= ((1 << PMCR_D) | (1 << PMCR_C) | (1 << PMCR_E)); asm volatile("mcr p15, 0, %0, c9, c12, 0" :: "r" (x)); asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=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, c9, c13, 0": "=r" (x)); return x; } #endif /* __KMC_PMON_CA9_H */
使用方法
pmon_ca9.h をインクルードし、(#include "pmon_ca9.h")
最初にpmon_start_cycle_counter()を呼んでカウントをスタートさせます。
その後は任意のところでpmon_read_cycle_counter()でサイクルカウンタを読み出し、その差分で時間を計ります。pmon_read_cycle_counter()を複数回呼び出してラップタイムを測定することもできます。
ライブラリなどを追加する必要がないので、Makefile等の変更が不要です。計測したい部分のソースファイルだけの変更で使えます。
ARMとThumb2のどちらのモードでも使用できます。
使用例
#include <stdio.h> #include "pmon_ca9.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; }
- パフォーマンスモニタ、サイクルカウンタの詳細はCortex-A9のテクニカルリファレンスマニュアルを参照してください。
- 動作確認はしていませんが、おそらくCortex-A8もこれとほぼ同じソースでできると思います。Cortex-A8のテクニカルリファレンスマニュアルを参照してください。
- このソースは特権モードで使用することを想定しています。ユーザーモードからパフォーマンスモニタのレジスタにアクセスするためにはあらかじめUser Enable Register(PMUSERENR)にてアクセスを許可しておく必要があります。