Linux Native KVM Toolsのメモリ割り当て

LKNTが仮想マシンにメモリをどのように割り当てているのか調べました. 流れとしては,ゲスト作成時にメモリを確保,KVMに確保したメモリを伝える,ゲストが終了する際に確保していたメモリを開放という手順です. 今回はユーザ側のコードですが,いずれはKVMの内部でメモリがどのように扱われているのかも調べてみたいです.

ユーザインタフェース


ユーザがゲストに割り当てるメモリのサイズを指定するにはコマンドライン引数を用います.

メモリ確保


指定した値は,グローバル変数のram_sizeに格納されます.

build-run.c/int kvm_cmd_run

コマンドライン引数で指定しなかった場合どうなるのでしょうか? build-run.cの中でram_sizeに値が格納されているかどうかを確認し,格 納されていない場合はget_ram_size関数で割り当てるメモリサイズを算出 し,ram_sizeに格納します.

build-run.c

get_ram_sizeには使用可能なCPUコア数を渡しています.そして,コア数からメモリサイズを算出します. コア数が2なら,64x(2+3)=320MBとなるようです. ゲストに割り当てられるメモリサイズはマシン全体のメモリサイズにRAM_SIZE_RATIOを掛けたサイズとなります. 算出したメモリサイズが割り当てられる限界値を越えている場合,限界値に修正してram_sizeを返却します.

build.c/host_ram_size

get_ram_sizeの中で呼び出されているhost_ram_size関数はホストマシンのメモリサイズを調べる関数です. sysconf(_SC_PHYS_PAGES)で物理メモリのページ数を取得,sysconf(_SC_PAGE_SIZE)でページサイズをバイト単位で取得します. ページ数xページサイズ=メモリサイズ(バイト)となります. 最後に単位をメガバイトに変更して返却します. メガバイトに変換する時,右シフトを使っています.

build.c

1メガバイト = 1048576バイトで,2進数にすると1048576 = 0b100000000000000000000となります. これを20ビット右シフトすると1になり,バイトからメガバイトへ変換ができるわけです.

build-run.c/int kvm_cmd_run

ゲストに割り当てるメモリのサイズが最小サイズより大きいか,もしくはホストのメモリサイズより大きくなっていないか確認します. 問題なければ,ram_sizeをメガバイトからバイトに戻しています.

KVMへ確保したメモリを登録する

さて,kvmの初期化関数に移動しましょう.

builtin-run.c/kvm_cmd_run

kvm_initは,さらにアーキテクチャ固有のinit関数を呼び出しています.

kvm.c/kvm__init

x86/kvm.c

kvm->ram_sizeにコマンドライン引数から取得した/自動生成したメモリサイズを格納します. ここで,32bitのギャップについてチェックしています.

KVM_32BIT_GAP_SIZEは (768<<20) = 805306368 = 768MB. KVM_32BIT_GAP_STARTは ((1ULL << 32) – KVM_32BIT_GAP_SIZE) = (4294967296 – 768MB) = (4096MB -768MB) = 3328MB.

指定したram_sizeが3328MBより小さい場合,そのサイズをmmapで確保します. ram_sizeが3328MB以上の場合,ram_size+768MBをmmapでマッピングします. メモリのマップに成功した場合,mprotectを使ってkvm->ram_start + KVM_32BIT_GAP_START〜KVM_32BIT_GAP_SIZEのメモリ範囲のアクセス保護を設定しています. PROT_NOTEは,メモリに全くアクセスできない設定となります. メモリのマップに失敗した場合はdieです.

madviceはメモリの利用に関するアドバイスを設定する関数です. kvm->ram_startからkvm->ram_sizeの範囲について,MADV_MERGEABLEに設定しています.MADV_MERGEABLEは,ユーザがマージしてもよいという設定です.

メモリの設定

build-run.cでしばらく先にあるkvm__init_ramでメモリ設定を行います.

builtin-run.c

x86/kvm.c

ここでも32ビットギャップを調べて,結果によって挙動を変えています. メモリサイズが3328MBより小さい場合,ゲストに設定する仮想メモリのサイズにkvm->ram_sizeを,ホストメモリの開始位置にkvm->ram_startを格納し,kvm__register_memを呼び出してVMのメモリの設定を行います.

3328MB以上の場合,仮想メモリのサイズに3328MBを設定してVMのメモリ設定を行い, その後,残りのサイズを再びVMに設定しています.

/kvm.c

ioctlのKVM_SET_USER_MEMORY_REGIONを使い,VMにメモリの変更を許可します.

KVM_SET_USER_MEMORY_REGIONはKVMのAPIです. mem_slotsがマザーボードのメモリスロットに対応するようです. 3328MB以上のメモリを扱う場合は,複数スロットに分割するわけですね. これで,VMがメモリを使えるようになります.

