PMU(パフォーマンス監視ユニット)

PMUの概要

プログラム性能の評価で実行時間を測定する場合、デバッグツールのトレース(プログラムの実行履歴)機能で、実行時間を測定することが今まで一般的でしたが、プロセッサの高速化に伴い、ARMプロセッサからトレース情報を出力することができない場合が見受けられます。この課題を解決するために、Cortex-Aシリーズでは、サイクル数を測定するサイクルカウンタと特定の事象を測定するイベントカウンタで構成されたPMUを搭載しています。

プログラム実行は、PMUの有効・無効に影響(*1)を受けることがなく、実行サイクル数やいろいろな事象を測定する機能です。PMUのサイクルカウンタおよびイベントカウンタは共に32ビットカウンタで、サイクルカウンタの測定点数は1点、イベントカウンタの測定点数はプロセッサコアにより異なり、Cortex-A9は6点搭載しています。サイクルカウンタおよびイベントカウンタのオーバーフローに関しては、オーバーフロー割り込みを利用することで、長時間の測定が可能です。

  • (*1)サイクルカウンタおよびイベントカウンタのオーバーフロー割り込みを使用した場合、割り込みによりプログラム実行に影響を与えます。

PMUの使用方法

PMUのサイクルカウンタを使用し、関数の実行時間測定方法を解説します。

  • ①PMUに関連するレジスタは、ユーザモードでのアクセスは禁止されていますので、PMUSERENR(ユーザイネーブルレジスタ)を特権モードでユーザモードアクセス許可を設定します。PMUSERENRについては、 後述の該当項目を参照ください。
  • ②PMUはリセット時に非稼働状態となっているので、稼働設定を行います。
  • ③測定時間は、動作クロックが1GHzの場合、約4.2秒となりますので、必要に応じてクロックを1/64分周に設定またはオーバーフロー割り込みを使用することを検討します。
  • ④サイクルカウンタ値を保存する変数にvolatile修飾子を付加します。
  • ⑤サイクルカウンタの許可・リセットを行い、開始サイクル数を変数に保存します。
  • ⑥測定対象の処理を実行します。
  • ⑦終了サイクル数を変数に保存します。
  • ⑧デバッグツール等を利用して、開始サイクル変数と終了サイクル変数から実行サイクル数を求めます。

【サイクル数測定サンプルプログラム】

								volatile unsigned long start_pmu_counter;   // 開始サイクル
								volatile unsigned long end_pmu_counter;     // 終了サイクル
								…
								    pmu_start();                            // PMUを稼働状態
								    pmu_enable_counter();                   // サイクルカウンタを許可
								    pmu_reset_counter();                    // サイクルカウンタをリセット
								    start_pmu_counter = pmu_read_counter(); // 開始サイクル数を取得
								    func1();                                // 測定を実施する処理を実行
								    end_pmu_counter = pmu_read_counter();   // 終了サイクル数を取得
								…
								

PMU制御関数

PMUで測定を行う場合の制御関数は、次の通りです。

No 処理内容 関数名
1 PMUを稼働状態に設定します。 void pmu_start(void)
2 サイクルカウンタをリセットします。 void pmu_reset_counter(void)
3 イベントカウンタをリセットします。 void pmu_reset_evnt_counter(void)
4 サイクルカウンタを稼働状態に設定します。 void pmu_enable_counter(void)
5 イベントカウンタ0を稼働状態に設定します。 void pmu_enable_event0(void)
6 イベントカウンタ0にイベントを設定します。 void pmu_set_event0(int event)
7 サイクルカウンタ測定値を読み込みます。 unsigned long pmu_read_counter(void)
8 イベントカウンタ0測定値を読み込みます。 unsigned long pmu_read_event0(void)

【PMU制御プログラム例】

								; PMUを稼働状態に設定
								; void pmu_start(void)
								pmu_start
								    MRC    p15, 0, r0, c9, c12, 0 ; PMCR(パフォーマンスモニタ制御レジスタ)をリード
								    ORR    r0, r0, #0x1           ; Eビットをセット(稼働設定)
								    MCR    p15, 0, r0, c9, c12, 0 ; PMCRをライト
								    BX     lr
								; サイクルカウンタをリセット
								; void pmu_reset_counter(void)
								pmu_reset_counter
								    MRC    p15, 0, r0, c9, c12, 0 ; PMCRをリード
								    ORR    r0, r0, #0x4           ; Cビットをセット(サイクルカウンタをリセット)
								    MCR    p15, 0, r0, c9, c12, 0 ; PMCRをライト
								    BX    lr
								; イベントカウンタをリセット
								; void pmu_reset_evnt_counter(void)
								pmu_reset_evnt_counter
								    MRC    p15, 0, r0, c9, c12, 0 ; PMCRをリード
								    ORR    r0, r0, #0x2           ; Pビットをセット(イベントカウンタをリセット)
								    MCR    p15, 0, r0, c9, c12, 0 ; PMCRをライト
								    BX    lr
								; サイクルカウンタを稼働状態に設定
								; void pmu_enable_counter(void)
								pmu_enable_counter
								    MRC    p15, 0, r0, c9, c12, 1 ; PMCNTENSET(カウントイネーブルセットレジスタ)をリード
								    ORR    r0, r0, #0x80000000    ; Cビットをセット(許可設定)
								    MCR    p15, 0, r0, c9, c12, 1 ; PMCNTENSETをライト
								    BX     lr
								; イベントカウンタ0を稼働状態に設定
								; void pmu_enable_event0(void)
								pmu_enable_event0
								    MRC    p15, 0, r0, c9, c12, 1 ; PMCNTENSETをリード
								    ORR    r0, r0, #0x1           ; P0ビットをセット(許可設定)
								    MCR    p15, 0, r0, c9, c12, 1 ; PMCNTENSETをライト
								    BX    lr
								; イベントカウンタ0にイベントを設定
								; void pmu_set_event0(int event)
								pmu_set_event0
								    MOV    r1, #0x0               ; イベントカウンタ0を選択
								    MCR    p15, 0, r1, c9, c12, 5 ; PMSELR(イベントカウンタ選択レジスタ)にライト
								    MCR    p15, 0, r0, c9, c13, 1 ; PMXEVTYPER(イベント選択レジスタ)にライト
								    BX    lr
								; サイクルカウンタ測定値を読み込み
								; unsigned long pmu_read_counter(void)
								pmu_read_counter
								    MRC    p15, 0, r0, c9, c13, 0 ; PMCCNTR(サイクルカウントレジスタ)をリード
								    BX    lr
								;  イベントカウンタ0測定値を読み込み
								; unsigned long pmu_read_event0(void)
								pmu_read_event0
								    MOV    r0, #0x0               ; イベントカウンタ0を選択
								    MCR    p15, 0, r0, c9, c12, 5 ; PMSELRにライト
								    MRC    p15, 0, r0, c9, c13, 2 ; PMXEVCNTRをリード 
								    BX    lr
								

