dsPIC33AKシリーズ⑦PMUの使い方

dsPIC33Aシリーズ

概要

今回はdsPIC33AKシリーズに新搭載されたPMU(Performance Monitor Unit)モジュールの使い方に関して紹介します。
PMUはコード効率を分析する方法を提供し、プロセッサストールを引き起こすソフトウェアルーチンを特定し、最適化する機能を提供します。

関連リンク

記事リンク
第1回dsPIC33AKシリーズについてdsPIC33Aシリーズに関して – ぴくおの電子工作的な何かWP (electricpico.com)
第2回開発ボード、コンフィグレーション設定、クロック設定についてdsPIC33AKシリーズ②開発ボード,コンフィグレーション設定,クロック設定について – ぴくおの電子工作的な何かWP (electricpico.com)
第3回CPU性能についてdsPIC33AKシリーズ③CPU性能について – ぴくおの電子工作的な何かWP (electricpico.com)
第4回FPU性能についてdsPIC33AKシリーズ④FPU性能について – ぴくおの電子工作的な何かWP (electricpico.com)
第5回DSPについてdsPIC33AKシリーズ⑤DSPについて – ぴくおの電子工作的な何かWP (electricpico.com)
第6回タイマー1割り込みについてdsPIC33AKシリーズ⑥Timer1割り込みの使い方 – ぴくおの電子工作的な何かWP (electricpico.com)
第7回(本記事)PMUの使い方
(fig.1-1)各関連記事リンク

開発環境

開発環境を以下に示します。

項目リンク
ベースボードdsPIC33A CURIOSITY PLATFORM
DEVELOPMENT BOARD
dsPIC33A Curiosity Platform Development Board User’s Guide (microchip.com)
CPUボードEV68M17A – dsPIC33AK128MC106 Motor Control DIMdsPIC33AK128MC106 Motor Control Dual In-Line Module (DIM) Information Sheet (microchip.com)
統合開発環境MPLAB X IDE v6.20MPLAB® X IDE | Microchip Technology
コンパイラMPLAB XC DSC v3.10MPLAB® XC DSC Compiler | Microchip Technology
(fig.2-1)本記事の動作確認環境
(fig.2-2)ベースボード+CPUボード(EV68M17A)

PMUについて

dsPIC33AKは5段インターロック命令パイプライン(*1)、投機実行(*2)、条件分岐レイテンシを提言するプリフェッチ分岐予測を特徴とするCPUアーキテクチャを備えています。そのためCPUのクロックとMIPSには一定の関係性が有りません。

CPUのスループットは、以下のような余分なサイクルによって左右されます。

スループットに左右する項目

・CPUパイプラインのデータ依存性
・分岐またはプログラムフローの変更
・キャッシュ・ミス・遅いメモリまたはSFRアクセス
・バス・マスター間のアービトレーション
・CPUより遅いバスのアクセス

パフォーマンス・モニターは、プログラム・フローに余分なサイクルが挿入される原因となるイベントと、経過したクロック・サイクル数をカウントします。この情報を使ってCPI(cycles-per-instruction)を計算し、コード効率が悪い原因を突き止めることができます。

このモジュールは、イベント数を捕捉するために8つの独立した64ビット・カウンタを備えています。

Noイベントソース内容
0None
1CPUサイクル経過 (参照)このイベントカウントは、経過したCPUクロックサイクルの総数を提供します。
2CPU命令完了CPUパイプライン内の命令が完了したことを示します。
3書き込みステージFPUストール“CPUがFPUレジスタに書き込めないため、現在CPU実行が停止していることを示します。これは、FPUが現在既存のレジスタデータの処理に忙しいために発生しました。”
4書き込みステージストール“RAMまたはSFRへの書き込みの追加待ち時間のために、命令が続行できなかったことを示します。”
5読み取りステージ条件分岐“条件分岐命令の発生を示します。条件分岐命令のカウントは、分岐予測の有効性を判断するために、分岐ミス予測の数と比較できます。”
6読み取りステージ分岐ミス予測予測ミスされたプログラムフローの変更によって引き起こされた追加の実行サイクルを示します。
7アドレスステージハザード“CPUパイプライン内の以前の命令へのデータ依存性によって引き起こされた追加の実行サイクルを示します。この依存性は転送できませんでした。”
8アドレスステージFPU命令ストール“レジスタデータの依存性のために、現在FPUコプロセッサ内の実行が停止していることを示します。”
9アドレスステージFPU読み取りストール“CPUがFPUレジスタから読み取れないため、現在CPU実行が停止していることを示します。これは、FPUが現在レジスタデータを更新しているために発生しました。”
10アドレスステージ読み取りストール“RAMまたはSFRの場所を読み取る追加の待ち時間のために、命令が続行できなかったことを示します。”
11アドレスステージストール“アドレスステージでCPUパイプラインが停止した理由を示します。これは、おそらく命令が破棄されているためです。”
12フェッチステージ割り込み遅延カウント有効化割り込み遅延によるサイクル数を示します。
13フェッチステージ読み取りストール“メモリからプログラムワードをフェッチするために追加のサイクルが必要であることを示します。これは、キャッシュミスや同じメモリからプログラムワードとデータをフェッチする際の仲裁競合が原因である可能性があります。”
14フェッチステージプログラムメモリプログラムフロー変更“プログラムフローの変更が発生したことを示します。これは、CALL、RETURN、RETFIE、条件分岐または無条件分岐、割り込みイベントが原因である可能性があります。”
15フェッチステージプログラムメモリベクトルフェッチ“CPUが割り込みベクトルをフェッチしており、それがプログラムフローチェンジイベントと整列していることを示します。このイベントは割り込みイベントのカウントに使用できます。”
16フェッチステージキャッシュビジー“キャッシュが命令ストリームバッファ(ISB)からキャッシュメモリにデータを転送している間に、サイクルがビジー状態であることを示します。”
17フェッチステージPBUヒット“要求されたプログラムデータがキャッシュメモリまたはISBから取得されたことを示します。したがって、命令をフェッチするために追加の実行サイクルは必要ありませんでした。”
18フェッチステージPBUミス“要求されたプログラムデータがキャッシュメモリまたはISBから取得できなかったことを示します。したがって、データを取得するためにプログラムメモリから新しいフェッチと追加の実行サイクルが必要でした。”

