やぁみんな、ビリーだよ。
今日は、ビリー宛てにもらった質問を紹介しよう。
読者からの質問
スタックってなあに?(2)のスタックオーバーフローの説明で、「この関数を「スタックメモリを1KBしか持っていない」タスクAがコールしたらどうなるだろう」と書いてありますね。どうして、1KBしかないか? どうして2KBあるいは512Bではないか? 1KBになる理由はなんでしょうか?
また、実は何Byteなら大丈夫かを調べる方法はありますか?
質問ありがとう。
「この関数を「スタックメモリを1KBしか持っていない」タスクAがコールしたら どうなるだろう」
と書いたけど、少しわかりにくかったかもしれないね。
ビリーからの回答
この例では、タスクが持つスタックサイズよりも大きな配列(char buf[4096])を取るとオーバーフローしてしまう、という例を挙げただけで、この場合のタスクAのスタックサイズは 2KB でも 4KB でも構わないよ(オーバーフローするからね)。
最後に書いてある、『では何バイトであれば大丈夫か?』という質問は非常に重要なんだ。これを論理的に計算するのはなかなか難しいんだよ。
例えば open()や read()関数自体も内部的にスタックを使用するし、ファイルの大きさなどにも影響されるかもしれないからね。
実際にはある程度大きなスタック領域を割り当てておき、実際にプログラムを何度も動作させて消費されているスタックサイズを実測し、問題のない範囲で減らしていく、というのが現実的なチューニング方法として広く採用されているみたいだ。
「実際に消費されているスタックサイズ」を測定する方法は、これまたいろいろとあるのだけどICE とデバッガがそのような機能を持っていることがあり、これを使うのが一例だよ。スタックポインタ(SP レジスタ)の内容をタスクごとに記憶しておき、その最大値が最大消費量ということになるね。
ソフトウェアで簡易的に調べる方法もあるんだ。タスク起動時にスタックを割り当てるけど、これをあるデータパターン(例えば 0xef とか)で埋めておく。
スタックの最大消費量は、0xef のデータがどこまで書き換わっているかを見ればわかるよ。例えばスタックの 100 バイト分が 0xef 以外の値、100 バイト以降が 0xef 以外であれば最大消費量は 100 バイトだったとわかるんだ。
ただしこちらの方法は、たまたま 0xef というデータをスタックに書き込んだような場合は起動時に設定されたものか、途中で書き込まれたものかが区別できないため、必ずしも正確ではない、という問題もあるけどね (でも、おおよその目安をつけるという意味では有効だから、市販 OS などでも採用されている方法だよ)。
例えば4KB(4096バイト)のスタックを持つタスクのスタック消費量を確認する方法を考えてみよう。スタックはCPUによって、初期値からアドレス減少方向に伸びていくものとアドレス増加方法に伸びていくものがあるけど、下に書くのは、アドレス減少方向に伸びていく場合の例だよ。
(1)タスク起動時
スタックを0xefというデータで埋めておく。このとき、スタックの初期値(ベースアドレス)を覚えておく。
例:ベースアドレス(0x6000)
(2)スタック最大消費時
ある時点で、スタックの最大消費サイズが2800(=0xAF0)バイトまで進んだとする。
スタックポインタは0x5510まで進んだ。スタック消費量は0x6000-0x5510=0xaf0(=2800)。
図中の黄色部分がスタックとして使用されたことになるね。
たまたまefというデータが入っている場合があるので、例えば0xefが連続で3回出てきたら未使用データと判定するといった工夫をしておくよ。
(3)現在の状態
スタックの現在消費量および過去の最大消費量は、以下のように計算できるよ。
スタックポインタは0x5780。
スタックの現在消費量は、0x6000-0x5780=0x880(=2176)バイト。
スタックの過去最大消費量は、SP現在値からアドレス減少方向にデータをたどり、0xefが3回連続で出てくる箇所(0x5510)を探し、これが0x5510番地なので(2)の通り2800バイトとなるね。
さて、ビリーはいつでもみんなからの質問を待っているよ。また、解説してほしいテーマがあれば、リクエストも受付中!!
-
- 第1回 組込みシステムのこれから
- 第2回 IoTの成功はセキュリティ次第
- 第3回 組込みでもGPUやFPGAと早めに親しんでおこう
- 第4回 電子産業の紅白歌合戦、CEATECで垣間見えた未来
- 第5回 小口開発案件の集合市場、IoTの歩き方(上)
- 第6回 小口開発案件の集合市場、IoTの歩き方(下)
- 第7回 徹底予習:AI時代の組込みシステム開発のお仕事
- 第8回 いまどきのセンサー(上):ありのままの状態を知る
- 第9回 いまどきのセンサー(下):データを賢く取捨選択する
- 第10回 組込みブロックチェーンの衝撃(上)
- 第11回 組込みブロックチェーンの衝撃(下)
- 第12回 エネルギーハーベスティングの使い所、使い方
- 第13回 「人を育てる」から「道具を育てる」へ、農業から学ぶAI有効活用法
- 第14回 CPS時代に組込みシステム開発に求められることとは
- 第15回 次世代車のE/Eアーキテクチャに見る組込みの進む道
- 第16回 RISC-Vが拓く専用プロセッサの時代
- 第17回 振動計測の大進化で、熟練エンジニアのスキルを広く身近に
-
- 零の巻:組込みというお仕事
- 壱の巻:2進数と16進数を覚えよう!
- 弐の巻:割り込みとポーリング
- 参の巻:printf()が使えない?
- 四の巻:これにもIntelが入ってるの?
- 五の巻:Endianってなに?
- 六の巻:マルチタスクとは
- 七の巻:スタックってなあに?(1)
- 七の巻:スタックってなあに?(2)
- 八の巻:メモリを壊してみましょう
- 九の巻:コードが消える?~最適化の罠~
- 拾の巻:例外が発生しました
- 拾壱の巻:コードサイズを聞かれたら
- 拾弐の巻:キャッシュは諸刃の剣
- 拾参の巻:デバイスにアクセスするには
- 拾四の巻:セキュリティってなに?(1)
- 拾四の巻:セキュリティってなに?(2)
- 拾四の巻:セキュリティってなに?(3)
- 拾五の巻 :DMA対応と言われたら(1)
- 拾五の巻 :DMA対応と言われたら(2)
- 拾六の巻:ヒープとスタック
- 拾七の巻:フラグメンテーション
- 拾八の巻:CPU起動とブートローダ
- 拾九の巻:kmとKByteの「kとK」
- ビリーへの質問:DMAとキャッシュの関係
- ビリーへの質問:スタックオーバーフローについて
- ビリーへの質問:CPUレジスタについて