LSI Jiu-Jitsu

電子工作とブラジリアン柔術

STM32で遊ぶ (10) - CoreMark

f:id:mohran:20200418121953j:plain

日常生活がとんでもない状況になり健康と経済の不安と戦う毎日です。
テレワークで会社のPCでプログラムを書いて、終了後は自分のPCで趣味のプログラムやボードいじりと言う生活サイクルはなかなか悪くないな、なんて思ったりもしますが家族は少々呆れています・・。
それでも、柔術ができないのは大きなストレスを感じています。
こんな日々が懐かしいと思える日が早く訪れてほしいものであり、それまではなんとしても生き延びたいと思っております。
ちなみに給付金の10万円を貰えたらオシロスコープを買う予定です(笑)

さて、仕事でベンチマークプログラムCoremMarkを使った縁もあり、NUCLEO-F446REでも実行させてみました。
実行方法についての紹介です。

ダウンロードはGitHubから行います。
f:id:mohran:20200418210802j:plain

coremark-master.zipを解凍して生成されるファイルから使用するのは下記の9ファイルです。

coremark.h
core_main.c
core_matrix.c
core_list_join.c
core_state.c
core_util.c
barebones/core_portme.h
barebones/core_portme.c
barebones/ee_printf.c


SW4STM32でプロジェクトを作ります。(ライブラリはSPLを使用しています)
srcディレクトリにcoremarkディレクトリを作って中に上の9ファイルをコピーします。
f:id:mohran:20200418224748j:plain

このうち下記の4ファイルの一部を変更します。

core_portme.h
  • 24行目付近にインクルードstdlib.hを追加
#ifndef CORE_PORTME_H
#define CORE_PORTME_H

#include <stdlib.h>

/************************/
/* Data types and settings */
core_portme.c
  • 21行目付近にインクルードstm32f4xx_tim.hを追加
#include "core_portme.h"

#include "stm32f4xx_tim.h"

#if VALIDATION_RUN
  • 46行目付近の#errorをコメント化、returnを追加
CORETIMETYPE barebones_clock() {
  //#error "You must implement a .....
  return((CORETIMETYPE)(TIM2->CNT));
}
  • 57行目付近のTIMER_RES_DIVIDERをコメント化
#define MYTIMEDIFF(fin,ini) ((fin)-(ini))
//#define TIMER_RES_DIVIDER 1
#define SAMPLE_TIME_IMPLEMENTATION 1
  • 114行目付近の#errorをコメント化
void portable_init(core_portable *p, int *argc, char *argv[])
{
  //#error "Call board initialization routines .....
  if (sizeof(ee_ptr_int) != sizeof(ee_u8 *)) {
ee_printf.c
  • 563行目付近の#errorをコメント化、printfを追加
void uart_send_char(char c) {
  //#error "You must implement .....
  printf("%c", c);
core_main.c
  • 89行目付近のmain関数名を変更
#if MAIN_HAS_NOARGC
//MAIN_RETURN_TYPE main(void) {
MAIN_RETURN_TYPE coremark_main(void) {


プロジェクトのプロパティを開いてReleaseコンフィグを選択します。
make時にコンパイラへ与えるdefineとインクルードパスの追加及び、リンカーへ与えるprintf向けの設定を追加します。

下記の画面でdefineの追加を行います。
f:id:mohran:20200418214535j:plain
ADDボタンをクリックして1つづつ追加します。
f:id:mohran:20200418215147j:plain

MAIN_HAS_NORETURN         // coremark_main関数の戻り値無し(void)
MAIN_HAS_NOARGC           // coremark_main関数の引数無し
FLAGS_STR="-O3"           // 最適化レベル
ITERATIONS=5000           // テストの繰り返し回数
CLOCKS_PER_SEC=180000000  // CPUクロック(180MHz)
TIMER_RES_DIVIDER=2       // CPUクロック(180MHz)÷タイマークロック(90MHz)
HAS_STDIO=1               // stdio.hをインクルード
HAS_PRINTF=1              // 結果をprintfで表示


インクルードパスへcoremarkディレクトリを追加します。
f:id:mohran:20200418223250j:plain

../src/coremark


リンカーへprintf向けの設定を追加します。
f:id:mohran:20200418224205j:plain

-specs=nosys.specs -specs=nano.specs -specs=rdimon.specs -lc -lrdimon


「OK」をクリックしてプロパティ画面を閉じます。

コンソール画面にprintfを表示させるためにsyscalls.cをリネームしてコンパイル対象から外します。
(削除しても問題ありません)
f:id:mohran:20200418225041j:plain


main.cを編集します。

#include "stm32f4xx.h"
#include "stm32f4xx_tim.h"

void __auto_semihosting(void) __attribute__((alias("main")));
extern void initialise_monitor_handles(void);

void coremark_main(void);

int main(void){
  initialise_monitor_handles();

  // TIM2 Clock enable
  RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;

  TIM2->CNT = 0x00000000;
  TIM2->CR1 = 0x0001;

  coremark_main();

  while(1);
  return(0);
}

コンパイル対象をReleaseに切り替えます。
f:id:mohran:20200418222443j:plain

コンパイルを行いエラーが出なければ成功です。
f:id:mohran:20200418231438j:plain


「Debug Configurations」よりデバッガの設定を行います。
f:id:mohran:20200418232008j:plain

「Startup」タブにセミホスティングの有効化コマンドを追加して、コンソールにprintfが表示できるようにします。
f:id:mohran:20200418232328j:plain

monitor arm semihosting enable


実行を開始して約12秒後に結果がコンソールに表示されます。
f:id:mohran:20200419005429j:plain

結果はCoreMarkスコア407.83でした。
CPUクロックは180MHzなので
2.26CoreMarks/MHz
となります。

公式サイトに登録されているSTM32F446REの結果は
CoreMarkスコア602.44
3.35CoreMarks/MHz
でしたので、全然足りていません。
調整が必要なのでしょう。
f:id:mohran:20200418234003j:plain


最後に、defineに設定したTIMER_RES_DIVIDERとITERATIONSについてです。

今回、時間計測には32bitタイマーのTIM2を使用しました。
CPUクロックは180MHzですが、TIM2のAPB1クロックは90MHzなのでTIMER_RES_DIVIDERには2を設定しています。
90MHz = 11.111nsecなので32bitカウンタで最大47.7秒ほど計測できる計算になります。

CoreMarkスコアはテストルーチンを1秒間当たりに何回実行したかを示したもので、最低10秒以上実行しないとエラーとなって正確なスコアが算出されません。
実行時間が10秒以上になるようにITERATIONSの値でテストルーチンの繰り返し回数を調整します。
試しにITERATIONSを3000で実行した結果です。
実行時間が7.35秒なのでエラーとなりました。
f:id:mohran:20200419013444j:plain

[参考記事]