PMU 動作確認

ソースコード

コンフィグレーションファイル、クロック設定ファイルは以下のファイルをインクルードしてください。

■コンフィグレーションファイル (config.h)

■クロック設定ソースファイル(Clock_Driver.c)

■クロックヘッダーファイル(clock_driver.h)

ソフトウェアの中身に特に意味は有りません。
メインルーチンでシーケンシャルアクセス、ランダムアクセスを繰り返し、100kHzの割り込みでポートをトグルさせた時の1秒間の実行結果を示します。

#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include "config.h"
#include "clock_driver.h"
#include <dsp.h>

#define ARRAY_SIZE 1024 * 2  //
#define ITERATIONS 1000000

int array[ARRAY_SIZE];
int cnt;

// 連続アクセス
void sequential_access() 
{
    for (int i = 0; i < ITERATIONS; i++) 
	{
        array[i % ARRAY_SIZE]++;
    }
}

// ランダムアクセス
void random_access() 
{
    for (int i = 0; i < ITERATIONS; i++) 
	{
        array[rand() % ARRAY_SIZE]++;
    }
}

int main() 
{
    /*----------------------------------------------------------------------------*/
    /*初期化*/
    /*----------------------------------------------------------------------------*/
        vdg_Clock_Set_Register();
	TRISDbits.TRISD9 = 0u;
	TRISDbits.TRISD10 = 0u;
		
    // タイマー割り込み設定
	PR1 = 1000;
	T1CONbits.ON = 1;
	T1CONbits.TCKPS = 0;
	IFS1bits.T1IF = 0;
	IEC1bits.T1IE = 1;
	IPC6bits.T1IP = 3;
		
	cnt = 0;
	INTCON1bits.GIE = 1;

	//PMU設定	
	HPSEL0bits.SELECT0 = 1U;
	HPSEL0bits.SELECT1 = 2U;
	HPSEL0bits.SELECT2 = 3U;
	HPSEL0bits.SELECT3 = 4U;
	HPSEL1bits.SELECT4 = 5U;
	HPSEL1bits.SELECT5 = 6U;
	HPSEL1bits.SELECT6 = 7U;
	HPSEL1bits.SELECT7 = 8U;
		
	HPCCONbits.CLR = 1U;
	HPCCONbits.CLR = 0U;
		
	HPCCONbits.ON = 1u;
    /*----------------------------------------------------------------------------*/
    /*メインルーチン*/
    /*----------------------------------------------------------------------------*/
	while(1)
        {

		// 配列の初期化
		for (int i = 0; i < ARRAY_SIZE; i++) 
		{
		  array[i] = 0;
		}

		// 連続アクセスの計測
		LATDbits.LATD9 = 1u;
		sequential_access();
		LATDbits.LATD9 = 0u;

		LATDbits.LATD10 = 1u;
		random_access();
		LATDbits.LATD10 = 0u;
        }
}

void __attribute__((interrupt, no_auto_psv)) _T1Interrupt(void)
{
	cnt ++;
	if (cnt > 100000 )
	{
	 HPCCONbits.ON = 0u;
	 Nop();
	}
	
	if ( LATDbits.LATD9 == 1)
	{
	 LATDbits.LATD9 = 0;
	}
	else
	{
	 LATDbits.LATD9 = 1;
	}
	IFS1bits.T1IF = 0u;
}

結果

1秒後にカウンタ動作を停止させた時の各カウンタ値を示します。
このように何が原因でスループットが出ないかの調査をすることが簡単にできます。

イベントカウンタ
CPUサイクル経過 (参照)4295167497928
CPU命令完了143244233
書き込みステージFPUストール0
書き込みステージストール0
読み取りステージ条件分岐11020373
読み取りステージ分岐ミス予測5557119
アドレスステージハザード24305225
アドレスステージFPU命令ストール0

記事についての注意点

本記事は慎重に内容を検討し正確さに努めておりますが、もし内容に誤りがあったとしても、この記事を参考にして生じた損害等については一切の責任を負いません。

コメント

タイトルとURLをコピーしました