プロフィール

kosaki

Author:kosaki
連絡先はコチラ

ブログ検索
最近の記事
最近のコメント
最近のトラックバック
リンク
カテゴリー
月別アーカイブ
RSSフィード
FC2ブログランキング

スポンサーサイト このエントリーをはてなブックマークに追加

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。


スポンサー広告 | 【--------(--) --:--:--】 | Trackback(-) | Comments(-)

CONFIG_VIRT_CPU_ACCOUNTINGまとめ このエントリーをはてなブックマークに追加

CONFIG_VIRT_CPU_ACCOUNTING

会社で近くに座っているすごい優秀な技術者がCONFIG_VIRT_CPU_ACCOUNTINGをいじっていたので、うらまやしくなってi386版でも作ろうかとほげり始める。

が、いろいろと 2.6.24-rc6 だと構造が変わっていて元々のパッチは素直に移植できないことが分かったので、いまのCPU時間統計の仕組みをちょいと調べてみた

以下はほぼ自分用の備忘録

1.VIRT_CPU_ACCOUNTINGとはなにか?
  名前がよくないのだが、最近流行の仮想化とはまったく関係ない。
  よーするにcpu時間情報がtick単位でしか集計できないのは今となっては荒すぎるので
  tscレジスタ相当の機能を使ってもっと細かくとれるようにしましょう。と
  そういう機能

2.どうやってつかうの?
  netlink機能のなかのtaskstatの情報を吸い出すことで見ることができる。
  サンプルが linux/Documentation/getdelays.c あたりにある

3.サポートされてるプラットフォームは?
  ppcとs390(だけ)
  よく、MIな部分にコードつっこめれたよね

4.ポーティング方法は?
  POWERがMD層でやっている事を以下に列挙するのでそれを真似してちょ
  # なお、POWERには時間を取得するレジスタが3種類あって、それぞれ意味が違う。
  # それは記事末尾で補足する。


A. 移植したいアーキのKconfig にCONFIG_VIRT_CPU_ACCOUNTINGを追加

B. include/asm/cputime.h を書き換えてcputime_tの粒度をtickからPURR
の粒度に定義しなおす。

C.システムコールの入り口で以下の処理をおこなう
  - PURRをとる
  - get_paca()->startpurr とPURR現在値の差分をget_paca()->user_timeに加算する
  - get_paca()->startpurr にPURR現在値を保存

D.システムコール出口で以下の処理を行う
  - PURRをとる
  - get_paca()->startpurr とPURR現在値の差分をget_paca()->system_timeに加算する
  - get_paca()->startpurr にPURR現在値を保存

E.__switch_toに以下の処理を追加
    account_system_vtime(current);
    account_process_tick(current, 0);
    calculate_steal_time();

要するに、プロセスコンテキストの切り替えの直前に今までper_cpu変数にためこんでおいた
CPU時刻を吐き出しているのである

F. account_system_vtime という関数を作る。これはirq, softirqの出入り口と
  __switch_toから呼ばれる関数。
  以下のように定義する
  (ここのPOWERの実装は気が狂ってるとしか思えないのでS390も併記する)
  - PURRとget_paca()->startpurrの差分をとる(delta)
  - get_puaca()->startpurrを現在時刻で初期化
  - SPURRとget_paca()->startspurrの差分をとる(deltascaled)
  - get_puaca()->startspurrを現在時刻で初期化
  - 割り込み中じゃなければ以下の補正
   o deltascaled *= system_time / (system_time + user_time)
    これは全体の時間中のsystem_time時間の%を意味する。
    って、システムコールの出入り口でstartspurrを更新してないのはおかしいんとちゃうか・・
   o delta += system_time
   o get_paca()->system_timeを0初期化
  - account_system_timeをdeltaを引数にして呼び出す
   ここで、hardirq_offset引数を常に0にしているのはたぶんバグ
   preempt_count()で簡単にとれるはずやろ・・・   
  - account_system_time_scaledをdeltascaledを引数にして呼び出す
  - get_paca()->purrdelta = delta
  - get_paca()->spurrdelta = deltascaled

  以下、S390の場合 
  - CPUタイマの前回時刻との差分をsystem_timeにセット
  - CPUタイマの前回時刻を現在時刻にセット
  - account_system_timeを呼び出す

G. update_process_times()から呼ばれるCPU時間更新処理account_process_tick()が
  MIな定義部分が #ifndef CONFIG_VIRT_CPU_ACCOUNTING
  で囲まれているので、自分のアーキのMD部分に自分用の定義を作る。

  - 引数user_tickは無視(CPUのレジスタでもっと細かい時間がとれるから)
  - get_paca()->user_time を引数に account_user_time()を呼び出す
  - get_paca()->user_time * spurrdelta / purrdelta を引数に account_user_time_scaled()を呼び出す
  - get_paca()->user_time, get_paca()->spurrdelta, get_paca()->purrdeltaを0で初期化

 なお、purrdelataが0でないことは以下で保障している(0割の考慮がないコードに見えたので調べた)
  - hard irq の出入り口でaccount_system_vtimeが呼ばれているので、ここを通るときは
 絶対purrdelta, spurrdeltaに値が入っている
  - 後述する __switch_toから呼ぶときもaccount_process_tickの直前にaccount_system_vtimeを呼んでいる


<補足 POWERの時間関係のレジスタの違いについて>
TB:    現実世界の時間と同じように進む。チップセットのタイマーでいいじゃんという気がしなくもない
PURR:  SMT時に自分がactive stateだったcycleのみカウンタがすすむ周波数カウンタ
haltしてもう一方のスレッドに処理をゆずっているときはカウンタは増えない
SPURR:  PURR * (feffective/fnominal) * (1 - cyclesthrottled/cyclestotal)
       などというよく分からない数式で定義されているカウンタ。ようするに省電力モードで
       周波数が落ちたときはそれに応じて進み方が遅くなる。と

ちなみにaccount_user_time_scaled()のscaledはSPURRがScaled PURRの略だからだ。ばかすぎる

なので、PURRだと省エネモードのときに実際の動いたクロックよりもすんげー速く進んでしまって
悲しい思いをすることになる。

困ったことにx86はtscの定義があいまいなので、省エネモードのときの動作はimplementation defined
っぽい気がする

<補足2 結局scaledtimeとstealedtimeってなんなん?>
scaledtime:省電力モードで周波数が半分になっているときは半分だけカウントアップしてくれる
steal:     SMTの相方のせいで動けなかった時間
        (これが計測できるってことはPOWER5の公称SMTは実装としてはVMTってことだよね:)


急いでいたので、乱文、失礼。


三河屋ーーーーー
急いでいたので! ランキング!

関連記事


linux | 【2008-01-01(Tue) 02:18:45】 | Trackback:(0) | Comments:(0)
  1. 無料アクセス解析
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。