メモリの開放

VMを終了するときにメモリを開放する必要があります.kvm__deleteの中で開放されています.

builtin-run.c

kvm.c

munmapを使い,指定したアドレス範囲のマップを消去するだけのようです.

Emacsのデータストアを見てみる

本記事はEmacs Advent Calendar jp: 2011 : ATNDの23日目です. emacs lispで,keyとvalueを扱う方法について調べていたので,そのま とめです. emacs lispでkey-valueを扱う方法としては,alist(連想リスト), plist(属性リスト),ハッシュテーブルがあるようです. alistとplistはS式を使ったもので,シンプルです.ただ,リストを順番 に見ていくため,計算量は最悪の場合O(n)となり,効率が悪そうです. ハッシュテーブルの場合,計算量はO(1)なので,大量のデータを扱う場 合はplistやalistより速いのですが,データをS式で扱うのではなくハッ シュテーブル型になります. どれを使うかは,用途によるでしょう,plistはユーザが設定を書く時に よく使われますね.

alist(連想リスト)

alist(association list)はコンスセルを用いたリスト.

keyを与えるとkeyとvalueのコンスセルが返ってきます.valueを取り出 すためにcdrを使うのが少し手間な気がします.

plist(属性リスト)

plist(property list)は属性を保持するためのリスト.

個人的に好きなデータ構造です.リストなので扱いやすいためです.

hash table

名前の通り,ハッシュテーブル.

ハッシュテーブルは,今回調べていて初めて存在を知りました.Emacsで 大量のkeyとvalueを扱う場合は素直にハッシュテーブルを使うのがよさ そうですね.

おわりに

EmacsLispでkeyとvalueを扱う構造について紹介しました. Emacs で IPC や RPC (Emacs Advent Calendar jp: 2011) – 技術 日記@kiwanamiのように,emacs lispから外部の言語やDBにアクセスす る試みも行われています.RDBやKVSをemacsから使う日もそう遠くはなさ そうです.

ありえるたんがかわいい

こんにちは,来年の4月からアリエルで8クイーンを書く予定になっている r_takaishiです.Ariel Advent Calendar 2011 : ATNDの22日目です. CTOに誘われたので書くことにしたのですが, 社内ネタを持っていないので,ありえるの中の人であるありえるたん を紹介 します.

twitterでは,ありえるえるあの更新告知をしたり,時々呟いているよう です.ArielAdventCalendarでも記事を書いていて ,なかなか活発ですね.さて,前から気になっていたのですが,ありえるたんのアイコンは こんなアイコンです.

http://a2.twimg.com/profile_images/1374385066/20110529kaeru-ariel-400.jpg

かわいいですね.なぜカエルスーツなのでしょうか?気になります.

http://a0.twimg.com/profile_background_images/145928719/20100907ariel-autamn-500.jpg

カエルスーツを脱ぐとこんな格好のようです.かわいいですね.アリの 触角みたいなのがチャームポイントのようです.

かわいいので,ぜひグッズ化してほしいですね.明日は,闇えるたん さんです.

Linux Native KVM Toolsを使ってみよう

少しずつ認知され始めたLinux Native KVM Tools(NLKT)を使ってゲス トを起動する方法について解説します.この記事は,カーネル/VM Advent Calendar : ATNDの11日目です.

Linux Native KVM Toolsとは?

今広く使われているKVMは,QEMUを用いたものですが,Linux Native KVM Tools(以下LNKT)は,QEMUを使わず1から書いたVMMです.またカーネルの メインラインにはマージされていませんが,近い内にマージされるよう です.Github上(penberg/linux-kvm – GitHub)で開発が行われています.

使ってみる

さて,何はともあれまずは動かしてみましょう. 私は,X60s,i386,GentooLinuxで検証しています.えらく古い環境です が,VTは動くので検証する分には問題ありません.

まずはソースコードを入手します.Githubからリポジトリをcloneするの が一番簡単です.

linux-kvm/tools/kvmに移動してmakeしましょう.

とりあえず動かすために,linux-0.2のディスクイメージを使います.ダ ウンロードして展開しておきます.

