ドキュメンテーション センター

  • 評価版
  • 製品アップデート

目次

最新のリリースでは、このページがまだ翻訳されていません。 このページの最新版は英語でご覧になれます。

マルチコア ターゲットへのビルドおよびダウンロード

コードの生成

コードを生成するには、Simulink® エディター ウィンドウで [コード][C/C++ コード][モデルのビルド] を選択します。Simulink Coder™ または Embedded Coder® ソフトウェアを使用すると、このコードをマルチコア ターゲットで同時に実行できます。コーダーは、スレッド作成、スレッド同期化、割り込みサービス ルーチン、および信号ハンドラーとデータ転送用にターゲット依存コードのみを生成します。main() プログラムには、以下のスレッドが含まれています。マッピング モデルのソース ファイル (model.cmodel.h など) は、スレッドの実行を設定するためのターゲット依存コードを含んでいません。ただし、データ転送タイプ用のターゲット依存コードは存在する可能性があり、これにより、ターゲット固有のデータ保護またはセマフォのアプリケーション プログラミング インターフェイス (API) 呼び出しが生成されます。

各周期タスクについては、Simulink Coder がそのタスクにマップされたブロックの出力メソッドと更新メソッドを組み合わせて、これらのメソッドをターゲット固有のスレッドにバインドします。また、連続状態を含んだ周期的タスクごとに、個別のソルバー インスタンスがマッピング モデルのソース ファイルに生成されます。このマッピング モデルはモデルの連続部分を同時実行できます (生成されるソルバー インスタンスは、マッピング モデルの [コンフィギュレーション パラメーター] ダイアログ ボックスの [ソルバー] で指定されているソルバー タイプを共有します)。

Simulink Coder は、非周期的タスクまたは非周期的トリガーごとに、そのタスクにマッピングされたブロックの出力メソッドと更新メソッドを組み合わせて、ターゲット固有の割り込みサービス ルーチン (ISR) またはターゲット固有のイベント ハンドラーにバインドします。

以下は、マッピング モデルのソース ファイルに生成されたコードの例です。このコードは、マッピング モデル用に生成された関数を示しています。

  • 2 つのソルバー インスタンス

  • 4 つの周期的タスク (そのうち 2 つは連続状態をもつ)

  • 2 つの非周期的タスク

  • 2 つの非周期的トリガー

/*
 * This function updates continuous states using the ODE3 fixed-step  
 * solver algorithm
 */
static void Periodic_Task1_rt_ertODEUpdateContinuousStates(RTWSolverInfo  *si )
{ … }

/*
 * This function updates continuous states using the ODE3 fixed-step  
 * solver algorithm
 */
static void Periodic_Task2_rt_ertODEUpdateContinuousStates(RTWSolverInfo  *si )
{ … }


/* OutputUpdate for Task: Periodic_Task1 */
void Periodic_Task1_step(void)                   /* Sample time: [0.1s, 0.0s] */
{ … 
    Periodic_Task1_rt_ertODEUpdateContinuousStates(&task_M[0]->solverInfo);
  …
}

/* OutputUpdate for Task: Periodic_Task2 */
void Periodic_Task2_step(void)                  /* Sample time: [0.2s, 0.0s] */
{ … 
    Periodic_Task2_rt_ertODEUpdateContinuousStates(&task_M[1]->solverInfo);
  …
}

/* OutputUpdate for Task: Periodic_Task3 */
void Periodic_Task3_step(void)                  /* Sample time: [0.1s, 0.0s] */
{ … }

/* OutputUpdate for Task: Periodic_Task4 */
void Periodic_Task4_step(void)                  /* Sample time: [0.2s, 0.0s] */
{ … }

/* OutputUpdate for Task:Interrupt1_asyncTask1 */
void Interrupt1_asyncTask1(void)
{ … }

/* OutputUpdate for Task:Interrupt2_asyncTask2 */
void Interrupt2_asyncTask2(void)
{ … }

/* OutputUpdate for Task:Interrupt3 */
void Interrupt3(void)
{ … }

/* OutputUpdate for Task:Interrupt4 */
void Interrupt4(void)
{ … }

また、連続信号の場合は、選択した外挿法のコードも生成されます。外挿法には、ゼロ次ホールド、線形、2 次、なしの 4 タイプがあります。[なし] は、2 つの通信タスクがマイナー ステップで同期している場合の理想的な外挿法です。