レジスタ一覧

Cortex-A9でPMUを使用する場合のレジスタについて説明します。詳細のレジスタの内容に関しては、「ARMアーキテクチャリファレンスマニュアル ARMv7-AおよびARMv7-Rエディション」を参照ください。

PMCR(パフォーマンスモニタ制御レジスタ)

このレジスタでは、PMUの稼働・非稼働、クロックカウンタおよびイベントカウンタのリセットを行います。

図1
名前 機能
N 使用できるイベントカウンタの数です(Cortex-A9は6点実装されています)。
D 測定クロックの分周比を設定します。
0:クロックを分周しません。
1:クロックを1/64分周を行います。
C サイクルカウンタをリセットします。
0:動作を行いません。
1:サイクルカウンタをリセットします。
P イベントカウンタをリセットします。
0:動作を行いません。
1:全イベントカウンタをリセットします。
E PMUの動作を設定します。
0: PMUが非稼働状態です。
1: PMUが稼働状態です。

PMCNTENSET(カウントイネーブルセットレジスタ)

  • このレジスタでは、サイクルカウンタまたはイベントカウンタを稼働に設定します。
  • ●0:サイクルカウンタが非稼働です(書き込みは無効です)。
  • ●1:サイクルカウンタが非稼働にします。
図2
名前 機能
C サイクルカウンタの稼働を設定します。
P5 イベントカウンタ5の稼働を設定します。
P4 イベントカウンタ4の稼働を設定します。
P3 イベントカウンタ3の稼働を設定します。
P2 イベントカウンタ2の稼働を設定します。
P1 イベントカウンタ1の稼働を設定します。
P0 イベントカウンタ0の稼働を設定します。

PMCNTENCLR(カウントイネーブルクリアレジスタ)

  • このレジスタでは、サイクルカウンタまたはイベントカウンタを非稼働に設定します。
  • ●0:サイクルカウンタが非稼働です(書き込みは無効です)。
  • ●1:サイクルカウンタが非稼働にします。
図2
名前 機能
C サイクルカウンタの非稼働を設定します。
P5 イベントカウンタ5の非稼働を設定します。
P4 イベントカウンタ4の非稼働を設定します。
P3 イベントカウンタ3の非稼働を設定します。
P2 イベントカウンタ2の非稼働を設定します。
P1 イベントカウンタ1の非稼働を設定します。
P0 イベントカウンタ0の非稼働を設定します。

PMSELR(イベントカウンタ選択レジスタ)

このレジスタでは、使用するイベントカウンタを選択します。このレジスタに、取得するイベントカウンタ番号(Cortex-A9の場合は、0から5)を設定すると、PMXEVTYPER(イベントタイプ選択レジスタ)またはPMXEVCNTR(イベントカウントレジスタ)に書き込みや読み込みが可能となります。

図3

PMCCNTR (サイクルカウントレジスタ)

このレジスタでは、プロセッサのクロックサイクルをカウントします。

図4

PMXEVTYPER(イベントタイプ選択レジスタ)

このレジスタでは、イベントカウンタを使用してカウントする事象を選択します。Cortex-A/Rシリーズに定義されている事象とプロセッサ固有に定義されている事象があり、イベント番号として定義されています。Cortex-A/Rシリーズ共通のイベント番号は0x00から0x3F、プロセッサ固有のイベント番号は0x40から0xFFです。

図5
【代表的なイベントタイプ設定値】
イベントタイプ 機能概要
0x09 取得されたすべての例外をカウントします。
0x0A 例外からの復帰命令をカウントします。
0x70 メイン実行ユニット命令数 (近似値)
0x71 第2実行ユニット命令数 (近似値)
0x72 ロード・ストア命令数 (近似値)
0x74 NONE命令数 (近似値)

PMXEVCNTR(イベントカウントレジスタ)

このレジスタでは、PMSELRで選択されたイベントカウンタ値を読み込むことができます。

図6

PMUSERENR(ユーザイネーブルレジスタ)

  • このレジスタでは、PMUへのユーザモードでのアクセスを設定します。
  • ●特権モードでは、PMUSERENRは、読み込み・書き込みレジスタです。
  • ●ユーザモードでは、PMUSERENRは、読み込み専用になります。
図7
名前 機能
EN ユーザモードへのPMUのアクセス設定を行います。
0:PMUへのユーザモードアクセスは不可能です。
1:PMUへのユーザモードアクセスは可能です。