Hatena::ブログ(Diary)

へにゃぺんて@日々勉強のまとめ

2016-02-24

getcpu_cacheシステムコール追加パッチを試してみました(前編: pwclientでパッチ適用まで)

今日(2/24)、LKMLで以下のパッチが流れていました。


「getcpu_cache()システムコールを追加する」パッチで、Linux 4.6に向けたものなので、

もう少し先のパッチです(現在は4.5のrc期間)。


まだ、パッチの中身を完全に理解したわけでは無いのですが、

調べたり、試してみたりしたことをまとめてみます。


今回やったことは、以下の3つです。

1. getcpu_cache()について、主にメール本文やコミットメッセージからだいたい理解

2. パッチ適用し、QEMU上でカーネルを動かしてみる

3. パッチに付属しているサンプルを動かしてみる(詳細は次回の記事)



1. getcpu_cache()について

そもそも、getcpu()というシステムコールがあり、

これは呼び出し元スレッドが動作しているCPUを判別するもので、

SMPやNUMAといったマルチコアアーキテクチャのためのものです。


getcpu_cache()は、getcpu()にキャッシュ機構を追加して高速化しています。


上記のメールの本文に、

「ARM上での、このアプローチとシステムコールに基づくgetcpuとの比較は44倍の高速化を示した。

x86-64上において、glibcを介したvDSOからのlsl実行と比較して14倍の高速化を示した。」

と書かれていることから、キャッシュが効力を発揮する条件においては、

高速化が期待できるパッチのようです。


なお、man 2 getcpuを見ると、getcpu()自体にtcacheという引数があり、

2.6.24より以前では、この引数がNULL以外の場合はgetcpu()用のキャッシュ機構が動作するように実装されていた

とのことです。

そのため、過去に一度実装されていたものが、形を変えて再実装された様に見えます。


2. パッチ適用し、QEMU上でカーネルを動かしてみる

2.1. パッチ適用

LKML等のML上で流れているパッチは、patchwork.kernel.orgで管理されています。

そして、pwclientというコマンドライン上で動作するPythonスクリプトを公開しており、

これを使用すると、「パッチダウンロードし、git amで適用」といった操作がコマンド一発で行えます。


手順は以下のとおりです。

なお、LinuxGitのツリーをcloneする手順は省略します。

私は、Linusの木をcloneし、試してみました。


1. pwclientの準備

以下のページからpwclientをダウンロードし、PATHの通った場所に配置、実行権限を付与


また、pwclient実行の度にMLを指定しなくても良いように、以下のページからLKML用の.pwclientrcをダウンロードし、

ホームディレクトリに配置


2. パッチ適用したいLinuxカーネルGitツリーにブランチを作成

$ git checkout -b add_getcpu_cache

3. 適用したいパッチのPatchwork上のIDを確認

$ pwclient list getcpu_cache
ID      State        Name
--      -----        ----
7952981 New          [RFC,1/3] getcpu_cache system call: cache CPU number of running thread
7953001 New          [RFC,2/3] getcpu_cache: wire up ARM system call
7952991 New          [RFC,3/3] getcpu_cache: wire up x86 32/64 system call
8135861 New          [RFC,v2,1/3] getcpu_cache system call: cache CPU number of running thread
8135881 New          [RFC,v2,2/3] getcpu_cache: wire up ARM system call
8135871 New          [RFC,v2,3/3] getcpu_cache: wire up x86 32/64 system call
8153941 New          [RFC,v3,1/5] getcpu_cache system call: cache CPU number of running thread
8153901 New          [RFC,v3,2/5] getcpu_cache: ARM resume notifier
8153931 New          [RFC,v3,3/5] getcpu_cache: wire up ARM system call
8153911 New          [RFC,v3,4/5] getcpu_cache: x86 32/64 resume notifier
8153921 New          [RFC,v3,5/5] getcpu_cache: wire up x86 32/64 system call
8154741 New          [RFC,v3,1/5] getcpu_cache system call: cache CPU number of running thread
8164781 New          [RFC,v3,1/5] getcpu_cache system call: cache CPU number of running thread
8397411 New          [v4,1/5] getcpu_cache system call: cache CPU number of running thread
8397451 New          [v4,2/5] getcpu_cache: ARM resume notifier
8397421 New          [v4,3/5] getcpu_cache: wire up ARM system call
8397431 New          [v4,4/5] getcpu_cache: x86 32/64 resume notifier
8397441 New          [v4,5/5] getcpu_cache: wire up x86 32/64 system call
8397691 New          [v4,(updated)] getcpu_cache: wire up ARM system call