次のコードの抜粋は、マッピング モデルのソース ファイルに生成されたタスク関数を含んでいます。sldemo_concurrent_execution モデルは次のように変更されています。

  • ControllerA/u1 は [信号プロパティ] ダイアログ ボックスの [データの整合性のみを保証] オプションを使用します。

  • 補償器と同時に実行される新しいタスクにプラントが再マッピングされています。プラントから補償器へのデータ転送は [確定的に転送を保証 (最小遅延)] です。

コーダーは、同時実行タスク間のデータ転送が「データ転送オプション」で説明されているとおりに動作していることを確認します。

同時実行環境でデータを共有するコードの生成

[データの整合性のみを保証] を選択した場合に生成されるコードは、データを同時実行環境で共有できます。これを実現するために、ダブルバッファリング アルゴリズム (同一レート データ転送の場合)、トリプルバッファリング アルゴリズム (レート変換データ転送の場合) よびバッファー フラグ管理用のターゲット固有の保護コードが使用されます。次の例は、sldemo_concurrent_execution モデルを使用して生成されたコードです。

  1. ControllerA/u1 の [信号プロパティ] ダイアログ ボックスを開いて、データ転送処理オプションとして [データ転送] ペインの [データの整合性のみ] を選択します。

  2. コードを生成するには、[コード][C/C++ コード][モデルのビルド] を選択します。

コーダーによって次のようなコードが生成されます。このコードは、Linux® プラットフォーム上の ControllerA/u1 に関するものです。

/* Output for Task: Periodic_ControllerA */
void Periodic_ControllerA_output(void) /* Sample time: [0.1s, 0.0s] */
{
   …
  /* TaskTransBlk: '<Root>/TaskTransAtController AOut1' */
  sldemo_concurrent_execution_DWork.
    TaskTransAtControllerAOut1_buf_3[sldemo_concurrent_execution_DWork.fw_buf_3]
    = sldemo_concurrent_execution_B.ControllerA;
  rtw_pthread_mutex_lock(sldemo_concurrent_execution_DWork.mw_buf_3);
  sldemo_concurrent_execution_DWork.fw_buf_3 = 1 -
    sldemo_concurrent_execution_DWork.fw_buf_3;
  rtw_pthread_mutex_unlock(sldemo_concurrent_execution_DWork.mw_buf_3);
}
/* Output for Task: Periodic_Plant */
void Periodic_Plant_output(void)       /* Sample time: [0.0s, 0.0s] */
{
  …
  if (rtmIsMajorTimeStep(task_M[2])) {
    /* TaskTransBlk: '<Root>/TaskTransAtPlantIn1' */
    rtw_pthread_mutex_lock(sldemo_concurrent_execution_DWork.mw_buf_3);
    wrBufIdx = 1 - sldemo_concurrent_execution_DWork.fw_buf_3;
    rtw_pthread_mutex_unlock(sldemo_concurrent_execution_DWork.mw_buf_3);
    sldemo_concurrent_execution_B.TaskTransAtPlantIn1 =
      sldemo_concurrent_execution_DWork.TaskTransAtControllerAOut1_buf_3[wrBufIdx];
  …
  }
 …
}
void MdlInitialize(void)
{
  …
  sldemo_concurrent_execution_DWork.fw_buf_3 = 0;
  rtw_pthread_mutex_init(&sldemo_concurrent_execution_DWork.mw_buf_3);
 …
}

データ転送中の最大容量のためのコードの生成

[確定的に転送を保証 (最大遅延)] を選択した場合にタスク変換用に生成されるコードは、ダブルバッファリングとの間の読み書きアクセス権をもつ ANSI® C コードです。[信号プロパティ] ダイアログ ボックスでは、最初の読み取り操作用のバッファーを初期化する [初期条件] の値を指定します。

ソフトウェアによって次のようなコードが生成されます。この例は、Linux プラットフォーム上の ControllerB/u1 に関するものです。