kvm-toolsではディスクイメージとは別にカーネルイメージが必要です. ホストマシンで使っているカーネルイメージを使ってもいいでし, linux-kvm用に作ってもいいですね.その際, カーネルは以下の設定が有効になっている必要があります.

  • デフォルトコンソール出力
    • CONFIG_SERIAL_8250=y
      • CONFIG_SERIAL_8250_CONSOLE=y
  • 32ビットのイメージを62ビットのホストで動かす
    • CONFIG_IA32_EMULATION=y
  • ディスクイメージで使っているファイルシステム(例: CONFIG_EXT2_FS, CONFIG_EXT4_FS) linux-0.2.imgを使う場合はCONFIG_EXT2_FSを有効にする.
  • virtioデバイス
    • CONFIG_VIRTIO=y
    • CONFIG_VIRTIO_RING=y
    • CONFIG_VIRTIO_PCI=y
  • virtio-blkデバイス(–disk, -dで使う) 疑似仮想化ブロックデバイス向けの仮想ブロックデバイスドライバら しいです.
    • CONFIG_VIRTIO_BLK=y
  • virtio-netデバイス([–network, -n] virtio): 仮想ネットワークドライバ.
    • CONFIG_VIRTIO_NET=y
  • virtio-9pデバイス(–virtio-9p):
    • CONFIG_NET_9P=y
    • CONFIG_NET_9P_VIRTIO=y
    • CONFIG_9P_FS=y
  • virtio-balloonデバイス(–balloon): 動的メモリ割当のためのメモリドライバで,これがあるとゲストに割 り当てるメモリを動的に変更できる.
    • CONFIG_VIRTIO_BALLOON=y
  • virtio-consoleデバイス(–console virtio):
    • CONFIG_VIRTIO_CONSOLE=y
  • virtio-rngデバイス(–rng):
    • CONFIG_HW_RANDOM_VIRTIO=y

カーネルを用意できたら,後は起動するだけです.今回は,linux-kvm内 でビルドしたカーネルを使っています.

VMを終了するには,kvm stopを使います.その際に,VMの名前を指定す るのですが,これはkvm listで確認することができます.

kvm runには他にもオプションがあり,kvm help runで見ることができま す.残念ながら,筆者の環境と能力では全てのオプションの動作確認を することができませんでした.また,動作したオプションについては別 の記事で紹介する予定です.

  • –name: ゲストの名前
  • -c,–cpus: VMに割り当てるCPU数を指定
  • -m,–mem: VMのメモリサイズ.MBで指定する.
  • –shmem: PCIデバイス経由でホストとゲストが共有するメモリを指定
  • -d,–disk: ディスクイメージまたはrootfsディレクトリを指定
  • –balloon: virtio balloonを有効にする
  • –vnc: VMCフレームバッファを有効にする
  • –sdl: SDLフレームバッファを有効にする
  • –rng: virtio Random Number Generatorを有効にする
  • –9p virtio 9pを有効に.ホストとゲストのファイル共有に用いる.
  • –console 使用するコンソールを指定
  • –dev=: KVMのデバイスファイル
  • –tty: ゲストのTTYをホストのptyにリマップする
  • -k,–kernel=: VM用カーネル
  • -r,–initrd=: initrdのイメージを指定する
  • -p,–params: カーネルに与える追加の引数
  • -n,–network: ゲストNICを作成
  • –no-dhcp: rootfs中ではカーネルのDHCPを無効に
  • –vidmode: Video mode
  • –debug: デバッグメッセージを有効に
  • –debug-single-step: シングルステッピングを有効に
  • -debug-ioport: ioportingデバッグを有効に
  • -debug-iodelay: IOのディレイをミリ秒で指定

Debianのイメージを起動してみる

さて,次はDebianを起動してみましょう.まずは,イメージファイルを ダウンロードします.

さて,このイメージファイルをディスクに指定して起動するのですが, カーネルに引数を与えることに注意します.このイメージファイルは, 内部がパーティションで区切られているため,どのパーティションが rootなのかを指定する必要があるのです.カーネルの引数は-pオプショ ンで指定できます.

起動できました.まだうまくいっていませんが,KVMで作成したディスク 等も起動できそうです.

まだまだ実用的なレベルとは言えませんが,きちんと動いていておもし ろいですね.また,カーネルのデバッグ用途に使えるようなので,こち らについても試したい所です.

tmux内でコマンドを実行する際に新しいウィンドウやウィンドウを分割して実行する

本記事はターミナルマルチプレクサ Advent Calendar 2011 : ATNDの3日 目です.2日目はtmuxのjoin-paneからpaneの指定方法を学ぶ (ターミナ ルマルチプレクサ Advent Calendar 2日目) – kozo2のはてなダイアリー でした. tmuxとzshを使った小ネタです.zsh以外のシェルでも可能だと思います.

  • tmux内でsshを実行すると新しいウィンドウを作成してそこで実行する
  • tmux内でmanを実行するとウィンドウを分割してそこで実行する

~/.zshrcに設定するだけです.

tmuxのnew-windowやsplit-windowは,実行した後に引数のコマ ンドを実行することができるので,それを利用しているだけです. ただ,この設定だと,新規ウィンドウや新規ペインでssh・manを実行し たくない時どうすればいいのか分かりません.誰か知っている人がいた ら教えてください.