実行速度の遅いiwup_tskに関連して「割り込み保留可能時間」2010年05月12日 02時46分13秒

前回の記事コメントをいただきました。

関心を持ってコメントいただき、ありがとうございました。

さて、少し認識の違うところがあると思います。

一番大きな認識の違いは「割り込み禁止時間」と「割り込み保留可能時間」です。

私は元の記事で割り込み禁止時間という言葉を使っておらず、割り込み保留可能時間という言葉を使っています。にも関わらず、割り込み禁止時間を引き合いに出されたのは恐らく、視点の違いの問題で同じ命題だと思い込んでおられるのではないかと思われます。

先に結論を申し上げますと、両者は別の命題になります。

「割り込み禁止時間」は特定のコンテキストの実行中に割り込み禁止にされると「他の」割り込み処理が実行出来ないという問題を議論する時の命題です。

それに対して「割り込み保留可能時間」というのは現在処理中のコンテキスト、つまり「自分の」割り込み処理が次の同じ要因の割り込みが発生するまでに終了することが出来るかどうか、ということを議論する時の命題です。 したがって、割り込み禁止というよりもその割り込み処理が次の割込みまでに終われるかということが最大の関心事なわけです。

例えばUARTでFIFOを持たないようなコントローラを使うとしましょう。 115200bpsで1文字10bitとします。この時、1文字の受信割込みが発生する間隔は約86μ秒です。

つまり、その受信割り込みが発生した時の割り込み処理は86μ秒未満の時間で処理を終わらせないと次の受信割込み処理が実行できずに、1文字のデータを取りこぼすことになります。 この時、割り込み保留可能時間は86μ秒です。

そんな状況で5μ秒で終わったり80μ秒で終わったりするような時間見積りが出来ないようなサービスコールは使い物にならないわけです。

だから、i付サービスコールの処理時間は「割り込み保留可能時間」とセットで考えなければいけないわけです。

※説明を簡略化するために「自分の」という表現を使いましたが、厳密に言うと「自分の」と「他の」割り込み処理時間の最大時間と割り込みタイミングや割り込み禁止区間のトータルの話になります。

設計に問題があるrcv_mbf2010年02月09日 00時39分53秒

rcv_mbf()は指定したメッセージバッファIDのメッセージバッファからメッセージを受信するまで待つサービスコールです。

メッセージバッファへの送信はsnd_mbf()を使います。

ここで問題。

snd_mbf()には送信サイズを指定して、そのサイズがメッセージバッファ生成時に指定した最大サイズを超えているとエラーリターンします。

一方rcv_mbf()は受信したメッセージサイズをリターン値として取得するようなインターフェースはありますが、異常動作を未然に防ぐような仕組みは全く用意されていない。 この仕様だとどうなるかというとバグによりRAM領域を破壊する可能性が高い。

  • バッファサイズ100バイトのメッセージバッファを生成
  • 送信サイズは可変
  • 送信側タスクがメッセージバッファに20バイトのメッセージを送信
  • 受信側タスクが10バイトの領域を指定して受信
  • 受信は正常完了
  • 受信のリターン値は20バイト
  • 受信タスクは異常に気付かない
  • 全く別のタスクでRAM破壊による異常動作が発生

というような不具合が平気で発生します。

rcv_mbf()にstrncpy()のような最大サイズを指定するようなインターフェースを用意するのが組込み屋さんとしての最低限の実装でしょう。 その上でエラーリターンしてくれないと・・・・

代替案としてはrcv_mbf()を直接使うのではなく、受信サイズと領域サイズをチェックするようなマクロを通常は使うようにする。というようなところでしょうか。

実行速度の遅いiwup_tsk2010年02月07日 00時46分16秒

現在開発に携わっている案件でμITRONを使っています。

このμITRONのiwup_tsk()が異常に遅い。 クロック周波数などは伏せますが、割り込みハンドラ内での実行速度に5us~80usというように幅がある。 サービスコールの前後でポートに出力してオシロスコープで観測した結果です。

私の認識ではiwup_tskはμITRONのサービスコール(システムコール)のなかでも最上級でシンプルで実行速度が速いつもりでいました。この認識を覆す遅さです。

遅いというよりも実行速度に幅があることが問題。こんなに幅があると割り込みハンドラの設計が出来ない。割り込み保留可能時間を見越せないということで非常に問題があります。

これは開発担当者の実装設計がまずいといわざるを得ないです。

私の認識では「iつきサービスコール」は以下のような実装である必要があると思っています。

  • 遅延ディスパッチは当然
  • 遅延ディスパッチの前の事前のキュー繫ぎ替え処理は関数本体では行わない
  • 関数本体では要求のためのマークをつけるだけ
  • キュー繫ぎ替え、割り込み復帰時のディスパッチ用のスタック操作は遅延ディスパッチ処理の一環として実施