/* Output for Task: Periodic_ControllerB */
void Periodic_ControllerB_output(void) /* Sample time: [0.1s, 0.0s] */
{
 …
  sldemo_concurrent_execution_DWork.
    TaskTransAtControllerBOut1_buf_4[sldemo_concurrent_execution_DWork.fw_buf_4]
    = sldemo_concurrent_execution_B.ControllerB;
  sldemo_concurrent_execution_DWork.fw_buf_4 = 1 -
    sldemo_concurrent_execution_DWork.fw_buf_4;
}
/* Output for Task: Periodic_Plant */
void Periodic_Plant_output(void)       /* Sample time: [0.0s, 0.0s] */
{
 …
  if (rtmIsMajorTimeStep(task_M[2])) {
 …

    /* TaskTransBlk: '<Root>/TaskTransAtPlantIn2' */
    sldemo_concurrent_execution_B.TaskTransAtPlantIn2 =
      sldemo_concurrent_execution_DWork.
      TaskTransAtControllerBOut1_buf_4[sldemo_concurrent_execution_DWork.fr_buf_4];
    sldemo_concurrent_execution_DWork.fr_buf_4 = 1 -
      sldemo_concurrent_execution_DWork.fr_buf_4;
  }

  …
}

void MdlInitialize(void)
{
  …

  /* InitializeConditions for TaskTransBlk: '<Root>/TaskTransAtController BOut1' */
  sldemo_concurrent_execution_DWork.fw_buf_4 = 0;

  …
}

データ転送中の最大データ整合性のために生成されたコード

[確定的に転送を保証 (最小遅延)] を選択した場合にデータ転送用に生成されるコードは、データ書き込みタスクによるデータの計算が完了するまでデータ読み取りタスクが待機することを保証します。この動作により、データ同期用のターゲット固有のコード (セマフォなど) が生成されます。

ソフトウェアによって次のようなコードが生成されます。このコードの例は、Linux プラットフォーム上の Plant/x に関するものです。

/*
 * This function updates continuous states using the ODE3 fixed-step
 * solver algorithm
 */
