今回は、NXPの最新の高速高性能のi.MX RT1050クロスオーバープロセッサの性能をベンチマークソフトにCoremark(コアマーク)で実際に測定してみます。Coremarkは、色々なMCUやMPUのコアの実行性能をベンチマークすることが可能で、使用するデバイスの性能比較に使用されることもしばしば。
今回はそんなコアマークの実装方法の紹介と、実際に実行した結果をお見せしたいと思います。
基本的には、どのマイコンでも同様に実装することが可能で、簡単に測定することが可能です。
今回は、NXPの新しい製品で、マイコンとプロセッサのいいとこ取りしたクロスオーバープロセッサi.MX RT1050という製品のEVKが手に入りましたので、このボードを使用してコアマークを測定して見たいと思います。
驚愕の結果に驚きですよ!
使用した評価ボード

使用したボードは、前述したようにNXP社のI.MX RT1050-EVKのボードを使用しました。
i.MX RT1050のスペック
このi.MXRT1050のコア、メモリ周りのスペックを見ておきます。
コア: Arm Cortex-M7 (FPU double precision)
クロックスピード: 最大600MHz
フラッシュメモリ: 無し
RAM: TCM-Memory 256kB
外部メモリ: SDRAM、SRAM、NOR/NAND Flash、QSPIフラッシュ
プログラムコードの実行
このデバイスは、基本的にフラッシュメモリが内蔵されていません。したがって、i.MX6などのプロセッサと同様に、プログラムメモリをSDRAMなどに展開して実行するシャドーイングによるコード実行となります。
QSPIフラッシュからの直接実行が可能!
ただ、QSPIフラッシュからの直接実行(XIP: eXecute In Place)をサポートしていて、シャドーしなくても直接QSPIフラッシュからプログラムコードを実行できるので、システムBOMコストの削減が可能です。
もちろんQSPIフラッシュからコード実行をすることで、コード実行のサイクル数にペナルティが増えますが、その場合は内蔵RAMなどに処理速度が重要なコードを展開しておくことで、システム全体の性能低下を防ぐことも可能です。
また、比較的大きなシステムキャッシュ(I-Cache 32kB, D-Cache 32kB)も内蔵しているので、システム全体の性能の底上げに大きな影響を与えています。
使用した統合開発環境
今回はIAR社のEWARMを使用してコアマークのベンチマーク測定を行いました。
IAR EWARMは、こちらから→IAR社Embedded Workbench for ARM
コアマークを入手する
早速、コアマークを実装して行きます。
まずは、コアマークを入手します。
コアマークは、EEMBCのサイトからダウンロードすることが可能です。下記URLからコアマークサイトに登録後にダウンロード可能になります。
使用するファイル
MCUXpresso SDKを使用する場合には、必要なファイルはcソースで5つ、ヘッダファイルは2つのみです。
- core_portme.c
- core_portme.h
- core_list_join_.c
- core_main.c
- core_matrix.c
- core_util.c
- coremark.h
これらのファイルを使用環境に合わせて若干修正する必要があります。
それでは、実装手順を見て行きましょう。
使用するプロジェクト
今回使用するプロジェクトは、MCUXpresso SDKのi.MXRT1050 用SDK内にあるサンプルプロジェクトHello Worldにコアマークを実装して行きます。
MCUXpresso SDKは、こちらから入手可能です。→MCUXpresso SDK
実装手順
1.ダウンロードしたコアマークファイルとgptタイマーのドライバをプロジェクトに追加
GPTドライバの追加
今回は、gptタイマー(General purpose timer)を使用して処理時間を測定します。クロックサイクルを測定できるものであれば、なんでも良いのですが、今回はgptタイマーを使って見ます。
ただ、Hello worldプロジェクトには、gptタイマーのドライバーが追加されていません。そのため、gptタイマーのドライバをSDKの下記のパスから追加します。
i.MXRT1050 SDKフォルダ/drivers/evkimxrt1050/drivers/
ここにあるfsl_gpt.c、fsl_gpt.hをEWARM内プロジェクトdriversにドラッグ&ドロップしてファイルを追加します。
coremarkファイルの追加
プロジェクトにcoremarkというフォルダを作成し、ダウンロードしたコアマークファイルを同じくドラッグ&ドロップして追加します。
2.coremark.cの編集
89行目 MAIN_RETURN_TYPE main(void){ がmain()関数と同じなので、コアマーク処理だと分かり易い関数名に変更します。
ここでは、main_coremark(void)に変更します。
#if MAIN_HAS_NOARGC
//MAIN_RETURN_TYPE main(void) {
MAIN_RETURN_TYPE main_coremark(void) {
int argc=0; char *argv[1];
#else
MAIN_RETURN_TYPE main(int argc, char *argv[]) {
#endif
3.hello_world.c
#include “coremark.h”のインクルードを追加
#include “fsl_gpt.h”のインクルードを追加
main関数を下記のように書き換えます。参考にしてください。GPTタイマーを使用しているので、GPT関連のdefineをしてあげる必要があるいます。
#define GPT_IRQ_ID GPT2_IRQn
#define EXAMPLE_GPT GPT2
#define EXAMPLE_GPT_IRQHandler GPT2_IRQHandler
/* Select IPG Clock as PERCLK_CLK clock source */
#define EXAMPLE_GPT_CLOCK_SOURCE_SELECT (0U)
/* Clock divider for PERCLK_CLK clock source */
#define EXAMPLE_GPT_CLOCK_DIVIDER_SELECT (0U)
/* Get source clock for GPT driver (GPT prescaler = 0) */
#define EXAMPLE_GPT_CLK_FREQ (CLOCK_GetFreq(kCLOCK_IpgClk) / (EXAMPLE_GPT_CLOCK_DIVIDER_SELECT + 1U))
int main(void){
gtp_config_t gptConfig;
/* Init board hardware */
BOARD_InitPins();
BOARD_BootClockRUN();
BOARD_InitDebugConsole();
/*Clock setting for GPT*/
CLOCK_SetMux(kCLOCK_PerclkMux, EXAMPLE_GPT_CLOCK_SOURCE_SELECT);
CLOCK_SetMux(kCLOCK_PerclkDiv, EXAMPLE_GPT_CLOCK_DIVIDEER_SELECT);
/*GPT timer is setup for measurement of coremark */
GPT_GetDefaultConfig(&gptConfig);
/* Initialize GPT module */
GPT_Init(EXAMPLE_GPT, &gptConfig);
/*Divide GPT clock source frequency by 2 inside GPT module */
GPT_SetClockDivider(EXAMPLE_GPT, 2);
/* Start Timer */
PRINTF("¥r¥nStarting GPT Timer...");
GPT_StartTimer(EXAMPLE_GPT);
/* Coremark start */
main_coremark();
while(1);
}
4.core_portme.hの編集
まず、#include “stdlib.h”をインクルード
#define NULL ((void *)0)をコメントアウトします。
このファイルでは、コアマークの実行回数やタイマーのクロック、コンパイラー情報を設定します。
コアマークの設定は、以下のようにDefineで定義します。
#define ITERATIONS 30000 //実行回数、i.MXRT1050の場合には30000回くらいが適当です。
#define CLOCKS_PER_SEC 150000000 //計測のためのタイマーのクロック周波数を指定
#define COMPILER_VERSION "IAR EWARM v8.20.2" //使用するコンパイラ情報
#define COMPILER_FLAGS "SPEED" //コンパイラのフラッグ、今回はスピードに最適化してコンパイルします
#define MEM_LOCATION "RAM"//実行場所
データタイプの設定を以下のように設定します。
HAS_TIME_H 0
USE_CLOCK 0
HAS_STDIO 1
HAS_PRINTF 1
/************************/
/* Data types and settings */
/************************/
/* Configuration : HAS_FLOAT
Define to 1 if the platform supports floating point.
*/
#ifndef HAS_FLOAT
#define HAS_FLOAT 1
#endif
/* Configuration : HAS_TIME_H
Define to 1 if platform has the time.h header file,
and implementation of functions thereof.
*/
#ifndef HAS_TIME_H
//#define HAS_TIME_H 1
#define HAS_TIME_H 0
#endif
/* Configuration : USE_CLOCK
Define to 1 if platform has the time.h header file,
and implementation of functions thereof.
*/
#ifndef USE_CLOCK
//#define USE_CLOCK 1
#define USE_CLOCK 0
#endif
/* Configuration : HAS_STDIO
Define to 1 if the platform has stdio.h.
*/
#ifndef HAS_STDIO
//#define HAS_STDIO 0
#define HAS_STDIO 1
#endif
/* Configuration : HAS_PRINTF
Define to 1 if the platform has stdio.h and implements the printf function.
*/
#ifndef HAS_PRINTF
//#define HAS_PRINTF 0
#define HAS_PRINTF 1
#endif
5. core_portme.cの編集
Barebones_clock()のエラー部分をコメントアウトします。
CODETIMETYPE barebones_clock(){
//#error "You must implement a method to measure time in barebones_clock"
return GPT_GetCurrentTimeCount(GPT1);
}
同様にportable_init()内の#errorもコメントアウトします。
void portable_init(){
//#error "Call board initialization routines in portable init (if needed), in particular"
if (sizeof(ee_ptr_int) != sizeof(ee_u8 *)){
:
:
6.EWARMのインクルードパス
最後にEWARMのインクルードパスを設定して終わります。
測定結果
なんと、コアマーク値=2,943です!i.MXRT1050は600MHzなのでコアマーク/MHz=5です!
これがどれくらいすごい値かって言うと、Cortex-M4FコアのK60(100MHz)でコアマーク値270です。コアマーク/MHzで2.7くらいです。
約10倍もあるんです。コアマーク/MHzでは倍も差があります。
まとめ
いかがでしたでしょうか?今回は、コアマークの実装方法とi.MXRT1050での実行結果を紹介しました。
基本的に、他のデバイスでも同様にコアマークを実装することができます。是非、参考にしてください。