のぴぴのメモ

自分用のLinuxとかの技術メモ

32bitと64bitプロセスのtime_tのbitsを実機確認してみる

32bitプロセスと64bitプロセスで、glibcのtime_t変数のビット数がどう違うのか確認してみました。

サンプルプログラム

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>

#define sizeof_bits(x) (int)sizeof(x)*8

int main()
{

      printf("char      size:= bits\n",sizeof_bits(char));
      printf("int       size:= bits\n",sizeof_bits(int));
      printf("long      size:= bits\n",sizeof_bits(long));
      printf("long long size:= bits\n",sizeof_bits(long long));

      printf("struct timeval {        ->size:= bits\n",sizeof_bits(struct timeval));
      printf("   time_t      tv_sec;  ->size:= bits\n",sizeof_bits(time_t));
      printf("   suseconds_t tv_usec; ->size:= bits\n",sizeof_bits(suseconds_t));
      printf("}\n");

      return(EXIT_SUCCESS);
}

実機確認

(1)コンパイル、(2)fileコマンドで32bitのバイナリ形式であることを確認、(3)実行してビット数を確認の流れです。
time_tが32bitプロセスの場合は32bit、64bitプロセスの場合は64bitであることが解ります。
ちなみに、32/64bitプロセスで、char、int、long long型は差異が無く、long型が32/64bitでそれぞれ差異がある事も確認できます。

32bitプロセスの場合

  1. long変数が、32bitである。
  2. time_tも、32bitである。
$ gcc -m32 -o time-32 time.c
$ 
$ file time-32
time-32: ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=e4d3d5ef99b4f5178372ff254729b284fc429946, not stripped

$ ./time-32 
char      size:  8 bits
int       size: 32 bits
long      size: 32 bits
long long size: 64 bits
struct timeval {        ->size: 64 bits
   time_t      tv_sec;  ->size: 32 bits
   suseconds_t tv_usec; ->size: 32 bits
}

64bitプロセスの場合

  1. long変数が、64bitである。
  2. time_tも、64bitである。
$ gcc -m64 -o time-64 time.c
$
$ file time-64
time-64: ELF 64-bit LSB  executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=dc935a4fb6c31c98544e90fc740d59cd4b9db081, not stripped

$ ./time-64
char      size:  8 bits
int       size: 32 bits
long      size: 64 bits
long long size: 64 bits
struct timeval {        ->size:128 bits
   time_t      tv_sec;  ->size: 64 bits
   suseconds_t tv_usec; ->size: 64 bits
}

蛇足

glibcのコード上からも裏付けとろうと思ったのですが、時間がないのでやめました。

(ftrace)trace-cmdでfunction_graphを使ってみる

はじめに

少し前にid:yohei-aさんに、Brendan Greggさんのfuncgraphを教わり、中身がシェルだったので、そのシェルでftraceの使い方が少し解りました。ありがとうございます。

今回は、funcgraphと同じ事をtrace-cmdコマンドで実現する方法をまとめます。(trace-cmdのfunction_graphを使います。)

ftraceを使うためのセットアップ

(1)kenelのリビルド

不要です。最近のディストリビューションは全てftraceがONになっています。少なくとも、RHEL6、Fedora22、ubuntu14.04では不要でした。

(2)debugfsの/sys/kernel/debugへのマウント

不要です。trace-cmdコマンド実行時に自動的にマウントしてくれます。

(3)trace-cmdのインストール。

trace-cmdコマンドがなかったら、yumやapt-getコマンドで、trace-cmdをインストールしてください。

■Fedora/RHEL
# yum install trace-cmd
■ubuntu
# apt-get install trace-cmd

trace-cmdを使う

基本的な使い方(trace-cmdからコマンドを実行する)

# trace-cmd record -p function_graph -g [トレースするfunction] コマンド
# trace-cmd report > trace.log
  • "trace-cmd record"でコマンドを実行しトレースを取得します。
  • "-g"オプションで取得したい関数を指定します。
    • 指定可能な関数は"/sys/kernel/debug/tracing/available_filter_functions"で確認できます。
    • 複数関数を指定する場合は、"-g"オプションを複数指定します。
  • トレース取得データは、デフォルトではカレントディレクトリのtrace.datになります。

実行例

# trace-cmd record -p function_graph -g SyS_mmap -g SyS_brk ls
  plugin 'function_graph'
a.log  a.out  ltrace.log  mem.c  test_ftrace.dat  trace.dat  trace.dat.cpu0  trace.dat.cpu1
Kernel buffer statistics:
  Note: "entries" are the entries left in the kernel ring buffer and are not
        recorded in the trace data. They should all be zero.

CPU: 0
entries: 0
overrun: 0
commit overrun: 0
bytes: 1764
oldest event ts: 17309.292890
now ts: 17309.295092
dropped events: 0
read events: 7450

CPU: 1
entries: 0
overrun: 0
commit overrun: 0
bytes: 0
oldest event ts: 16818.044541
now ts: 17309.295277
dropped events: 0
read events: 0

CPU0 data recorded at offset=0x4e6000
    303104 bytes in size
CPU1 data recorded at offset=0x530000
    0 bytes in size

# trace-cmd report -t > trace.log

取得した結果(trace.log)