static void Periodic_Compensator_rt_ertODEUpdateContinuousStates(RTWSolverInfo
  *si )
{
  …
  /* TaskTransBlk: '<Root>/TaskTransAtCompensatorIn1' */
  if (sldemo_concurrent_execution_DWork.br_buf_5) {
    sldemo_concurrent_execution_DWork.br_buf_5 = FALSE;
  } else {
    rtw_pthread_sem_wait(sldemo_concurrent_execution_DWork.sw_buf_5);
    sldemo_concurrent_execution_B.TaskTransAtCompensatorIn1 =
      sldemo_concurrent_execution_DWork.TaskTransAtPlantOut1_buf_5;
    rtw_pthread_sem_post(sldemo_concurrent_execution_DWork.sr_buf_5);
    if (rtmIsMajorTimeStep(task_M[0])) {
      sldemo_concurrent_execution_DWork.br_buf_5 = TRUE;
    }
  }
  /* End of TaskTransBlk: '<Root>/TaskTransAtCompensatorIn1' */
  …
}
/* Output for Task: Periodic_Plant */
void Periodic_Plant_output(void)       /* Sample time: [0.0s, 0.0s] */
{
   …
  if (rtmIsMajorTimeStep(task_M[3])) {
    …
  /* TaskTransBlk: '<Root>/TaskTransAtPlantOut1' */
  rtw_pthread_sem_wait(sldemo_concurrent_execution_DWork.sr_buf_5);
  sldemo_concurrent_execution_DWork.TaskTransAtPlantOut1_buf_5 =
    sldemo_concurrent_execution_B.x;
  rtw_pthread_sem_post(sldemo_concurrent_execution_DWork.sw_buf_5);
}
void MdlInitialize(void)
{
 …
  /* InitializeConditions for TaskTransBlk: '<Root>/TaskTransAtPlantOut1' */
  sldemo_concurrent_execution_DWork.fw_buf_5 = 0;
  rtw_pthread_sem_create(&sldemo_concurrent_execution_DWork.sw_buf_5, 0);
}

スレッド API

Embedded Coder ターゲットおよび汎用のリアルタイム ターゲットの場合、マッピング モデルから生成されるコードは、タスクごとにスレッドを 1 つ作成し、ホスト マシン上で実行されているオペレーティング システムに対応したスレッド API を自動的に活用します。

  • ホスト マシンが Windows® プラットフォームの場合、生成されるコードは Windows スレッドを作成して実行します。

  • ホスト マシンが Linux または Mac OS プラットフォームの場合、生成されるコードは POSIX® pthread を作成して実行します。

同時実行の側面Linux 実装Windows 実装Mac OS 実装

周期的なトリガー イベント

POSIX タイマー

Windows タイマー

該当なし

非周期的なトリガー イベント

POSIX リアルタイム信号

Windows イベント

POSIX 非リアルタイム信号

非周期的トリガー

非周期的タスクにマッピングされているブロックの場合: 信号待ちスレッド

非周期的トリガーにマッピングされているブロックの場合: 信号アクション

イベント待ちスレッド

非周期的タスクにマッピングされているブロックの場合: 信号待ちスレッド

非周期的トリガーにマッピングされているブロックの場合: 信号アクション

スレッド

POSIX

Windows

POSIX

スレッド優先順位

サンプル時間に基づいて割り当て: 最速タスクに最高の優先順位

優先順位クラスは親プロセスから継承。

サンプル時間に基づいて割り当て: 最初の 3 つの最速タスクについては、最速タスクに最高の優先順位を割り当て。残りのタスクは最低の優先順位を共有。

サンプル時間に基づいて割り当て: 最速タスクに最高の優先順位

オーバーラン検出の例

あり

あり

なし

同時に実行しているタスク間のデータ転送は、「データ転送オプション」に示すように動作します。Coder は、この動作をサポートするターゲットで次の API を使用します。

Embedded Coder と汎用リアルタイム ターゲットによって使用されるデータ保護 API と同期 API

APILinux 実装Windows 実装Mac OS 実装
データ保護 API
  • pthread_mutex_init

  • pthread_mutex_destroy

  • pthread_mutex_lock

  • pthread_mutex_unlock

  • CreateMutex

  • CloseHandle

  • WaitForSingleObject

  • ReleaseMutex

  • pthread_mutex_init

  • pthread_mutex_destroy

  • pthread_mutex_lock

  • pthread_mutex_unlock

同期 API
  • sem_init

  • sem_destroy

  • sem_wait

  • sem_post

  • CreateSemaphore

  • CloseHandle

  • WaitForSingleObject

  • ReleaseSemaphore

  • sem_open

  • sem_unlink

  • sem_wait

  • sem_post

main() コードは常に動的に生成されます。生成されるメイン ファイルの全般的な構造は次の疑似コードに示すとおりです。

main()
{
  Model_initialize();
	For_each_periodic_task
	{
		Create_synchronization_event(periodic_task);	
		Create_thread(periodic_task);
	}
           For_each_aperiodic_task
	{
		Create_external_event(aperiodic_task);	
		Create_thread(aperiodic_task);
	}

     	Create_timer();
Create_thread(Periodic_task_scheduler);

For_each_aperiodic_trigger
{
	Hookup_isr_to_aperiodic_event();
}

Wait_for_stopping();
	Cleanup();
	Model_terminate();
	return 0;
}

Periodic_task_scheduler()
{
	Wait_for_event_from_timer(clock);
	For_each_periodic_task
	{
   		If periodic_task has a sample time hit
  			Set the event to run the task	
	}
}

Periodic_Task()
{
	Wait_for_event(Periodic_task_scheduler);
	Run the appropriate periodic_task();
}

Aperiodic_Task()
{
	Wait_for_aperiodic_event();
	Run the appropriate aperiodic_task();
}

Isr()
{
    Run the appropriate aperiodic_trigger ();
}

ネイティブ スレッド サンプル用の Embedded Coder の構成

Embedded Coder ターゲット用にコードを生成するには、[コンフィギュレーション実行] ダイアログ ボックスで以下の操作を行います。

  • [コード生成][テンプレート][メイン プログラム例の生成] チェック ボックスをオンにします。

  • [コード生成][テンプレート][ターゲット オペレーティング システム] リストの [NativeThreadsExample] を選択します。

ビルドとダウンロード

システム ターゲット ファイルを使用して、以下のターゲット用の同時実行モデルをビルドおよびダウンロードできます。

  • Linux、Windows および Mac OS (ert.tlc grt.tlc を使用)。

  • xPC Target™ (xpctarget.tlcxpctargetert.tlc を使用)

  • Linux および Windows (idelink_ert.tlcidelink_grt.tlc を使用)

  • 組み込み Linux および VxWorks® (idelink_ert.tlcidelink_grt.tlc を使用)

    メモ:   組み込み Linux および VxWorks の各ターゲットへの配布には、Embedded Coder 製品が必要です。

C++ (Encapsulated) 言語オプション用のコードを生成することはできません。

プロファイリングと評価

[同時実行] ダイアログ ボックスの [プロファイル レポート] ペインを使用して、マルチコア システム上でコードの実行をプロファイリングします。Simulink Coder (GRT) および Embedded Coder (ERT) ターゲットを使用してプロファイリングを実行できます。プロファイリングを行うと、実行のボトルネックとなっている領域をモデル内で特定しやすくなります。各タスクの実行時間を分析して、実行時間の大半を占めているタスクを見つけることが可能です。たとえば、タスクの平均実行時間を比較できます。計算量の多いタスクやリアルタイム要件とオーバーランを満たしていないタスクがある場合は、計算量が少なく同時実行が可能なタスクにそのタスクを分割することができます。

プロファイル レポートを生成すると、ソフトウェアは以下の処理を実行します。

  1. モデルを作成します。

  2. モデルのコードを生成します。

  3. データを収集する目的で、生成されたコードにツールを追加します。

  4. 生成されたコードをターゲット上で実行してデータを収集します。

  5. データを照合し、現在のフォルダーに HTML ファイル (model_name_ProfileReport.html) を生成して、[プロファイル レポート] ペインに HTML ファイルを表示します。

      メモ:   モデルの HTML プロファイル レポートが存在する場合、そのファイルが [プロファイル レポート] ペインに表示されます。新しいプロファイル レポートを生成するには、 をクリックします。

セクション説明

概要

合計実行時間やプロファイル レポートの作成時間など、モデルの実行に関連する統計情報をまとめて表示します。ホスト マシン上のコア プロセスの合計数も表示します。

Task Execution Time

タスク別に色分けされた円グラフに、各タスクの実行時間 (マイクロ秒単位) を表示します。

Windows、Linux および Mac OS プラットフォームで表示されます。

Task Affinitization to Processor Cores

プラットフォームに依存します。タイム ステップおよびタスクごとに、そのタイム ステップでタスクが実行されたプロセッサ番号をプロセッサ別に色分けして表示します。

特定のタイム ステップにスケジューリングされたタスクが存在しない場合、NR が表示されます。

Windows および Linux プラットフォームで表示されます。

プロファイル レポートを解析したら、Model ブロックのマッピングを明示的に変更することにより、マルチコア システムで利用可能な同時実行性を効率的に利用することを検討してください (「タスクへのブロックの段階的なマッピング」を参照)。

xPC Target や Embedded Coder などの一部の製品では、特定のターゲットでの実行をプロファイリングする場合に使用できるツールが用意されています。

製品詳細情報の参照先
xPC Target「Execution Profiling for Target Applications」
Embedded Coder「Perform Execution Time Profiling for IDE and Toolchain Targets」

プロファイル レポートの生成

このトピックでは、プロファイリングする同時実行に対して既に設定済みのモデルがあるものと仮定します。このようにモデルを設定する場合は、「モデルの構成」を参照してください。

  1. [同時実行] ダイアログ ボックスで [プロファイル レポート] ノードをクリックします。

    プロファイル ツールは、model_name_ProfileReport.html という名前のファイルを検索します。該当するファイルが現在のモデルに存在しない場合、[プロファイル レポート] ペインに以下のように表示されます。

      メモ:   モデルの HTML プロファイル レポートが存在する場合、そのファイルが [プロファイル レポート] ペインに表示されます。新しいプロファイル レポートを生成するには、 をクリックします。

  2. モデルの実行データをプロファイラーで収集する場合のタイム ステップの数を入力します。

  3. [タスク実行のプロファイル レポートを生成します] ボタンをクリックします。

    この操作により、モデルの作成、コードの生成、コードへのデータ収集ツールの追加、ターゲットでのコードの実行といった処理が行われて、HTML プロファイル レポートも生成されます。この処理には、数分かかることがあります。この処理が完了したら、プロファイル レポートの内容が [プロファイル レポート] ペインに表示されます。例:

  4. プロファイル レポートを解析し、必要に応じて新しいタスクの作成と再割り当てを行って、プロファイル レポートを再生成します。

コマンド ラインでのプロファイル レポートの生成

別の方法として、同時実行に対して構成されたモデルのプロファイル レポートをコマンド ラインで生成できます。関数 Simulink.SoftwareTarget.profile を使用します。

たとえば、モデル sldemo_concurrent_execution のプロファイル レポートを作成するには、以下の手順に従います。

Simulink.SoftwareTarget.profile('sldemo_concurrent_execution');

特定のサンプル数 (100) でモデル sldemo_concurrent_execution のプロファイル レポートを作成するには、以下のようにします。

Simulink.SoftwareTarget.profile('sldemo_concurrent_execution',120);

この関数は、sldemo_concurrent_execution_ProfileReport.html という名前のプロファイル レポートを現在のフォルダーに作成します。

この情報は役に立ちましたか?