実行速度に幅がある理由は想像では以下です。

  • 関数本体で遅延ディスパッチの事前準備まで実施
  • つまりレディキュー、待ちキューの繫ぎ替え処理まで行っている
  • 処理時間の違いはキューに繋がっているタスクの数に依存
  • キュー繫ぎ替えの結果によってディスパッチするタスクが割込みが入る以前のタスクかそうでないかによってコンテキストの扱いが変っている

遅延ディスパッチの実装上の意味を割り込みハンドラから抜けるタイミングまで遅らせて次の実行タスクにジャンプする程度のことだと勘違いしていないですかね。開発担当者は。

例えばサービスコール発行が一つではなく、複数の場合はこの実装だと処理時間の無駄が積算されます。

まあ、そんなに単純な理由ではないのかもしれませんけど。 ソースコード見ないことには真相は不明です。

いずれにしてもこんなに性能が悪いμITRONが出回っているのだとするとμITRONを使用したシステムの基本設計の最初の段階でサービスコールの実測作業が必要だということになります。 特に「iつきサービスコール」については実測必須です。 μITRONが速いということも主張できなくなりますね。

・・・・というところまで書いてきて、検索してたら使っているものとは違いますがdoxygenでTOPPERSのソース公開されているところを見つけました。結論としてはTOPPERSの実装が諸悪の根源みたいです。

これを見るとiwup_tsk()とwup_tsk()の実装はほぼ同じ。iwup_tsk()ではディスパッチを実行せずにディスパッチが必要かどうかのフラグを立てているところが違う。 だめじゃん。もっと前の段階の処理を省略しないと処理速度が一定にならないです。ディスパッチが必要かどうかを判定する処理自体も遅延させないと。つまり「wait_complete(tcb)」って関数コールはここでやったらだめです。キューの状態に依存する処理は処理速度が一定にならないですから。

こちらにも解説がありますね。

このような状況が放置されているのは最近のμITRONのカーネルの開発者と実際の組込みシステムの開発者の意識が違いすぎるということなのかもしれません。μITRON2.0の時代は現場の人間がμITRONカーネルの開発をしたので学者じゃなかったと思います。

今のμITRONカーネル開発者は「学者」ってことです。本当の性能要件が分かっていない。 割り込みハンドラの実装部分から設計をやり直したいですね。 メモリ保護とかよりもこっちが先でしょ。

プログラマは言葉と解釈の自動変換をしてはいけない2009年12月22日 23時47分42秒

現在、またまた短期で請けている助っ人案件ですが、基本設計、ポリシー設計などを行っています。

さて、私のμITRONベースのソフトウェア基本設計書でdly_tskでループしてdly_tskから起き上がるたびに他のタスクにタイムアウトイベントを通知するタイマータスクの実装を指示していました。

周期ハンドラの使い方が間違っている開発だったので新規追加部分ではタスクで大まかなタイマ監視を実現することが目的です。

設計書にも「タスク生成・タスク起動」とか、名前もタイマ監視「タスク」って書いているにもかかわらず、実装担当者は「周期ハンドラ」を生成していました。 いちいちコードは見ないので「出来た」ということばを信じて任せていたら、デバッグで動かない。

なんせ、周期ハンドラでdly_tsk(1)などをコールしているものだからぜんぜん駄目です。wdtでシステムがリセットしてしまいます。 周期ハンドラでdly_tsk()は使えません。待てないんだから。 多分処理的には永久ループになってしまう。

今回のプログラマ向けの教訓は以下です。

  1. 自分を信じて、自分の思い込みで言葉の自動変換をしてはいけない
  2. 仕様書に書いてあることをそのまま実装することを心がける
  3. タスクはタスク、ハンドラはハンドラ。違うものだよ!!
  4. 設計者が間違っていて自分が正しいと思ったらきちんと実装前に意見する

どこに問題があるの?2009年12月18日 23時13分37秒

μITRONのセミナーをやっている会社の社員の言葉です。

データキューやメッセージバッファのメッセージ内容として特定の領域のポインタを格納することが可能です。 良くある手法ではあるのですが、この方式とセットの考え方は格納する領域はキュー構造で別途メモリを管理している領域である必要があります。もちろん、μITRONのメモリプールで確保した領域でもOKです。

ところが、既存の開発物でメッセージ内容にポインタを格納してデータを他のタスクに渡している部分があるのですが、その領域がスタック(自動変数領域)だったり、1個しかないスタティックな領域だったりしています。

この実装に問題があると感じる人は組込みソフトウェアの開発者として合格です。

いくら問題点を説明しても聞く耳を持たない。最後には「どこに問題があるの?」と逆切れされる始末です。 一つの機器の開発を分担しているわけですが、これ以上は彼らが自力で成長するのを待つしかないです。