上記のコマンドでは、"getcpu_cache"でpatchwork.kernel.org内を検索し、結果をリスト表示しています。


"v4"が一番新しく、

> 8397421 New [v4,3/5] getcpu_cache: wire up ARM system call

については、

> 8397691 New [v4,(updated)] getcpu_cache: wire up ARM system call

の更新版が出ているので、今回は以下の5つのパッチ適用してみます。

> 8397411 New [v4,1/5] getcpu_cache system call: cache CPU number of running thread

> 8397451 New [v4,2/5] getcpu_cache: ARM resume notifier

> 8397691 New [v4,(updated)] getcpu_cache: wire up ARM system call

> 8397431 New [v4,4/5] getcpu_cache: x86 32/64 resume notifier

> 8397441 New [v4,5/5] getcpu_cache: wire up x86 32/64 system call


4. パッチ適用

pwclient git-am ID

で、「パッチダウンロードし、git am」を一括で行ってくれます。

今回の場合、以下の5つのコマンドを実行しました。

$ pwclient git-am 8397411
$ pwclient git-am 8397451
$ pwclient git-am 8397691
$ pwclient git-am 8397431
$ pwclient git-am 8397441

> 62dda9b getcpu_cache: wire up x86 32/64 system call

がHEADである時点のLinusツリーにおいては、コンフリクト無く適用できました。


なお、pwclientについて詳しくは、

pwclientをオプション無しで実行すると表示されるUsageを見てみてください。


2.2. カーネルビルド

今回は、x86_64_defconfig のデフォルトコンフィギュレーションビルドしてみます。

また、今回は、カーネルイメージ(bzImage)と初期RAMディスク(initrd)のみで、簡易的に動作確認してみますので、

上記ではbzImageターゲットを指定しています。(initrdはPC上(Debian Jessie)のものを流用します。)

$ make x86_64_defconfig
$ make -j4 bzImage

ビルドが完了すると、arch/x86/boot/bzImage にカーネルイメージが生成されます。


加えて、以降でサンプルをビルドするときのために、

カーネルのヘッダーファイルを適当なディレクトリに生成しておきます。

$ mkdir ~/test_linux_headers
$ make headers_install INSTALL_HDR_PATH=~/test_linux_headers

2.3. QEMUで起動してみる

以下のコマンドで、先ほどビルドしたカーネルとinitrdを使用してQEMU上で起動してみることができます。

"-kernel"オプションと"-initrd"オプションは、自身の環境に合わせて書き換えてください。

$ qemu-system-x86_64 -kernel ~/git/linux/arch/x86/boot/bzImage -initrd /boot/initrd.img-4.4.0 -append "root=/dev/ram rdinit=/bin/sh"

QEMUのウィンドウが立ち上がり、カーネルのブートログが表示された後、

Enterキーを押下すると、"\ #"というプロンプトが表示され、コマンド実行ができるようになります。


なお、以下の例のように実行することで、QEMUのウィンドウを立ち上げずに、シェル上で実行できます。

QEMUオプションcursesの使用を指定する例

qemu-system-x86_64 -kernel ~/git/linux/arch/x86/boot/bzImage -initrd /boot/initrd.img-4.4.0 -curses -append "root=/dev/ram rdinit=/bin/sh"

カーネルのブートパラメータでttyS0をコンソールとする例

$ qemu-system-x86_64 -kernel ~/git/linux/arch/x86/boot/bzImage -initrd /boot/initrd.img-4.4.0 -nographic -append "console=ttyS0 root=/dev/ram rdinit=/bin/sh"

つづく

思ったより記事を書くのに時間がかかってしまったので、

サンプルの実行については、また次回に。


なお、簡単に紹介すると、

実行するサンプルは以下のメールにあるものです。


また、サンプル実行でやったこととしては、以下のとおりです。

1. ビルド

2. initrdを展開、ビルドしたサンプルを追加し、再度initrd生成

3. 生成したinitrdを使用してQEMU上でカーネルブート

4. サンプル動作確認

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証