version = 6
CPU 1 is empty
cpus=2
              ls-10862 [000] 17309.286563606: funcgraph_entry:                   |  SyS_brk() {
              ls-10862 [000] 17309.286588309: funcgraph_entry:                   |    down_write() {
              ls-10862 [000] 17309.286589501: funcgraph_entry:        0.231 us   |      _cond_resched();
              ls-10862 [000] 17309.286591455: funcgraph_exit:         2.024 us   |    }
              ls-10862 [000] 17309.286592097: funcgraph_entry:        0.200 us   |    up_write();
              ls-10862 [000] 17309.286593610: funcgraph_exit:         5.743 us   |  }
              ls-10862 [000] 17309.286665524: funcgraph_entry:                   |  SyS_mmap() {
              ls-10862 [000] 17309.286666667: funcgraph_entry:                   |    sys_mmap_pgoff() {
              ls-10862 [000] 17309.286667488: funcgraph_entry:                   |      vm_mmap_pgoff() {
              ls-10862 [000] 17309.286668370: funcgraph_entry:                   |        security_mmap_file() {
              ls-10862 [000] 17309.286669192: funcgraph_entry:                   |          apparmor_mmap_file() {
              ls-10862 [000] 17309.286669904: funcgraph_entry:        0.201 us   |            common_mmap();
              ls-10862 [000] 17309.286671417: funcgraph_exit:         1.613 us   |          }
              ls-10862 [000] 17309.286672048: funcgraph_entry:        0.170 us   |          ima_file_mmap();
              ls-10862 [000] 17309.286673511: funcgraph_exit:         4.520 us   |        }
<以下略>

実行中のプロセスのトレースを取得する

実行中のプロセスのトレースを取得する場合は、"-P"オプションで取得したいプロセスのPIDを指定します。

# trace-cmd record -p function_graph -g [トレースするfunction] -P PID
# trace-cmd report > trace.log

実行例

# trace-cmd record -p function_graph -g SyS_mmap -g SyS_brk -P 10894
  plugin 'function_graph'
Hit Ctrl^C to stop recording
<取得が終了したら、Ctrl+Cで中止する>
^CKernel buffer statistics:
  Note: "entries" are the entries left in the kernel ring buffer and are not
        recorded in the trace data. They should all be zero.

CPU: 0
entries: 0
overrun: 0
commit overrun: 0
bytes: 2580
oldest event ts: 17631.193419
now ts: 17634.029942
dropped events: 0
read events: 166

CPU: 1
entries: 0
overrun: 0
commit overrun: 0
bytes: 0
oldest event ts: 16818.044541
now ts: 17634.030212
dropped events: 0
read events: 0

CPU0 data recorded at offset=0x4e6000
    8192 bytes in size
CPU1 data recorded at offset=0x4e8000
    0 bytes in size

# trace-cmd report -t > trace.log

データ圧縮アルゴリズムを整理してみた

データ圧縮(可逆圧縮)方式についてまとめました。

まとめ

  • 可逆圧縮の実用的アルゴリズムのほとんどは、LZ法を元にしている
  • LZは、ジェイコブ・ジヴ(Jacob Ziv)とエイブラハム・レンペル(Abraham Lempel)が開発した圧縮アルゴリズム
  • LZ法は、LZ77と、LZ78の2種類があり、それぞれ圧縮の符号方式が異なる。LZ77はsliding-window手法、LZ78はdictionaryによる符号化をする。
  • LZ77、LZ78は基礎的なアルゴリズムであり、実際に利用されるのはLZ77/78をベースに改良した実用的なアルゴリズムが利用されている。
  • 実用的なアルゴリズムの例としては、LZ77から派生した、LZSS(ARA、LZH)やDEFLATE(zip、gzip)、LZ78から派生した、LZW(GIFTIFF)などがある。

f:id:nopipi:20151209002040p:plain

Macbook Air(2010/A1370)にubuntu14.04(Trusty)を入れてみた

(2016/12追記)ubuntu16.04のインストールの話も別記事で書いていますので、そちらも参照下さい。
nopipi.hatenablog.com

1.はじめに

MacbookAir3.1(2010年モデル:A1370)に、Ubuntu14.04.3(Trusty Tahr)をインストールしました。結果的には、14.04では基本悩むところはなくサクサク行くのですが、ググるといろんな情報が出てきて戸惑う(多分古いバージョンのubuntuの情報)ので、まとめてみました。
【補足】
基本的には、ubuntuのページにMacBookへのインストール情報がまとまっているので、こちらを参考にすればOKです。が、MacbookAir3.1/Trusty(ubuntu14.04)という組み合わせが無く他の組み合わせを参考にしたのが戸惑いの原因でした。

前提は以下の通りです。

  • 入れる箱(Mac)
    • Macbook Air A1370(2010年モデル)
      • 機種名/Model: MacBookAir3.1 / A1370
      • 液晶サイズ 11.6
      • CPU/Mem/HDD】Core2Duo 1.4GHz / 2GB / SSD
  • 入れるもの
    • Ubuntu14.04.3(Trusty Tahr)
  • メディア作成環境
    • Windows10(OSレスの中古で、"OS X"環境ないもので...と言い訳^^;)

2.準備(インストールメディア)

ubuntuのインストール用メディアのisoをUSBメモリに突っ込んで、USBメモリブートでインストールしました。

インストールメディアを用意

ubuntuからダウンロード(当たり前ですが)

【ハマったポイント】
Mac用にチューニングされたisoもあるのですが、こちらではUSBブートが(なぜか)できませんでした。MacbookAir5.1とかではこちらを使ってとあるので、やり方があるのかもしれませんが分かりませんでした。

USBメモリブートメディア作成

今回は、"Universal-USB"というツールを利用しました。
http://www.pendrivelinux.com/universal-usb-installer-easy-as-1-2-3/
手順は、下記サイトを参考にしました。

3.インストール

  1. 作成したUSBメモリMacbookに差し、「オプションキー」を押しながら起動します。
  2. ブート可能なメディア一覧がでるので、USBメモリを選択
  3. 後は普通にインストール
    1. キーボード設定は、「日本語」->「日本語(Macintosh)」を選択。
    2. それ以外は、Macbook固有で悩むところはないです。

4.MacBook用のubuntu設定

古いバージョンのubuntuだとドライバーを追加で入れたり、いろいろやらなければならないようですが、14.04は悩む必要はありませんでした。使いやすい用に少しカスタマイズした程度です。

ファンクションキーの反転

初期状態では、ファンクションキーは音声や液晶の明るさ調整がメインで、F1やF2とかファンクションキーとして利用する場合は、fnキーと組み合わせる必要があります。ですが、日本語変換の時面倒なので機能を反転させます。
以下のページを参考にしました。

$ sudo vi /etc/rc.local 
下記の行を追加
echo 2 > /sys/module/hid_apple/parameters/fnmode

マウス変更

2本指で操作できるように設定変更。左バーの「システム設定」→「マウスとタッチパッド」を選択して設定。
f:id:nopipi:20151122165023p:plain

ブート画面修正(CPU高騰という別の問題が出たため見送り)

起動画面に「ubuntus」のタイトルがでてこないという実害はない話です。
これはどうやら、Macbookとの問題ではなくubuntu14.04(Trusty)の問題のようで、uvesafbというフレームバッファを設定することで、表示されました。ですが、uvesafbを動かすために必要なv86dとか言うデーモン(ユーザー空間で動くデーモンが必要と言う時点で微妙な気分ですが)がCPU100%に張り付くという別の問題が発生したので、結局断念しました。参考にしたサイトをリストします。

5.使いやすくするために

ランチャーへの登録

デフォルトではターミナルが、左メニューバー(Launcher)にないので追加します。

  1. ランチャーの一番上のボタンを押し検索画面を出す
  2. 検索ボックスから「Ter・・・」と入力すると、ターミナルが表示されるので実行する。
  3. 実行するとlauncherに実行アプリのボタンが追加されるので、右クリックして「Launcherに登録」を実行

アップデート

立ち上げて暫くするとアップデートを促するメニューが出てそれを実行すればよいですが、手動実行する場合は以下の通り実行します。

GUIから実行
  1. 検索から「update」と入力し、アプリを実行
CLIで実行

ターミナルから以下を実行します。

sudo apt-get upgrade

パッケージの追加インストール

sudo apt-get install vim
sudo apt-get install openssh-server
sudo apt-get install gimp 

備考

これまで10年前のLet'sNoteにFedoraを入れて使っていましたが、持ち歩きがかさばるので中古でmacbookを買って、せっかくだから今まで使ったことなかったubuntuを使ってみようかなと思ったのがきっかけです

【RHEL/CentOS】RHEL6.6にMemAbailableがバックポートされている件

はじめに

先日の下記の記事で「RHEL6ではバックポートされてMemAvailableが使えるよ」という情報を頂いたので、追加で情報を整理しました。
nopipi.hatenablog.com

RHEL6.6へのMemAvailableのバックポート

MemAvailableは、RHEL6.6でバックポートされてました。というのも、ググったらredhatのナレッジ情報が出てきました。
詳細はログインしないと見れないのですが、MemAvailableは"kernel-2.6.32-504.el6"以上で利用可能とあり、このバージョンがRHEL6.6のカーネルバージョンになります。
Backport "MemAvailable" field to /proc/meminfo in Red Hat Enterprise Linux 6. - Red Hat Customer Portal

使い方

MemAvailableの有効化

デフォルトでは互換性に配慮し非表示に設定されているため、カーネルパラメータvm.meminfo_legacy_layoutを無効する必要があります。

# vim /etc/sysctl.conf
vm.meminfo_legacy_layout=0

書き込み後、下記コマンドで反映&確認。
# sysctl -p
# sysctl vm.meminfo_legacy_layout
vm.meminfo_legacy_layout = 0

表示

RHEL7とは表示位置が違ったり、freeコマンドの表示形式が違うとかありますが、availableがキチンと表示されます。

/proc/meminfo

一番最後の行に表示されます。取ってつけたようなとも思いますが、コード修正の影響を考えたらしょうがないですね。

# cat /proc/meminfo
MemTotal:        1020236 kB
MemFree:           76136 kB
Buffers:          230192 kB
Cached:           596980 kB
SwapCached:          332 kB
Active:           328452 kB
Inactive:         519032 kB
Active(anon):       3200 kB
Inactive(anon):    17380 kB
Active(file):     325252 kB
Inactive(file):   501652 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:       1048572 kB
SwapFree:        1046720 kB
Dirty:                 0 kB
Writeback:             0 kB
AnonPages:         20084 kB
Mapped:             7884 kB
Shmem:               268 kB
Slab:              72596 kB
SReclaimable:      45560 kB
SUnreclaim:        27036 kB
KernelStack:        1312 kB
PageTables:         5976 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:     1558688 kB
Committed_AS:     108076 kB
VmallocTotal:   34359738367 kB
VmallocUsed:      138664 kB
VmallocChunk:   34359594564 kB
HardwareCorrupted:     0 kB
AnonHugePages:      2048 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
DirectMap4k:        8192 kB
DirectMap2M:     1040384 kB
MemAvailable:     813196 kB
freeコマンド

freeコマンドは、"-a"オプションで表示されます。

# free -a
             total       used       free     shared    buffers     cached  available
Mem:       1020236     944480      75756        268     230216     597172     813036
-/+ buffers/cache:     117092     903144
Swap:      1048572       1852    1046720

ちなみに、MemAvailableが無効化(vm.meminfo_legacy_layout=1)の場合、availableは0と表示されます。

# free -a
             total       used       free     shared    buffers     cached  available
Mem:       1020236     944472      75764        268     230248     597192          0
-/+ buffers/cache:     117032     903204
Swap:      1048572       1852    1046720

補足

upstreamカーネルのMemAbailableコミット情報

ちなみにナレッジには以下の通り、upstream(コミュニティのカーネル)からRHEL6バックポートしているよと記載があります。

Backport upstream commit id: 34e431b0ae398fc54ea69ff85ec700722c9da773 to add MemAvailable field to /proc/meminfo in Red Hat Enterprise Linux 6

そして、このgitのコミットIDを探すとupstreamカーネルのコミットとLKMLの情報は以下の通りでした。
kernel/git/torvalds/linux.git - Linux kernel source tree
LKML: Rik van Riel: [RFC PATCH -mm] provide estimated available memory in /proc/meminfo

【RHEL】linuxメモリのfreeとmeminfoの関係を図解し利用率の計算方法を説明してみる

はじめに

linuxサーバを利用する上で何時も頭を悩ますものの一つが、メモリ利用状況の評価(メモリ利用率)ではないでしょうか。私も悩みます。そこでRHELベースですが、メモリ利用容量/メモリ利用率の評価をどう考えるかということを整理しました。
詳細は後述しますが、例えばRHEL7のfreeコマンドとmeminfoの関係を整理するとこんな感じになります。
f:id:nopipi:20150913163740p:plain

ちなみにlinuxのメモリ解説&meminfoをどのように見ればいいかは、e.nakaiさんのページが参考になります。(私のメモリ周辺のバイブル的ページです^^;)
enakai00.hatenablog.com

linuxのメモリ利用容量(空き容量)の考え方

何を持って、「メモリが空いている」とするのか??
単純に考えると、何も利用していない(割り当てていない)領域を空き容量とすればいいはずです。しかしlinuxをはじめとする現在のOSでは、「使えるメモリはとことん使ってしまえ!!」という設計思想なため、空きメモリは積極的にファイルキャッシュ用途に利用してしまいます。その結果、「未割り当て領域を空き領域」と定義すると、メモリ利用率が常に100%となり「意味がねぇなぁ」という感じになってしまいます。

そこで改めて「メモリが空いている状態」を考える必要があります。そこで着目するのが、メモリ解放のカーネルの挙動です。カーネルはプロセスやドライバから新規メモリ(ページ)の確保要求があった時、未使用領域(freeコマンドやmeminfoで言うところのfree領域)から新規割り当てを行います。未使用領域が無い場合、既存のメモリを解放して空きを作り、新なメモリ割当を行います。この「既存メモリの解放処理」は2通りのやり方があり、一つはスワップアウトして空きを作る方法、もう一つはディスク同期してメモリ解放する方法になります。メモリ解放の方式を整理すると、以下の表のようになります。

メモリ解放方法 対象ページ 対象ページの例 再アクセス時の挙動
スワップアウトして解放 無名ページ
(anonymous page)
プロセスのメモリ(データ/スタック領域),共有メモリ,tmpfs スワップイン
ディスク同期して解放 ファイルページ
(file page)
ファイルキャッシュ&バッファ、プロセスのテキスト領域 ディスクから再読み込み

※1 無名ページ&ファイルページについては、記事文末を参照。
※2 プロセスのテキスト領域とは、プロセスの実行イメージ(プログラム)を格納するメモリ領域です。
※3 もちろん、プロセス終了やプログラム中のfree()など、本当に不要になって開放するパターンもありますが、ここでは割愛します。

ここでサーバ用途の場合のメモリ設計を考えると、「可能な限りスワップを発生させないようにメモリサイジングする」ことが重要になります。特に(バッチ処理ではなく)オンライン系のサーバ(web,AP,DBサーバとか)の場合、スワップイン処理にかかるオーバーヘッドによるクライアントへのレスポンス遅延が一番気になるためです。例えば通常1秒以内でレスポンスが帰っている処理が数秒や最悪十数秒に伸びることで、利用者のユーザビリティが落ち「使えねーシステム」の烙印を押されることになることになるためです。

ということで、メモリ空き容量を評価する上は、「スワップが発生しない程度」の空きが保たれていることが重要というとになり、結果として「未割当て領域+ディスク同期による解放領域」を空きと見なすという考えになります。(説明がちょっと強引ですが。)

ここまでの話を、式にまとめると以下のような形になります。

メモリの空き容量 = 未割り当て容量(free) + ディスク同期にて解放可能な容量(ファイルページ≒バッファ&キャッシュ)
メモリ利用容量 = メモリ合計容量 - メモリ空き容量
               = メモリから解放不可な容量 + 解放時にスワップアウトしてしまう容量





linuxのメモリ利用容量/空き容量の計算方法

と前置きが長かったですが、ここからがlinuxの悩ましい所。

なぜなら、linuxでメモリ容量を確認するfreeコマンドで取得できるバッファ&キャッシュ領域には、スワップする領域も含まれており、単純に「メモリ利用容量=メモリ全体 - free - Buffer&Cache」としてしまうと、メモリ利用容量を過小評価してしまうためです。最近のlinuxカーネルはこの辺を考慮したメモリ情報を表示してくれるのですが(RHEL7とか。詳細は後述)、昔の特にRHEL5以前は真面目にやろうとすると結構しんどかったです。(カーネルのメモリ管理を理解していなかったという要素も大きいですが。。。)

以下に最新のRHEL7から順に、代々のバージョンでどのようにメモリ利用容量/利用率を計算していたかを説明します。こうやって整理すると、「昔は苦労したなぁ〜」というのがよくわかりますね。^^;

■RHEL7

最初にRHEL7ですが、RHEL7からはメモリ利用率の計算が劇的に楽になりました。
というのも、上でぐちゃぐちゃ説明したことを、freeコマンドの「available」というパラメータで表示してくれるからです。(厳密には/proc/meminfoに"MemAvailable:"という利用可能なメモリ容量の目安を表示してくれるようになったのですが)

なので、わざわざmeminfoをみなくても、freeコマンドの結果をちょっと加工すれば利用率をだせるようになりました。

【freeコマンドとmeminfoの図解】

f:id:nopipi:20150913163740p:plain

【計算方法】

freeコマンドの結果をawkで処理させています。

#!/bin/bash
export LANG=C, LC_ALL=C

free | awk '
    BEGIN{
        total=0;used=0;available=0;rate=0;
    }

    /^Mem:/{
        total=$2;
        available=$7;
    }

    END{
        used=total-available;
        rate=100*used/total;
        printf("used%,total(KB),used(KB),available(KB)\n");
        printf("%.1f,%d,%d,%d\n",rate,total,used,available);
    }';
freeコマンド表示例
# free
              total        used        free      shared  buff/cache   available
Mem:        1884812      106076     1615644        8632      163092     1624364
Swap:       2097148           0     2097148
/proc/meminfo表示例
# cat /proc/meminfo
MemTotal:        1884812 kB
MemFree:         1615784 kB
MemAvailable:    1624504 kB
Buffers:             880 kB
Cached:           120396 kB
SwapCached:            0 kB
Active:            84932 kB
Inactive:          95568 kB
Active(anon):      59524 kB
Inactive(anon):     8332 kB
Active(file):      25408 kB
Inactive(file):    87236 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:       2097148 kB
SwapFree:        2097148 kB
Dirty:                 0 kB
Writeback:             0 kB
AnonPages:         59244 kB
Mapped:            20852 kB
Shmem:              8632 kB
Slab:              41816 kB
SReclaimable:      17396 kB
SUnreclaim:        24420 kB
KernelStack:        1680 kB
PageTables:         3688 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:     3039552 kB
Committed_AS:     268452 kB
VmallocTotal:   34359738367 kB
VmallocUsed:      156764 kB
VmallocChunk:   34359575144 kB
HardwareCorrupted:     0 kB
AnonHugePages:      4096 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
DirectMap4k:       53184 kB
DirectMap2M:     2043904 kB

■RHEL6

RHEL6時代までのfreeコマンドでは、バッファ&キャッシュ領域にスワップアウトしてしまうメモリも含まれているため、meminfoを直接参照していました。ただRHEL5以前とは異なり、RHEL6ではメモリ管理にSplitLRUが導入され、無名ページとファイルページを分て管理するようになっており、meminfoでもactive,inactive(メモリ回収候補ページのリスト)の登録ページ数が種別ごとに表示されるようになっているので、それを利用してメモリ計算をしています。

【freeコマンドとmeminfoの図解】

f:id:nopipi:20150913163744p:plain


【計算方法】

/proc/meminfoのデータをawkでガリガリ計算させています。

export LANG=C, LC_ALL=C

awk '
    BEGIN{
        total=0;used=0;available=0;rate=0;
    }

    /^MemTotal:/         {total=$2;}
    /^MemFree:/          {available=available+$2;}
    /^Active\(file\):/   {available=available+$2;}
    /^Inactive\(file\):/ {available=available+$2;}

    END{
        used=total-available;
        rate=100*used/total;
        printf("used%,total(KB),used(KB),available(KB)\n");
        printf("%.1f,%d,%d,%d\n",rate,total,used,available);
    }' /proc/meminfo;
freeコマンド表示例
# free
             total       used       free     shared    buffers     cached
Mem:       1020236     147168     873068        268      17824      54444
 -/+ buffers/cache:      74900     945336
Swap:      1048572          0    1048572
/proc/meminfo表示例
MemTotal:        1020236 kB
MemFree:          873068 kB
Buffers:           17832 kB
Cached:            54460 kB
SwapCached:            0 kB
Active:            38724 kB
Inactive:          51140 kB
Active(anon):      17580 kB
Inactive(anon):      256 kB
Active(file):      21144 kB
Inactive(file):    50884 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:       1048572 kB
SwapFree:        1048572 kB
Dirty:                60 kB
Writeback:             0 kB
AnonPages:         17588 kB
Mapped:            15584 kB
Shmem:               268 kB
Slab:              34304 kB
SReclaimable:       8984 kB
SUnreclaim:        25320 kB
KernelStack:        1280 kB
PageTables:         5236 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:     1558688 kB
Committed_AS:     101760 kB
VmallocTotal:   34359738367 kB
VmallocUsed:      138664 kB
VmallocChunk:   34359594564 kB
HardwareCorrupted:     0 kB
AnonHugePages:         0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
DirectMap4k:        8192 kB
DirectMap2M:     1040384 kB

RHEL5以前

で、一番悩ましいRHEL5以前です。この時代はfreeコマンドがダメでかつ、この当時は無名ページとファイルページを一緒に管理(一つのLRUリストにゴジャッと登録していた)ため、meminfoでもファイルページ数を的確に把握することができませんでした。

そこでどうするかというと、ファイルキャッシュ&バッファとしてカウントされるもののうち、無名ページに該当するものほとんどは、(1)tmpfs用のメモリ,(2)IPCの共有メモリ用のメモリ、の2つになることに着目します。そこで、それぞれの利用状況を取得してその分をmeminfoから取得した値から引き算し近似的に利用可能な容量を計算するというやり方をします。

  • キャッシュ&バッファから除外する容量の計算方法
    • tmpfs --> dfコマンド結果から、tmpfsのusedの容量を足し算する
    • IPC共有メモリ --> "ipcs -u"コマンドの"pages allocated"(共有メモリ様に割り当て済みのページ数)を取得
【freeコマンドとmeminfoの図解】

f:id:nopipi:20150913163749p:plain

【計算方法】

dfコマンド、"ipcs -u"コマンド、と/proc/meminfoのデータを組み合わせて、awkで計算させています。

#!/bin/bash

export LANG=C, LC_ALL=C

#メモリファイル
TMPFS=`/bin/df --portability |awk 'BEGIN{used=0;} /^tmpfs/{used=used+$3}END{print used}'`

#IPC シェアードメモリ
PAGE_SIZE=$((`/usr/bin/getconf PAGE_SIZE` / 1024))
IPC_SHM=`/usr/bin/ipcs -u |awk -v SIZE=${PAGE_SIZE} '/^pages allocated/{print $3 * SIZE}'`

#シェアードメモリ合計(tmpfs + ipc_shm)
SHMEM=$(( ${TMPFS} + ${IPC_SHM} ))

awk -v shmem=${SHMEM} '
    BEGIN{
        total=0;used=0;available=0;rate=0;
    }

    /^MemTotal:/ {total=$2;}
    /^MemFree:/  {available=available+$2;}
    /^Buffers:/  {available=available+$2;}
    /^Cached:/   {available=available+$2;}

    END{
        available=available-shmem
        used=total-available;
        rate=100*used/total;
        printf("used%,total(KB),used(KB),available(KB)\n");
        printf("%.1f,%d,%d,%d\n",rate,total,used,available);
    }' /proc/meminfo;
freeコマンド表示例
# free
             total       used       free     shared    buffers     cached
Mem:       2058764     313972    1744792          0      19748     165736
  • /+ buffers/cache: 128488 1930276
Swap: 4095992 0 4095992
/proc/meminfo表示例
MemTotal:      2058764 kB
MemFree:       1744792 kB
Buffers:         19756 kB
Cached:         165736 kB
SwapCached:          0 kB
Active:         103444 kB
Inactive:       160096 kB
HighTotal:           0 kB
HighFree:            0 kB
LowTotal:      2058764 kB
LowFree:       1744792 kB
SwapTotal:     4095992 kB
SwapFree:      4095992 kB
Dirty:             112 kB
Writeback:           0 kB
AnonPages:       78060 kB
Mapped:          10520 kB
Slab:            26440 kB
PageTables:       3472 kB
NFS_Unstable:        0 kB
Bounce:              0 kB
CommitLimit:   5125372 kB
Committed_AS:   158884 kB
VmallocTotal: 34359738367 kB
VmallocUsed:    265472 kB
VmallocChunk: 34359470723 kB
HugePages_Total:     0
HugePages_Free:      0
HugePages_Rsvd:      0
Hugepagesize:     2048 kB

蛇足

その1:無名ページとファイルページ

まず、このページではファイルページと記載しましたが、正確には「ファイルバックド(file-backed)ページ」ですかね。また、ファイルページを記事内では「ディスクと同期して解放」と記載してますが、正確にはディスクと同期するのは未同期データの解放の時のみです。同期済みの場合は同期処理なく解放します。

無名ページとファイルページの違いをざっくりと書くと、本文にも記載しましたが以下の通りになります。

  • 無名ページ --->メモリが足りない時スワップアウト(スワップへ退避)され、物理メモリから解放されるページ
  • ファイルページ ---> メモリが足りない時ディスク同期し解放されるページ

蛇足になりますが、10年前にカーネル本(オライリー&ペンギン黒本)を読んだ時は、いきなり「無名ページ」と出て来て、何が何だか分からず挫折した経験があります。それから10年経ってやっと「スワップする/しない、の差なのね」という理解に到達。この辺の理解している人としてない人の溝の深さが、カーネルを理解する上での障壁(カーネル難しぃ〜)の一つになっているのかなと思います。

その2:図解の内容のツッコミ

「SReclaimable」領域を、「ディスク同期して解放」で色塗りしていますが、実際は単純にslabとして未使用領域で、メモリが足りない場合は単純に開放するだけですね。後で気付いたのですが、図を修正するのが面倒なので、そのままにしちゃいました。

その3:RHEL6の計算

RHEL6では、"active(file)"と"inative(file)"から計算していますが、RHEL7のavailaleのカーネル内部の計算を見るに、"SReclaimable"も加算しなければならないですね。まあ全体量に対して、"SRelaimale"は小さいので加算しなくても大した影響はないとおもいますが。

その4:Inactiveを空き領域とすることは間違い。

ちなみに、linuxでのメモリ利用量(空き容量)をググると「利用可能なメモリ ≒(MemFree+Inactive)」という話がでますが、これはガチャピン先生が指摘されていますが、間違いです。

【Fedora22】日本語入力設定のメモ

忘れないように、自分用のメモ

IME設定(デフォルトibus-kkcを入力ソースに追加)

Fedora22のデフォルトIMEは、ibus-kkcのようでデフォルトでインストールされている。しかし、入力ソースに含まれておらずインストール直後の状態では日本語入力ができない(私の環境だけ?)。なので、日本語入力できるように追加設定をする。

  1. 「アクティビティ」→「設定」を開き、「地域と言語」を選択
  2. 「入力ソース」で「+」ボタンを押す
  3. 出て来たウィンドウの言語リストから「日本語(かな漢字)」を選択し「追加」ボタンを押す
  4. 本のウィンドウの「入力ソース」に新しい入力ソースが追加されていることを確認

IME切替ショートカットの変更(「半角/全角」キーに変更)

個人的に「半角/全角」キーでIME切り返したいので設定変更。

  1. 「アクティビティ」→「設定」を開き、「キーボード」を選択
  2. タブを「ショートカット」に変更
  3. 左のカテゴリから「タイピング」を選択し、「次の入力ソースへ切り替える」を選択
  4. キー設定部分が「新しいアクセラレータ」と表示されるので、「半角/全角」キーを入力し設定する

【RHEL7】sysctlのカーネルパニックオプション

sysctlのカーネルパニックオプション

ちょいとカーネルパニックをどう設定すればよいかという話があって、ためしにsyscltをpanicでgrepすると、意外にというかpanicに関するパラメータがバラバラ出てきてどうすればよいかイマイチわからない。

# sysctl -a|grep panic
fs.xfs.panic_mask = 0
kernel.hung_task_panic = 0
kernel.panic = 0
kernel.panic_on_io_nmi = 0
kernel.panic_on_oops = 1
kernel.panic_on_stackoverflow = 0
kernel.panic_on_unrecovered_nmi = 0
kernel.panic_on_warn = 0
kernel.softlockup_panic = 0
kernel.unknown_nmi_panic = 0
vm.panic_on_oom = 0

ということで整理してみた。

panicの整理

整理するとこんな感じ。

  • パニック本体設定
      • kernel.panic
  • トリガー設定
    • NMI割込みトリガー(SVP/iLO2とかからのNMI割込みによるダンプ取得)
      • kernel.panic_on_unrecovered_nmi
      • kernel.unknown_nmi_panic
      • kernel.panic_on_io_nmi
    • OOPSメッセージトリガー
      • kernel.panic_on_oops
    • カーネル警告メッセージトリガー
      • kernel.panic_on_warn
    • watchdogトリガー
      • kernel.softlockup_panic
    • ハングタスクチェックトリガー
      • kernel.hung_task_panic
    • カーネル内のスタックオーバーフロートリガー
      • kernel.panic_on_stackoverflow
    • OOM killerトリガー
    • xfs系統
      • fs.xfs.panic_mask

panic系パラメータの関係

カーネルソースから各パラメータの関係を整理すとこうなる。
f:id:nopipi:20150516115617p:plain

それぞれのパラメータの挙動

kernel.panic

  • 説明
    • panic時の挙動設定。kdump利用時は、このパラメータが使われている処理ロジックの前に、kdumpのセカンドカーネル起動が走るため、パラメータが使われることはない。
  • 設定
    • kernel.panic > 0:n秒後まって再起動
    • kernel.panic = 0:ハング(デフォルト)
    • kernel.panic < 0:即時再起動

kernel.panic_on_unrecovered_nmi

  • 説明
    • メモリECCで修復不能なエラー、PCI通信の致命的エラー、あとサーバ管理コンソール(SVP/CMM/iLO2)からのダンプ取得のためのNMI割込み時に、panicさせるかの設定。
  • 設定
    • kernel.panic_on_unrecovered_nmi=0:panicしない(デフォルト)
    • kernel.panic_on_unrecovered_nmi=1:panicする

kernel.unknown_nmi_panic

  • 説明
    • kernel.panic_on_unrecovered_nmiとほぼ同じで、PCI通信の致命的エラー時のpanicが含まれないだけ。なのでpnic_on_unrecovered_nmiだけ設定すれば十分。
  • 設定
    • kernel.kernel.unknown_nmi_panic=0:panicしない(デフォルト)
    • kernel.kernel.unknown_nmi_panic=1:panicする

kernel.panic_on_io_nmi

  • 説明
    • IOエラーが原因で NMI割込みが発生した場合のpanic有無。致命的なパターンなのでpanicがいいのかな。またHPのサーバではiLO2からのダンプ取得のためにONにするようなことが書かれている。
  • 設定
    • kernel.panic_on_io_nmi=0:panicしない(デフォルト)
    • kernel.panic_on_io_nmi=1:panicする

kernel.panic_on_warn

  • 説明
    • カーネルのワーニング出力時(WARN()呼び出し時)にpanicさせるかの設定。カーネルのデバックでもない限り、WARN()ごときでpanicさせないだろう。
  • 設定
    • kernel.panic_on_warn=0:panicしない(デフォルト)
    • kernel.panic_on_warn=1:panicする

kernel.softlockup_panic

  • 説明
    • カーネルのwatchdog監視が有効(kernel.nmi_watchdogか、kernel.watchdogが1の場合、有効)の場合で、watchdog監視に引っかかった時のpanic発生有無。
  • 設定
    • kernel.softlockup_panic=0:panicしない(デフォルト)
    • kernel.softlockup_panic=1:panicする

kernel.hung_task_panic

  • 説明
    • khungtaskカーネルスレッドが、TASK_UNINTERRUPTIBLE状態が120秒(デフォルト)超過しているスレッドを監視していて、該当するスレッドがいた時にpanicさせるかの設定。
  • 設定
    • kernel.hung_task_panic=0:panicしない(デフォルト)
    • kernel.hung_task_panic=1:panicする

kernel.panic_on_stackoverflow

  • 説明
    • カーネル内でスタックオーバーフローが発生した時にpanicさせるかの設定。
  • 設定
    • kernel.panic_on_stackoverflow=0:panicしない(デフォルト)
    • kernel.panic_on_stackoverflow=1:panicする

vm.panic_on_oom

  • 説明
    • OOM killer発生時のpanic有無
  • 設定
    • vm.panic_on_oom=0:panicしない(デフォルト)
    • vm.panic_on_oom=1:panicする。ただし、cgroupの制限に引っかかった場合はpanicしない。
    • vm.panic_on_oom=2:panicする。cgroup制限も含め問答無用でpanicする。

RHEL7 initramfsの展開方法

今までのやり方では展開されない

普通、initramfsの中身を展開する場合は、gunzipあたりとcpioを使って以下のようにするはず。

$ cd /tmp
$ cp /boot/initramfs.img initramfs.gz
$ gunzip initramfs.gz
$ mkdir ramdisk
$ cd ramdisk
$ cpio -i -d -H newc --no-absolute-filenames < ../initramfs

ところが、最近のFedora/CentOS/RHELで上記をやると、これは「gzipじゃない!!」と怒られてしまう。

$gunzip initramfs.gz
gzip: initramfs.gz: not in gzip format

じゃあ、fileで確認するとcpioだというから直接cpioで展開すると、CPUのマイクロコードらしきものしか展開されない(´・ω・`)

$ mkdir ramdisk
$ cd ramdisk
$ file ../initramfs.gz
../initramfs.gz: ASCII cpio archive (SVR4 with no CRC)
$ cpio -i -d -H newc --no-absolute-filenames < ../initramfs.gz
26 blocks
$ find .
.
./kernel
./kernel/x86
./kernel/x86/microcode
./kernel/x86/microcode/GenuineIntel.bin
./early_cpio

[RHEL7/CentOS7/FC21]initramfsの展開方法

グーグルさんに聞いてみる

キーワードを変えていろいろ調べたら、出てきた。
forums.fedoraforum.org

手順

上記内容をちょっとだけ丁寧に解説。

バイナリ解析ツールのインストール

まずバイナリー解析用ツールを入れないといけないらしい。

yum -y install binwalk

なおRHELCentOSのレポジトリにはbinwalkはないので、ネットからrpmパッケージをDLしてrpmコマンドで個別にインストールするか、ソースを落としてコンパイルする。

initramfsの解析と展開
$ cp /boot/initramfs-3.10.0-229.el7.x86_64.img .
$ binwalk initramfs-3.10.0-229.el7.x86_64.img

DECIMAL         HEX             DESCRIPTION
-------------------------------------------------------------------------------------------------------
13312           0x3400          gzip compressed data, from Unix, last modified: Thu Apr 30 13:18:46 2015, max compression
3412955         0x3413DB        bzip2 compressed data

$ dd if=initramfs-3.10.0-229.el7.x86_64.img of=initramfs.gz bs=13312 skip=1
1350+1 records in
1350+1 records out
17982993 bytes (18 MB) copied, 0.0431475 s, 417 MB/s
$ gunzip initramfs.gz
$ mkdir ramdisk
$ cd ramdisk/
$ cpio -i -d -H newc --no-absolute-filenames < ../initramfs
80381 blocks
    • binwalk解析でgzipが始まる位置を確認(上記例では、13312bytesから開始)
    • ddコマンドでgzipの前のデータをスキップしてコピー("bs=13312 skip=1"がミソ)
    • それ以降は今までのやり方と同じ

なおgzipが始まる位置はその時々で変わる(おそらくmicrocodeのデータサイズが変わるから)ため、都度binwalk解析の確認が必要。

RHEL6 squashfsの作り方

squashfsとは

squashfsとは、圧縮された読み込み専用のファイルシステムでLiveCD(CD/DVDブートして利用するOS)で利用されている。詳しくはwikipediaを見るのが手っ取り早いかと。
wikipedia:SquashFS

squashfsファイルシステムの作り方

squashfs用ツールのインストール

squshfsなファイルシステムはmksquashfsコマンドを利用するが、CentOSなどではデフォルトでは入っていないため、個別にrpmパッケージ(squashfs-tools)インストールする必要がある。

# yum install squashfs-tools

squashfsファイルシステムの作成

mksquashfsコマンドで、squashfsファイルシステムを作成する。

$ mksquashfs ./SOURCE/ File.squashfs

squashfsファイルシステムのマウント

出来上がったsqushfsはmountコマンドのループバックオプションでマウントする。

#  mount -o loop File.squashfs /MountPoint/

fstabで自動マウント

fstabに登録するときは以下のように記載する。

/Directory/File.squashfs /MountPoint  squashfs loop 0 0

mountコマンドでマウントする。

# mount -a

追伸

昔、cloopで圧縮ファイルを作るということをやっていたけど(Fedora5/RHEL4 cloopでLinux圧縮ファイルシステムを作る - のぴぴのメモ、Upstreamにマージされていて各ディストリビューションにもデフォルトで入っているsquashfsのほうが使いやすいですよね。

Linux /proc/meminfoの統計情報を取得する。

/proc/meminfoの統計情報を取得する

 Linuxのメモリ挙動を詳しく分析するためには/proc/meminfoを見る必要がある。がしかし、sarコマンドのように時系列でmeminfo情報を取得してくれるコマンドはなく、自作のスクリプトなどで取得するしかない。  

そこで、スクリプトで/proc/meminfo情報を時系列で取得する方法を説明する。

  • 2013.3.4 awkコマンド修正(ヘッダ末尾のリターンコード忘れてた)

コマンドで取得する(テストなどの秒間隔での取得)

ざっくりいうと、meminfoをawkCSV形式に整形してログファイルに追加でリダイレクトするコマンドを、wlile分で無限ループさせているだけ。終了する場合は、CTRL+Cで強制終了させる。

LANG=C;( awk 'BEGIN{ printf "\"DATE\",\"TIME\""} {printf ",\"%s(%s)\"",$1,$3} END{printf "\n"}' /proc/meminfo > meminfo.csv ); while true;do ( awk 'BEGIN{ printf strftime("%Y/%m/%d, %H:%M:%S") } {printf ",%d",$2} END{printf "\n"}' /proc/meminfo >> meminfo.csv );sleep 1; done

これを動かすと、こんな結果が取得される。

"DATE","TIME","MemTotal:(kB)","MemFree:(kB)","Buffers:(kB)","Cached:(kB)","SwapCached:(kB)","Active:(kB)","Inactive:(kB)","Active(anon):(kB)","Inactive(anon):(kB)","Active(file):(kB)","Inactive(file):(kB)","Unevictable:(kB)","Mlocked:(kB)","SwapTotal:(kB)","SwapFree:(kB)","Dirty:(kB)","Writeback:(kB)","AnonPages:(kB)","Mapped:(kB)","Shmem:(kB)","Slab:(kB)","SReclaimable:(kB)","SUnreclaim:(kB)","KernelStack:(kB)","PageTables:(kB)","NFS_Unstable:(kB)","Bounce:(kB)","WritebackTmp:(kB)","CommitLimit:(kB)","Committed_AS:(kB)","VmallocTotal:(kB)","VmallocUsed:(kB)","VmallocChunk:(kB)","HardwareCorrupted:(kB)","AnonHugePages:(kB)","HugePages_Total:()","HugePages_Free:()","HugePages_Rsvd:()","HugePages_Surp:()","Hugepagesize:(kB)","DirectMap4k:(kB)","DirectMap2M:(kB)"
2013/03/03, 23:58:48,2054984,1161012,99012,605416,0,282204,439192,17128,8,265076,439184,0,0,4128760,4128760,8,0,16960,15536,172,132568,77788,54780,808,4056,0,0,0,5156252,140192,34359738367,274388,34359451196,0,0,0,0,0,0,2048,8192,2088960
2013/03/03, 23:58:49,2054984,1160996,99012,605412,0,282176,439192,17104,8,265072,439184,0,0,4128760,4128760,8,0,16976,15576,172,132580,77792,54788,816,4036,0,0,0,5156252,140192,34359738367,274388,34359451196,0,0,0,0,0,0,2048,8192,2088960
2013/03/03, 23:58:50,2054984,1160996,99020,605412,0,282176,439200,17104,8,265072,439192,0,0,4128760,4128760,20,0,16976,15576,172,132580,77792,54788,816,4036,0,0,0,5156252,140192,34359738367,274388,34359451196,0,0,0,0,0,0,2048,8192,2088960
2013/03/03, 23:58:51,2054984,1160996,99020,605412,0,282216,439200,17144,8,265072,439192,0,0,4128760,4128760,20,0,16972,15576,172,132580,77792,54788,816,4036,0,0,0,5156252,140192,34359738367,274388,34359451196,0,0,0,0,0,0,2048,8192,2088960

cronで取得する(日/週/月単位のトレンド取得)

長期のトレンドを見たい場合は、cronで分以上の間隔で取得するのが良い。

取得用のシェル

  • /usr/lib64/sa/meminfo.sh
#!/bin/bash
LANG=C
PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:
export LANG PATH
umask 022

LOGFILE_BASE="/var/log/sa/meminfo"
LOGFILE="${LOGFILE_BASE}.`date +%Y%m%d`"

# Write header, if LOGFILE does not exist.
if [ ! -f ${LOGFILE} ]; then
    awk '
        BEGIN{
            printf "\"DATE\",\"TIME\""
        }
        {
            printf ",\"%s(%s)\"",$1,$3
        }
        END{
            printf "\n"
        }' /proc/meminfo > ${LOGFILE}

    fi

# Write data
awk '
        BEGIN{
            printf strftime("%Y/%M/%d, %H:%M:%S")
        }
        {
            printf ",%d",$2
        }
        END{
            printf "\n"
        }' /proc/meminfo >> ${LOGFILE}

exit 0

シェルをキックするcron設定

1分間隔で取得する。

  • /etc/cron.d/meminfo
# Get meminfo.
* * * * * root /usr/lib64/sa/meminfo  > /dev/null 2>&1

ログのローテーションは。。。別に考えよう(^^;

シェル用のメッセージロギングツール

シェルのメッセージを一元的に出力する自作のツールです。
職場で使われているロギングツールがシンプルで使いやすいので、同じようなものを自作したものです。

ツールはgithubで公開しています。

configureの作り方(autotoolsの使い方)

はじめに

オープンソースでよくある、configure → make → make installというセットアップの流れ。これはGNUのautotoolsというツール&フレームワーク群により実現されている。
本記事ではそのautotoolsによりconfigureを作成する手順を説明する。

作成の流れ

  1. 必要ファイルの作成(automake時に必要)
  2. Makefile.am作成(後の作成/修正も可)
  3. autoscanコマンドの実行
  4. configure.acファイルの作成&編集
  5. aclocal実行
  6. autoheader実行
  7. automake実行
  8. autoconf実行

ユーザが編集するファイルは、configure.acとMakefile.am。これらファイルを修正した時は、aclocalコマンド以降を都度実行してファイルを再生性する。なので、aclocalコマンド以降をシェル化して一気に実行するようにしておくと便利である。

f:id:nopipi:20130109013829p:plain

手順詳細

必要ファイルの作成

automakeコマンド実行時に求められるファイルを作成する。とりあえずファイルがあればよいので、空ファイルを作成する。(内容は必要に応じ別途修正する)

$ touch INSTALL NEWS README LICENSE AUTHORS ChangeLog

Makefile.am作成(後の作成/修正も可)

次のautoscanコマンドで、AC_CONFIG_FILESを自動生成するため、とりあえずMakefile.amを作成する。とりあえずこの段階では空ファイルでもかまわない。(automake実行時に中身があればOK)

 -> Makefile.amのつくり方(別途作成予定)

autoscanコマンドの実行

configure.scanを作成し、それをRenameしてconfigure.acを作成する。

$ autoscan
$ mv configure.scan configure.ac

configure.acファイルの作成&編集

configure.acを修正する。詳細は別途作成

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

sAC_PREREQ([2.63])
AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS]) <== パッケージ&バージョン&連絡先を記入
AC_CONFIG_SRCDIR([src/uplog_util.c])
AC_CONFIG_HEADERS([config.h])

# Checks for programs.
AC_PROG_CC

# Checks for libraries.

# Checks for header files.
AC_CHECK_HEADERS([fcntl.h limits.h locale.h stdlib.h string.h sys/socket.h syslog.h unistd.h])

# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_PID_T

# Checks for library functions.
AC_FUNC_FORK
AC_FUNC_MALLOC
AC_FUNC_STRNLEN
AC_CHECK_FUNCS([dup2 getcwd gethostname gettimeofday memset realpath select setlocale socket strerror])

AC_CONFIG_FILES([Makefile
                 conf/Makefile
                 src/Makefile]) <==Makefile.amを増やしたらここに追加
AC_OUTPUT

aclocal実行以降

以後はシェル化し、Makefile.amやconfigure.ac修正時に都度実行すると楽。

echo aclocal
aclocal
echo autoheader
autoheader
echo automake
automake --add-missing --copy
echo autoconf
autoconf

ESXi TeraTermマクロ自動化

本当はvSphere CLIをインストールして利用すればよいのだが、VMのPowerOnとハイパーバイザのシャットダウンだけで十分だったので、TeraTermのマクロで自動化。

前提

ESXiは、SSH 鍵認証でログインできること。
SSH設定詳細はこちら→ESXi5 SSH 有効化&鍵認証(TeraTermの自動ログインマクロ付) - のぴぴのメモ

ESXi Hypervisorシャットダウン

コマンド"vim-cmd hostsvc/standby_mode_enter'"で停止。

; ==========================================================
; Setting (IP, UserName, KEY file)
HOSTADDR = 'xxx.xxx.xxx.xx'       ;ESXiのIPアドレス
USERNAME = 'root'
KEY_FILE = 'xxxxxxxxxxxxxxxxxxxx' ;ログインに使用する秘密鍵
CNF_FILE = 'xxxxxxxxxxxxxxxxxxxx' ;TeraTermの設定ファイル
; ==========================================================


;; Generate login command
COMMAND = HOSTADDR
strconcat COMMAND ':22 /ssh /2 /auth=publickey /user='
strconcat COMMAND USERNAME
strconcat COMMAND ' /keyfile="'
strconcat COMMAND KEY_FILE
strconcat COMMAND '" /F="'
strconcat COMMAND CNF_FILE
strconcat COMMAND '"'

;; Login
connect COMMAND
wait '~ #'

;; shutdown hypervisor
sendln 'vim-cmd hostsvc/standby_mode_enter'
sendln 'exit'

end

VM PowerON

  1. "vim-cmd vmsvc/getallvms"コマンドで、VM一覧を取得
  2. 取得したVM一覧よりリストを生成、起動したいVMの番号をインプットボックスより入力
  3. "vim-cmd vmsvc/power.getstate vim"で、各VMのPower状態を取得
  4. "vim-cmd vmsvc/power.on VMID"コマンドでVMを起動
; ==========================================================
; Setting (IP, UserName, KEY file)
HOSTADDR = 'xxx.xxx.xxx.xx'       ;ESXiのIPアドレス
USERNAME = 'root'
KEY_FILE = 'xxxxxxxxxxxxxxxxxxxx' ;ログインに使用する秘密鍵
CNF_FILE = 'xxxxxxxxxxxxxxxxxxxx' ;TeraTermの設定ファイル
; ==========================================================
;; Initialize
NUM=256
strdim VM_NO   NUM
strdim VM_NAME NUM
strdim VM_STAT NUM

timeout=1


;; Generate login command
COMMAND = HOSTADDR
strconcat COMMAND ':22 /ssh /2 /auth=publickey /user='
strconcat COMMAND USERNAME
strconcat COMMAND ' /keyfile="'
strconcat COMMAND KEY_FILE
strconcat COMMAND '" /F="'
strconcat COMMAND CNF_FILE
strconcat COMMAND '"'

;; Login
connect COMMAND
wait '~ #'


;;PowerOn VM
count = 0
result = 1
sendln 'vim-cmd vmsvc/getallvms'
waitln 'Vmid'
while result
    ; receive VM list
    recvln
    if result = 0 then
        goto getall_fail
    endif
    strmatch inputstr '~ #'
    if result <> 0 then
        goto getall_fail
    endif
    
    ; Split
    strreplace inputstr 1 '\s+' ' '
    strsplit inputstr " "
    VM_NO[count]   = groupmatchstr1
    VM_NAME[count] = groupmatchstr2
    
    count = count + 1
    goto getall_end
    :getall_fail
    result = 0
    
    :getall_end
endwhile

; Get VM power status
for i 0 count-1
    ; get VM stat
    MSG = 'vim-cmd vmsvc/power.getstate '
    strconcat MSG VM_NO[i]
    sendln MSG
    waitln 'Retrieved'
    
    recvln
    strsplit inputstr " "
    VM_STAT[i] = groupmatchstr2
next


;;Select VM
MSG="Select VM Number\n-----------------------------\n"
for i 0 count-1
    int2str stri  i
    strconcat MSG stri
    strconcat MSG '.\t'
    strconcat MSG VM_STAT[i]
    strconcat MSG '\t'
    strconcat MSG VM_NAME[i]
    strconcat MSG '\n'
next
strconcat MSG '\n\n-1\tCancel\n-----------------------------'

:select_RETRY
inputbox MSG 'select VM' 1
str2int vmnum inputstr
if result = 0 then
    goto select_RETRY
endif
if vmnum < 0 then
    goto EXIT_MACRO
endif


; PowerON VM
COMMAND= 'vim-cmd vmsvc/power.on '
strconcat COMMAND VM_NO[vmnum]
sendln COMMAND
wait '~ #'

;;exit
:EXIT_MACRO

sendln 'exit'
end

VM PowerOFF

  1. "vim-cmd vmsvc/getallvms"コマンドで、VM一覧を取得
  2. 取得したVM一覧よりリストを生成、起動したいVMの番号をインプットボックスより入力
  3. "vim-cmd vmsvc/power.getstate vim"で、各VMのPower状態を取得
  4. "vim-cmd vmsvc/power.off VMID"コマンドでVMを停止
; ==========================================================
; Setting (IP, UserName, KEY file)
HOSTADDR = 'xxx.xxx.xxx.xx'       ;ESXiのIPアドレス
USERNAME = 'root'
KEY_FILE = 'xxxxxxxxxxxxxxxxxxxx' ;ログインに使用する秘密鍵
CNF_FILE = 'xxxxxxxxxxxxxxxxxxxx' ;TeraTermの設定ファイル
; ===========================================================
;; Initialize
NUM=256
strdim VM_NO   NUM
strdim VM_NAME NUM
strdim VM_STAT NUM

timeout=1


;; Generate login command
COMMAND = HOSTADDR
strconcat COMMAND ':22 /ssh /2 /auth=publickey /user='
strconcat COMMAND USERNAME
strconcat COMMAND ' /keyfile="'
strconcat COMMAND KEY_FILE
strconcat COMMAND '" /F="'
strconcat COMMAND CNF_FILE
strconcat COMMAND '"'

;; Login
connect COMMAND
wait '~ #'


;;PowerOn VM
count = 0
result = 1
sendln 'vim-cmd vmsvc/getallvms'
waitln 'Vmid'
while result
    ; receive VM list
    recvln
    if result = 0 then
        goto getall_fail
    endif
    strmatch inputstr '~ #'
    if result <> 0 then
        goto getall_fail
    endif
    
    ; Split
    strreplace inputstr 1 '\s+' ' '
    strsplit inputstr " "
    VM_NO[count]   = groupmatchstr1
    VM_NAME[count] = groupmatchstr2
    
    count = count + 1
    goto getall_end
    :getall_fail
    result = 0
    
    :getall_end
endwhile

; Get VM power status
for i 0 count-1
    ; get VM stat
    MSG = 'vim-cmd vmsvc/power.getstate '
    strconcat MSG VM_NO[i]
    sendln MSG
    waitln 'Retrieved'
    
    recvln
    strsplit inputstr " "
    VM_STAT[i] = groupmatchstr2
next

;;Select VM
MSG="Select VM Number\n-----------------------------\n"
for i 0 count-1
    int2str stri  i
    strconcat MSG stri
    strconcat MSG '.\t'
    strconcat MSG VM_STAT[i]
    strconcat MSG '\t'
    strconcat MSG VM_NAME[i]
    strconcat MSG '\n'
next
strconcat MSG '\n\n-1\tCancel\n-----------------------------'

:select_RETRY
inputbox MSG 'select VM' 1
str2int vmnum inputstr
if result = 0 then
    goto select_RETRY
endif
if vmnum < 0 then
    goto EXIT_MACRO
endif


; PowerON VM
COMMAND= 'vim-cmd vmsvc/power.off '
strconcat COMMAND VM_NO[vmnum]
sendln COMMAND
wait '~ #'

;;exit
:EXIT_MACRO

sendln 'exit'
end

ESXi5 SSH 有効化&鍵認証(TeraTermの自動ログインマクロ付)

VMware ESXi5をSSHでリモートで操作したい場合の設定手順を記録する。

1.ESXのSSHサービスを有効にする

SSHのサービス有効化は、コンソール画面とvSphereClientの2通りのがあるらしい。
ここではコンソール画面からの変更を記載する。

  • "F2"キーを押し、コンソールにログインする
  • "Trubleshooting Options"を選択する
  • "Enable SSH"を選択し「リターン」キーを押す

これでSSHが有効化される。

ちなみにコンソール画面から直接操作するには、ひとつ上の項目"Enable ESXi shell"を有効化する。ついでに、コンソールシェル(ESXi shell)も有効化する。(必須ではない)

  • "Trubleshooting Options" -> "Enable ESXi shell"でシェルを有効かする。
  • ESXi shellを有効化したあと"ALT+F1"キーを押すとシェル画面に切り替わる
  • 元の画面(System Coustomization)に戻るには、"ALT+F2"キーを押す

2.TeraTermからパスワード認証ログインを確認

TeraTermからSSHのパスワード認証でログイン可能なことを確認する。ここで中が必要なのは、ESXi5では「チャレンジレスポンス認証」を利用しているらしく、TeraTermSSH認証で「チャレンジレスポンス認証を使う(キーボードインタラクティブ)」を選択する必要があることである。(下図参照)
f:id:nopipi:20121117215649p:plain

3.鍵の設定

SSHでとりあえずログインできることを確認したら、ESXiにログインに利用する公開鍵を登録する。

  • TeraTermで鍵を作成する(詳細はググルこと)
    • 「設定(S)」->「SSH鍵生成(N)」を選択
    • 鍵の種類を「RSA」にして「生成(G)」ボタンで鍵を生成
    • 公開鍵&秘密鍵を保存する
  • ESXiにパスワード認証でログインする

~ # cd /etc/ssh/keys-root
/etc/ssh/keys-root #
  • TeraTermで作成した公開鍵をエディタで開きファイル内の文字列をauthorized_keysに貼り付ける
/etc/ssh/keys-root # cat > authorized_keys
<<公開鍵のテキストカット&ペーストする>>
"CTL+D"を押すと入力終了する
/etc/ssh/keys-root #
  • TeraTermから鍵認証でログインできることを確認する
  • TeraTermからESXiにSSH接続
  • SSH認証画面で「RSA/DSA鍵を使う」を選択し、秘密鍵のファイルを指定

f:id:nopipi:20121117220601p:plain

4.TeraTerm鍵認証による自動ログインマクロ

参考までに、SSH鍵認証の場合の自動ログインマクロを公開。

; ==========================================================
; Setting (IP, UserName, KEY file)
HOSTADDR = 'xxx.xxx.xxx.xx'       ;ESXiのIPアドレス
USERNAME = 'root'
KEY_FILE = 'xxxxxxxxxxxxxxxxxxxx' ;ログインに使用する秘密鍵
CNF_FILE = 'xxxxxxxxxxxxxxxxxxxx' ;TeraTermの設定ファイル
; ==========================================================


;; Generate login command
COMMAND = HOSTADDR
strconcat COMMAND ':22 /ssh /2 /auth=publickey /user='
strconcat COMMAND USERNAME
strconcat COMMAND ' /keyfile="'
strconcat COMMAND KEY_FILE
strconcat COMMAND '" /F="'
strconcat COMMAND CNF_FILE
strconcat COMMAND '"'

;; Login
connect COMMAND
wait '~ #'

end