今回の初心者講座では、複数のコア(マルチコア/メインコア+サブコア)上で実際に動作するアプリケーションの基礎を徹底解説。さらには、統合開発環境(IDE)を使ってマルチコア上で動作するアプリケーションを開発し、SPRESENSE上で実行。ICEデバッガにより可視化することで、実際のコアの内部状態までも詳解します。
なお、例題には設計・実装が最もシンプルな「サブコアからメインコアへメッセージを送る」アプリケーションを取り挙げます。動作もソースコードも非常にコンパクトなアプリケーションですが、本講座では「関数を呼び出したので動いた」という表面的な解説ではなく、さらに一歩先へと踏み込み、プロセッサ(CPUコア)の真髄へとフォーカス。指定したプログラムをサブコアが処理する仕組みから、コア間におけるデータの交換や同期の仕組みとその方法、プログラムを高速化する際に注意すべきポイントなど、様々な技術を紹介いたします。やや遠回りに感じますが、音声解析や動画像処理の高速化、複数タスクの共存と行った実アプリケーションを設計する際に、大きく役立つ知識です。是非、最後までお付き合いください。
本アプリケーションは、SPRESENSE Main Board、ICEデバッガ(NXP LPC-Link2)、無償のVisual Studio Codeによる統合開発環境で簡単に実行できます。手元で実際に操作しながら、マルチコアの設計技術を体得していきましょう。
ASMP上で動作するアプリケーションの構造
まず、ASMP上で動作するアプリケーションの構造について紹介いたします。ASMPのシステムは、システム全体を統括する万能なメインコアと、特定用途(演算処理など)に特化したサブコアから構成されるため、アプリケーションもまた、メインコア用のプログラム/実行ファイルと、サブコア用のプログラム/実行ファイルがそれぞれ必要となります。
本節では、実機を操作する前段階として、プログラムの構成やビルド方法を解説。次に、プログラムがどのようにしてASMP上で実行されていくのかを図解し、最後に、マルチコア化による「デメリット(注意点)」を紹介いたします。プログラムの構造や、高速化でつまずきやすいポイントを事前に把握しておくことで、「マルチコアに最適なプログラム」をスムーズに設計することができるようになるでしょう。
マルチコア・アプリケーションのビルド
ASMPアーキテクチャでは、メインコアの機能と、サブコアの機能が異なります。そのため、メインコアとサブコアそれぞれに実行ファイルを準備する必要があります。ASMPアーキテクチャを採用しているSPRESENSEも同様です。なお、実行ファイルのフォーマットは一般的に「ELF形式」が使われています。
ELF形式|Executable and Linkable Format
SPRESENSEのビルド環境では、図1の流れでプログラムを実行ファイルへと変換します。まず、①サブコアで実行するプログラムをコンパイルし、サブコア用の実行ファイルを生成。次に、②RTOS(NuttX)のプログラムをコンパイルし、メインコア上で動作するOSの実行ファイルを生成します。最後に、③メインコアで実行するプログラムをコンパイルしアプリケーションの実行ファイルを生成。RTOSと結合し、OSとアプリケーションが統合されたnuttx.spk(④)を生成します。
実行の際は、①のバイナリファイルと、④OSとアプリケーションが統合されたnuttx.spkをSPRESENSE上のフラッシュメモリへ書き込みます。再起動後、各実行タイミングにあわせて、RTOS、アプリケーション、サブコアのプログラムが開始されます。
メインコア用のプログラムを追加する
メインコア用のプログラムを増やしたい(実行できるコマンドを増やしたい)場合は、工程③で扱う「メインコア用のプログラムを追加」し、メインコア用の実行ファイルを追加するようMakefileにルールを追加します。なお、Makefileはどのプログラムをどのように変換し実行ファイルを生成するかのルールを定めた設定ファイルです。make
コマンドから利用されます。
サブコア用のプログラムを追加する
サブコアを活用した高度なアプリケーションを開発したい場合は、工程①で扱う、サブコア用のプログラムを追加し、Makefileにルールを追記します。面倒な作業に感じるかもしれませんが、Visual Studio Code と SPRESENSE SDKを統合した統合開発環境(IDE)を使うことで、1クリックでプログラムを登録することができます。是非ご活用ください(図2)。
サブコア上で動作する実行ファイルを生成するためのMakefileは、下記のリンクよりテンプレートを入手することができます。このMakefileでは、まずサブコア上に展開される実行ファイル(ELF形式)を生成し、実行ファイルをディスクイメージ(romfs.img)に格納。実行時にNuttXのファイルシステム/mnt
上に展開される構造を生成します。
Worker Task Makefile|examples/asmp
Worker Task Library Makefile|examples/asmp
マルチコア環境でのプログラムの実行
プログラムの呼び出し順序
続いてプログラムが開始される順序(図3)について、解説いたします。
SPRESENSEでは、まずRTOSがシェルプロンプト(nsh)を起動します。①ターミナルにコマンドが入力されると、コマンドに対応する②メインコア用のプログラムがRTOSにより開始されます(SPRESENSE SDKの設定により①と②の動作を自動化することも可能です)。
プログラムがサブコアを利用するタイミングになると、③メインコア上のプログラムがRTOSのASMPインタフェース(API)を操作。RTOSが④ファイルシステム上にあるサブコアの実行ファイルをロード、⑤メモリに展開します。最後にRTOSがサブコアへ⑥実行するプログラムのアドレスを通知し、⑦サブコア上にて、メインコアの期待するプログラムが開始されます。
メインコアとサブコアの連携
メインコア上のプログラムと、サブコア上のプログラムは、SPRESENSEに搭載された同期用ハードウェアによって、連携します。「メッセージキュー(mpmq)」「ミューテックス・ロック(mpmutex)」「共有メモリ(mpshm)」が同期用のハードウェアです。全てのハードウェアは、サブコアのプログラムを開始される前に、メインコアがによって初期化される必要があります。それぞれのハードウェアは任意の管理番号によって識別され、メインコアとサブコアが同じ管理番号を使うことにより、通信・連携を行います。
同期用ハードウェアを利用する、最もシンプルなサンプル・アプリケーションは、SPRESENSE SDKに同梱された「examples/asmp」です。本アプリケーションは、図4に示すように、同期用ハードウェアを全て操作し、共有メモリを介して、サブコアが生成したデータ(文字列)を、メインコアへ送付。メインコアのプログラムがRTOSを介してUARTドライバを操作し、USB-UARTポートから文字列を出力します。
CPUコアの間で通信・同期するための機能は下記APIとして提供されています。
マルチコア化によるオーバーヘッド
マルチコア(メインコアとサブコアが連携する)システムは、シングルコア(メインコアのみ)システムに比べ「メインコアとサブコア間の通信処理」が追加されています(図5)。これがマルチコア化による通信オーバヘッドです。
開発者は、オーバーヘッド(デメリット)を意識し、「オーバーヘッドに打ち勝てる処理の分配」や「待ち状態のときに何を先行処理するか」などの検討/議論し、マルチコアの並列性/柔軟性といったメリットを引き出します。小さなオーバーヘッドに負けない、大きな実行性能改善です。
一例として、画像処理プログラムをマルチコア化し、高速化にチャレンジする際の手順を図6に示します。本アプリケーションは、カメラで映像を撮影し、画像処理を行い、処理結果をLCDへ表示します(カメラによる撮影機能をf1(x)、画像処理の機能をf2(x)、LCDへの出力機能をf3(x)として図示します)。全てをメインコアで実行すると、実行時間は(A)となります。
次に、画像処理を並列化しようと考え、画像処理のみをCPU#1へ移動させたとしましょう。この場合、処理時間は(B)となります。メインコアとサブコアが連携のために同期する処理S1(x)とS2(x)が増え、実行時間は長くなります(アプリケーションは遅くなります)。これがマルチコア化によるオーバーヘッドです。
その後、設計・検討の結果、画像処理f2(x)を5コアで並列化できるようになると、アプリケーションの実行時間は(C)となり、最初のアプリケーション(A)より高速になります。
マルチコア・プログラミング(特にASMPのように演算CPUコアを活用するケース)では「マルチコアを使えるので高速化ができる」のではなく「並列化による性能改善と、同期処理による処理の増加の両方を加味した上で」プログラムを設計する必要があります(このトレードオフについては、後の初心者講座にて取り挙げます)。
メインコアとサブコアが連携するプログラムを作成し、デバッガを使って解析する
SPRESENSE SDKとVisual Studio Codeを使うことにより、クリックのみで、サブコアを利用するタスクを生成することができます(図7:そのままビルド可能です)。生成されるプログラムには、図4に示したマルチコアとサブコアの連携処理が含まれます。
ポイントとなる処理(ICEデバッガで確認した機能)
本動画では、メインコアがサブコアを制御する様子を紹介しています。メインコアから、サブコア上のタスクの生成と、メインコアとサブコアが連携するための同期用リソース、それらのリソースを活用している処理を以下に抜粋します。
タスクの生成、同期用リソースの生成
/* タスクの生成(WORKER_FILEにELF形式の実行ファイルを指定) */ ret = mptask_init(&mptask, WORKER_FILE); /* タスクをサブコアへ割り当てる */ ret = mptask_assign(&mptask); /* ミューテックス・ロック・リソースを生成し、タスクに割り当てる */ ret = mpmutex_init(&mutex, SAMPLE_WORKERKEY_MUTEX); ret = mptask_bindobj(&mptask, &mutex); /* メッセージキュー・リソースを生成し、タスクに割り当てる */ ret = mpmq_init(&mq, SAMPLE_WORKERKEY_MQ, mptask_getcpuid(&mptask)); ret = mptask_bindobj(&mptask, &mq); /* 共有メモリ・リソースを生成し、タスクに割り当てる */ ret = mpshm_init(&shm, SAMPLE_WORKERKEY_SHM, 1024); ret = mptask_bindobj(&mptask, &shm); /* メインコアのアドレスに共有メモリを割り当てる */ buf = mpshm_attach(&shm, 0); /* タスクを開始する */ ret = mptask_exec(&mptask);
同期用リソースを使ったメインコアとサブコアの連携
/* メッセージキューを使って、サブコアへデータを送信する */ ret = mpmq_send(&mq, MSG_ID_SAMPLE_WORKER, (uint32_t)data); /* メッセージキューを使って、サブコアからデータを取得する */ ret = mpmq_receive(&mq, &msgdata);
/* ミューテックス・ロックを使って、共有メモリへの同時アクセスを防ぐ */ mpmutex_lock(&mutex); /* 共有メモリは mpshm_attach で割付済み */ message("Worker said: %s\n", buf); /* ミューテックス・ロックを解除する */ mpmutex_unlock(&mutex);
まとめ
今回は、ASMPアーキテクチャ/マルチコア上でアプリケーションを構築する際に、欠かすことのできない技術を紹介しました。是非、実機を準備し、お手元で動作をご確認ください。次回は、サブコアをデバッグするテクニックについて紹介いたします。是非、ご期待ください!
Q&A
サブコア用のプログラムが格納されない場合
ASMP用にビルドされたサブコア用実行ファイルは、SPRESENSEに搭載されたSPI接続のフラッシュメモリ(/mnt/spif)に格納されます。
フラッシュメモリはサンプルアプリケーションが生成するデータの格納先としても利用されることから、他のアプリケーションが生成したデータによりフラッシュメモリの空きがなく、図7のようにサブコア用の実行ファイルが格納されない場合があります。
もし、サブコア用の実行ファイルが見つからない場合、df -u
コマンドにて空き容量を確認し、不要なファイルをrm /mnt/spif/ファイル名
コマンドで削除してください。
ASMPのサブコアのELFファイルがインストールされない|stack Overflow
SONY SPRESENSE
SPRESENSEは、Arm Cortex-M4コア(FPU機能搭載)を6コア搭載したシングルボードコンピュータです。マルチコアによる豊富な演算能力をはじめ、魅力的なペリフェラルを多数搭載しながら、電池のみでも駆動できる超低消費電力な製品です。本格的なエッジコンピューティングを是非ご体験ください。システムの試作はもちろん、PoC、製品化にもご活用いただけます。
開発者向けサイトを見る Switch-Scienceで購入する
APS学習ボード(SPRESENSE™ Extension Board用)
APS学習ボード(SPRESENSE™ Extension Board用)は、初心者講座の内容をはじめ、SPRESENSE SDKの提供するオーディオ入力機能やLCDドライバをはじめとする各種機能を、回路設計をすることなく簡単にお試しいただけるよう開発したAPSオリジナルの評価基板です。Web記事と併せてお楽しみください。
取扱説明書|APS学習ボード Switch-Scienceで購入する(ボード単体) Switch-Scienceで購入する(部品キット)
こちらも是非
“もっと見る” マルチコア|SPRESENSE編
SPRESENSE×Neural Network Console:第4回|推論モデルを最適化し、エッジAIによるオリジナルの音声識別システムを構築する
今回の初心者講座では、SPRESENSEの「ハイレゾオーディオ入力」と「DNNRT機能」により「Neural Network Console」で生成したディープニューラルネットワーク(DNN)の推論モデルを統合。エッジ単体で完結するオリジナルの音声識別システムを構築する技法を解説いたします。
SPRESENSE×Neural Network Console:第3回|オーディオ解析に必要な学習用データを採取し、PC上で学習・推論を実行する
今回の初心者講座では、SPRESENSEに搭載されたハイレゾオーディオ入力を活用し、環境音を録音し、ディープニューラルネットワークによる音声分類に不可欠な学習用データと検証用データを生成する方法について解説します。また、PC上で動作するNeural Network Consoleによって生成した推論モデルをエッジ・デバイスへ統合するために解決すべき課題を紹介します。
SPRESENSE×Neural Network Console:第2回|異常検知に活用できるニューラルネットワークで波形の扱い方を学ぶ
SPRESENSEのDNNRT機能が扱うことのできるデータは画像だけでなく、産業分野を中心に人気が高まっている「異常検知・故障予知」に活用できる加速度センサーや大気圧センサーなどから収集した波形データも解析することができます。さらにSPRESENSEに内蔵されたハイレゾオーディオ録音機能も周辺環境を可聴域の波形データとして記録することができる優れたセンサーとして利用可能です。そこで、今回の初心者講座では、まず簡単な波形データの解析方法を例に、DNNRT機能から波形データを扱うシステムの構築方法について解説。DNNRT機能を活用した製品開発に必要となる技術を紹介いたします。