(toppers-users 3855) Re: SSP 同一実行優先度のディパッチアルゴリズムの機能の追加

koizumi yoshiyuki koizumiyoshiyuki @ gmail.com
2012年 1月 30日 (月) 20:41:58 JST


 高橋さま

こいさんです。
1.
は高橋さんの指摘通りです。誤りが有りました。意図は終了したタスクと次に起動すべきタスクの優先度同一のとき、次に起動するタスク決定を現状アルゴリズムとは別な選択が出来るようにすることに有ります。
下記ではどうでしょうか。

  if(primap_empty())break;
  next_pri = search_schedtsk();
  if(runtsk_ipri == next_pri){
//   runtsk_ipri = semePri();
   runtsk_ipri = next_pri;
  }else if(saved_pri <= next_pri){
   break;
  }else{
   runtsk_ipri = tinib_epriority[next_pri];
  }
 } while(1);

2.は処理が終了したとき次の起動する優先が等しいときと考えたので、同一優先度ではプリエンプトしません。
説明が混乱するかも知れませんが、「_kernel_tinib_epriorityで同一実行優先度が隣り合っているときのみ」優先度が同一だとの認識です。(これは私流の考え方かも知れません)。起動優先度と実行優先度の指定で、以前私が書いた、優先度逆転する場合は同一優先度としないことが前提でになっています。この為には、runtsk_ipriとして起動優先度と実行優先度を持つ必要があります。
優先度が逆転した場合の処理はsemePri();の中で考えればよいかと手抜きをしています。

以上
2012年1月30日19:34 高橋和浩@nifty <takahashi_kazuhiro @ nifty.com>:

> こんさんさん
> こんばんは、アライブビジョンソフトウエアの高橋です。
>
> (toppers-users 3834)はだいたい合ってるかなと思っていますが、
> これはちょっと違うと思います。メールで説明できないケースもあるので、
> 開発者からコメントいただいたほうがいいと思います。
>
> たぶん1点間違えと、もう一点コメントします。
>
> 1.  }else if((saved_pri == (next_pri = search_schedtsk()))){
> これは、戻り先の実行時優先度と今起動されたタスクの起動時優先度の比較ですよ。
>
>
> 2.プリエンプトできても狭義の省スタック化できないですよね
> 改造方法はいろいろあると思いますが、実行時優先度が同一で起動時優先度の違うものを
> 同一優先度として扱い、後押し優先でスケジュールすることも実装上可能だと思いますが
> プリエンプトされるということは、(toppers-users 3839)の狭義の省スタック化はできない
> ので、それよりも (toppers-users 3818)の5.先取り方式の提案 のほうがいいと思います。
> FCFSのスケジューリングになります(共通用語で書くようにします)。
>
> (toppers-users 3818)には考え方しか書いていなかったので補足します。
>
>
> ------------------------------------------------------------------------------
> UB      pri_tbl[16];
>
> 初期化時
> pri_tbl[0] = 0;
> pri_tbl[1] = 1;
> 〜同様〜
> pri_tbl[15] = 15;
>
>
>
> --------------------------------------------------
> まずスケジューラ部分
> テーブルから引いてくるのみです。
> 起動時優先度(0-15)から実態のTCBを参照する場合にpri_tblをかまして合わせこみます。
> スケジュールビットの演算はそのままやります。
>        do {
>                runtsk_ipri = tinib_epriority[pri_tbl[next_pri]]; // ここと違うだけ
>
>                /* CPUロック解除 */
>                t_unlock_cpu();
>
>                /* タスク実行開始 */
>
>  (*((TASK)(tinib_task[pri_tbl[next_pri]])))(tinib_exinf[pri_tbl[next_pri]]);
> //ここが違うだけ
>
>                if (t_sense_lock()) {
>                        /*
>                         *  CPUロック状態でext_tskが呼ばれた場合は,CPUロックを解除し
>                         *  てからタスクを終了する.実装上は,サービスコール内でのCPU
>                         *  ロックを省略すればよいだけ.
>                         */
>                }
>                else {
>                        /*
>                         *  このt_lock_cpuをこの下のdisdspの設定のようにしないのは,
>                         *  CPUロック中に再度t_lock_cpuを呼ばないためである.
>                         */
>                        t_lock_cpu();
>                }
>
>                /* 割込み優先度マスクは全解除状態のはずなので,何もしない */
>
>                /*
>                 *  ディスパッチ禁止状態でext_tskが呼ばれた場合は,ディスパッ
>                 *  チ許可状態にしてからタスクを終了する.
>                 *
>                 *      本来は以下のように記述すべきであるが,いずれにせよdisdspを
>                 *      falseにすればいいため,単にfalseに設定する.
>                 *
>                 *              if (disdsp) {
>                 *                      disdsp = false;
>                 *              }
>                 */
>                disdsp = false;
>
>                /* ビットマップクリア. */
>                primap_clear(next_pri);         //ここはそのまま
>
>          /* 戻り先タスクの実行時優先度より高い起動時優先度をもつタスクが起動されたか */
>        } while((!primap_empty()) && (saved_pri > (next_pri =
> search_schedtsk())));     //ここもそのまま
>
>
> -------------------------------------------------
> あとタスク起動のときに起動時優先度をスワップする。iact_tskのみだけど act_tskも同様だと思う。
>
> iact_tsk(ID tskid)
> {
>        ER              ercd;
>        uint_t  ipri;
>        uint_t  ipri_org;               // オリジナルの起動優先度
>        uint_t  same_stack_map;         //狭義の省スタック化できるタスクマップ
>
>        LOG_IACT_TSK_ENTER(tskid);
>        CHECK_INTCTX_UNL();
>        CHECK_TSKID(tskid);
>        ipri_org = pri_tbl[get_ipri(tskid)];                    //
> tblからデータを持ってくるようにする
>
>        i_lock_cpu();
>        if (test_dormant(ipri_org)) {
>
>                same_task_map = get_task_map_same_group(taskid); // たとえば
> タスク1とタスク2が狭義の省スタック化なら 0x03を返す。
>                if (same_task_map !=0)
>  //非該当は従来どおり、非該当なら0を返す仕様とする
>                {
>                        same_task_map = &(~ready_primap);               //
> すでに実行可能状態のものはマスクする
>                        ipri =  bitmap_search(same_task_map);           //
>  同一グループの中で起動優先度の高いものを選ぶ
>                        pri_tbl[ipri] = ipri_org;                       //
> スワップする
>                        pri_tbl[ipri_org] = ipri;
>                }
>                else
>                {
>                        ipri = ipri_org;
>                }
>
>                if(make_active(ipri)) {                         //
> これでビットマップだけ起動優先度が高いものに
>                                                                // セットされる。
>                        reqflg = true;
>                }
>                ercd = E_OK;
>        }
>        else {
>                ercd = E_QOVR;
>        }
>        i_unlock_cpu();
>
> ----------------------------------------
>
> get_task_map_same_group()はサボりましたが、cfgのテーブルをどう料理するかの話なので
> 割愛してます。
> これで実現できると思いますがいかがでしょうか?
>
>
>
> On Mon, 30 Jan 2012 15:52:54 +0900
> koizumi yoshiyuki <koizumiyoshiyuki @ gmail.com> wrote:
>
> >  こいさんです
> >
> > 同一優先度で過負荷になった場合ディスパッチされないタスクが発生する問題の、一つの対策案です。
> >
> > ・ 同一優先度のディパッチアルゴリズムを追加できるようにrun_task()を変更して見ました。
> >
> > void run_task(uint_t ipri)
> > {
> >  uint_t next_pri; /* 次に実行開始するタスクの起動時優先度 */
> >  uint_t saved_pri; /* 呼び出し元タスクの起動時優先度 */
> >
> >  next_pri = ipri;
> >  saved_pri = runtsk_ipri;
> >
> >  runtsk_ipri = tinib_epriority[next_pri];
> >  do {
> >   /* CPUロック解除 */
> >   t_unlock_cpu();
> >   /* タスク実行開始 */
> >   (*((TASK)(tinib_task[next_pri])))(tinib_exinf[next_pri]);
> >   if (t_sense_lock()) {
> >   }else {
> >    t_lock_cpu();
> >   }
> >   disdsp = false;
> >   /* ビットマップクリア. */
> >   primap_clear(next_pri);
> >   if(primap_empty())break;
> >   if((saved_pri < (next_pri = search_schedtsk()))){
> >    break;
> >   }else if((saved_pri == (next_pri = search_schedtsk()))){
> > //   runtsk_ipri = samePri();
> >    break;
> >   }else{
> >    runtsk_ipri = tinib_epriority[next_pri];
> >   }
> >  } while(1);
> >
> >  runtsk_ipri = saved_pri;
> > }
> >
> この修正でsample1は従来と同様に動作するはずです。samePri();に同一実行優先度のディパッチアルゴリズム処理を組み込めは、その他は従来と変わりません。アルゴリズムの修正には起動優先度も必要でしょう。runtsk_ipriをunionにして起動優先度、実行時優先度を保存します。_kernel_tinib_epriorityで隣接する同一実行優先度タスクをラウンドロビンに修正するのは容易だと思っています。ラウンドロビンはFCFSでは有りませんが、サービスされないケースは回避できます。
> >
> > ・
> >
> 別件ですが、基本的にrun_taskはロック解除で動作させたいと思っています。ディパッチ関連でロックが必要なのはready_primapのsetとclearなので(読み出しはロック不要)、ここだけロックすればよいはずです。runtsk_ipriに2つの情報を含めた場合、個別にアクセスすればロックが必要になりますが、unionで同時にアクセスすれば回避できるでしょう。うまくやれば、act_taskのキュー処理追加も容易に出来ると思っています。
> >
> Cortex-M3に限るなら、ビットバインドエイリアスを使えばready_primapのsetとclearをロックを使わずにアトミックに実現できます。ロック時間の短縮は、確証はありませんが、出来そうな気はしています。
> > SSP程度の機能なら、色々面白い作り方が有ると思っています。
> >
> > 以上
> ---
> アライブビジョンソフトウエア株式会社
> 高橋和浩
> 673-0005兵庫県明石市小久保2-2-7幹線ビル4F
> Email:takahashi_kazuhiro @ nifty.com
> http://homepage3.nifty.com/ALVS/
>
-------------- next part --------------
HTMLの添付ファイルを保管しました...
URL: <http://www.toppers.jp/pipermail/users/attachments/20120130/73c2c942/attachment.html>