2005年06月27日

パフォーマンス チューニング

あなたは「マシンがボロいせいで性能がでない」と感じたことはありますか? マシンがボロいということはハードウエアを増強すればプログラムをいじらなくても性能向上するわけです。 ただし,どこがボトルネックかを把握せずに闇雲にハードウエアを増強しても高いコストパフォーマンス得られません。
今回はハードウエアのボトルネックの追求方法を考えます。ネットワークを使用する場合はネットワークがボトルネックとなることがありますが今回は考えません。

全体像を把握するためにPCの構成を書いてみます。
PCの構成

PCではCPU,メモリ,ハードディスクの3箇所がボトルネックの容疑者となります。

  • CPUがボトルネックの場合:CPU利用率を監視する
  • メモリがボトルネックの場合:所要メモリを監視する
  • ハードディスクがボトルネックの場合:DISK I/Oを監視する

ボトルネックを判断する最初のツールはtopコマンドです。topコマンドの読み方を説明します。

 10:26:09  up 27 days, 13:59,  3 users,  load average: 0.44, 0.64, 0.49
67 processes: 66 sleeping, 1 running, 0 zombie, 0 stopped
CPU states:  cpu    user    nice  system    irq  softirq  iowait    idle
           total    0.0%    0.0%    0.1%   0.0%     0.0%    6.8%   93.1%
           cpu00    0.0%    0.0%    0.2%   0.0%     0.0%   13.4%   86.4%
           cpu01    0.0%    0.0%    0.0%   0.0%     0.0%    0.2%   99.8%
Mem:  4124036k av, 2459384k used, 1664652k free,       0k shrd,    2152k buff
                   1219456k actv,  333160k in_d,   55428k in_c
Swap:  522104k av,   13020k used,  509084k free                 1828964k cached

  PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME CPU COMMAND
    7 root      15   0     0    0     0 SW    0.0  0.0   5:21   1 kswapd

まずはシステム全体の構成について読み取ります。

  • CPUがcpu00,cpu01なので2CPUのマシンです。
  • Mem:4124036k,1664652k freeなので実メモリが4Gで空きメモリが1.7G弱です。
  • Swap:522104k,509084k freeなのでスワップは500Mでほとんど使用していません。

ではCPUがボトルネックとなった場合を見てみます。

10:33:02  up 27 days, 14:00,  3 users,  load average: 0.44, 0.62, 0.49
73 processes: 71 sleeping, 2 running, 0 zombie, 0 stopped
CPU states:  cpu    user    nice  system    irq  softirq  iowait    idle
           total   94.5%    0.0%    3.4%   0.0%     0.0%    1.4%    0.9%
           cpu00   95.0%    0.0%    4.8%   0.0%     0.0%    0.2%    0.0%
           cpu01   93.6%    0.0%    2.0%   0.0%     0.0%    2.6%    1.8%
Mem:  4124036k av, 2521440k used, 1602596k free,       0k shrd,    2224k buff
                   1282492k actv,  333160k in_d,   55428k in_c
Swap:  522104k av,   13008k used,  509096k free                 1828968k cached

  PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME CPU COMMAND
28447 apache    25   0 68956  67M  9968 R    47.5  1.6   0:08   0 test
28461 apache    25   0 68956  67M  9968 R    46.8  1.6   2:07   1 test

CPUがボトルネックの場合は簡単です。CPUのuserまたはsystemが100%近くに張り付いている場合です。
対処としてはCPUの増強やアルゴリズムの変更が一般的です。topコマンド実行中に "P" と入力すればCPU利用率順にソートされるので先頭付近にいるプロセスを対象に改善策を考えてください。

次にメモリがボトルネックとなった場合を見てみます。

 10:38:12  up 27 days, 14:11,  3 users,  load average: 2.06, 1.53, 0.97
77 processes: 76 sleeping, 1 running, 0 zombie, 0 stopped
CPU states:  cpu    user    nice  system    irq  softirq  iowait    idle
           total    6.8%    0.0%    0.6%   0.0%     0.0%   91.8%    0.7%
           cpu00   11.0%    0.0%    0.6%   0.0%     0.0%   86.9%    1.4%
           cpu01    2.6%    0.0%    0.6%   0.0%     0.0%   96.8%    0.0%
Mem:  4124036k av, 4107244k used,   16792k free,       0k shrd,    1016k buff
                   2826044k actv,  350332k in_d,   67036k in_c
Swap:  522104k av,  232180k used,  289924k free                 1423472k cached

  PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME CPU COMMAND
28447 apache    16   0 1574M 1.4G 91632 D     5.6 35.5   5:15   0 test
28461 apache    15   0  715M 691M 54964 D     1.0 17.1   2:09   1 test

メモリがボトルネックの場合はディスクがボトルネックの場合とよく似た出力になることがあります。スラッシングといってスワップイン,スワップアウトにCPUとディスクIOを占有されて他の処理をできなくなる現象が発生するからです。
判断のポイントは,メモリのfreeのサイズとプロセスの所要メモリです。vmstatコマンドを使用してスワップイン,スワップアウトの回数を計測するのもいいでしょう。
対処としてはメモリの増設やプログラムのメモリ使用量を削減するのが一般的です。CPU利用率と同様にtopコマンド実行中に "M" と入力すればメモリ所要量順にソートされます。

最後にディスクがボトルネックとなった場合を見てみます。

 10:45:10  up 27 days, 14:11,  3 users,  load average: 2.06, 1.53, 0.97
77 processes: 76 sleeping, 1 running, 0 zombie, 0 stopped
CPU states:  cpu    user    nice  system    irq  softirq  iowait    idle
           total    9.8%    0.0%    0.6%   0.0%     0.0%   88.5%    0.7%
           cpu00   14.9%    0.0%    0.6%   0.0%     0.0%   83.1%    1.4%
           cpu01    4.6%    0.0%    0.6%   0.0%     0.0%   94.8%    0.0%
Mem:  4124036k av, 4107244k used, 1602596k free,       0k shrd,    1016k buff
                   2826044k actv,  350332k in_d,   67036k in_c
Swap:  522104k av,   13008k used,  509096k free                 1828968k cached

  PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME CPU COMMAND
28447 apache    16   0 68956  67M  9968 R     5.6 35.5   5:15   0 test
28461 apache    15   0 68956  67M  9968 R     1.0 17.1   2:09   1 test

ディスクがボトルネックの場合はiowaitの値が大きくなっています。ただし前述したようにメモリがボトルネックの可能性もあるので,空きメモリの確認を同時に行います。
対処としてはiostatコマンドなどを使用して使用ディスクを割り出し,ディスク自体を高性能なものに交換する。アクセスするディスクを分散させるといった手段が一般的です。
なお,ディスク障害の場合はディスクに何回も読み込みや書き込みを行うため,突如ディスクがボトルネックとなる場合があります。いままでは問題なかったのに突然ディスクがボトルネックとなった場合はディスクの障害を疑う必要もあります。

ちょっと量が多くなったので今週はここまでです。来週はvmstat,iostatの使用法を解説します。



posted by まる at 21:59| Comment(0) | TrackBack(0) | プログラマ Chips | このブログの読者になる | 更新情報をチェックする

2005年06月20日

デスマーチ哀話

みなさんはデスマーチと聞いて何を想像しますか?IT業界の人であれば身をもって知っているでしょうが,学生さんやカタギの人は雑誌や噂で聞いたことがある程度でしょう。 デスマーチがどんなものか残業時間別に観察してみましょう。

残業時間称号説明
  〜40趣味人一日の平均残業時間が2時間以下です。
元気一杯です。一日は余暇にあふれています。今日は何をしようかなって感じでしょうか。
この暇人め。うらやましいぞ。
40〜60一般人一日の平均残業時間が2〜3時間です。
夕飯には間に合わないかもしれませんが,趣味の時間は確保できるでしょう。
60〜80悲しき
労働者
一日の平均残業時間が3〜4時間です。帰宅は22時を越すでしょう。
筆者がこんな時間に帰宅すると余暇の長さに呆然としてしまいます。
80〜100不満分子一日の平均残業時間が4〜5時間です。
その日のうちに帰宅するのが難しくなってきます。 自分の境遇や会社に対し怒りを覚え始めます。転職や人生の意味について考えてみたりもします。
100〜150業界人一日の平均残業時間が5時間程度で,休日出勤も追加されてます。
納期直前だと徹夜もします。納期直前でこのぐらいなら許容範囲としておかないと,同業他社に転職してもきっと同じ目にあいます。
150〜200負け犬一日の平均残業時間が6時間程度で,帰宅は午前様が基本です。
週休2日の会社でも休日は1日でしょう。運が悪ければ土日とも出勤です。
たまの休日はひたすら眠ります。遊びに行って体力を消耗するなんてとんでもない。だんだんと思考能力が麻痺してきて,今の状況を抜け出すことしか考えられなくなってきます。
200〜 廃人会社に泊り込んでます。平日だろうと休日だろうと早朝だろうと深夜だろうと仕事をしています。仕事をしていない時間は食事をしているか,寝ているかどちらかです。
ねむくてねむくてしょうがないです。思考の大半は睡魔との戦いです。
睡魔以外にも目がかすむ,手足がしびれる,耳鳴りがするといった身体の不調を訴える人も多く,寿命を縮めてるというヤバイ実感があります。
感情も麻痺し,会社や状況に対して怒る気力すら沸いてきません。人というよりはもはやロボットです。

どこからをデスマーチとして認定するか友人や後輩と議論した結果,100時間超の残業が数ヶ月続くとデスマーチではないかという結論になりました。
なるべくならデスマーチには近寄りたくないのですが,避けられるものではないのが難しいところです。上司を経由してデスマーチから迫ってくるのが困りものです。
だれかどうにかしてください。ホントに。

posted by まる at 20:18| Comment(0) | TrackBack(0) | プログラマ Chips | このブログの読者になる | 更新情報をチェックする

2005年06月13日

日本一短い上司からのメール

筆者があるデスマーチに放り込まれたときの出来事です。この案件は他社と仕様の扱いで揉めており,部課長を含めてメールが飛び交っていました。

他社「御社の提供したライブラリは弊社の要求どおりに動作していない」
筆者「弊社は2ヶ月以上前に仕様書を提出している。御社の指摘は仕様書に記載済みの事項である。」
他社「御社では仕様と言うが,御社の仕様は弊社の要求事項を満たしていない。仕様不良ではないか。」
筆者「そのような指摘は仕様書のレビュー時にすべき事項である。御社として問題ないと判断したから合議したのではないか。」
他社「そうは言っても御社の…」

この議論に負けると自分たちのチームが悲惨な目にあうことは確定です。
プログラムの根幹に関わる仕様変更なのでソースの修正量がハンパじゃありません。ソースを修正すると今までのテスト成果もパアです。テストを一からやり直す羽目になります。今でも休日も会社に来てるし,平日の帰宅は午前様なのです。これ以上の作業が増えると徹夜以外に選択肢がありません。
自分だけならまだしも同僚たちも同じ目にあいます。負けるわけにはいきません。他社も同様の状況らしく担当者は相当熱くなってました。

こんな状態のある日,幹部からメールが届きました。事態を打開する素晴らしいメールに違いないとワクワクしながらメールを開きました。
せっかくなのでこの素晴らしいメールの本文を全文引用します。

To: 関係者各位
Subject: XXXの扱いについて

よろしく。

肝心な部分を省略しているわけではありません。本当に5文字です。全文を引用してもたった5文字です。
誰に何を指示してるんでしょうか。意味不明です。幹部もボケたのでしょうか。
徹夜の後でもあり相当頭にきました。いっそ幹部に文句を言おうかと考えたぐらいです。

しばらくすると,部長から信じられないようなメールが返ってきました。

To: 幹部
Cc: 関係者各位
Subject: Re:XXXの扱いについて

指示いただきありがとうございます。
次のように対処します。

(1) XXXの扱い
弊社の見解は仕様です。
ただし,プロジェクト完遂のため要望事項にあわせて仕様を変更します。

(2) 対策期日
ソースの修正が必要となるため提供を○月に延期します。
他社でのテストが滞らないようにテスト用のモジュールは別途提供します。
日程は別途相談します。

(3) 要員
テスト工程以降に人員をX名追加します。
...

メールの内容自体はこちらが譲歩した場合の案であり違和感はありません。 しかし,先ほどのメールのどこに指示があったのでしょう。筆者には全然分かりませんでした。
あまりに不思議だったのでタバコ部屋に部長が行ったときに直接聞いてみました。

筆者「さっきのメールのどこにそんな指示があったんですか?」
部長「今の状態だとお互いに不幸だよね。だからこっちが泥をかぶって相手に貸しを作るわけ。今回の相手とは今後もつきあうので,ここで貸しを作っておけば後で困ったときに有利に働くしね。」
筆者「それは分かりますけど…」
部長「君たちのチームが厳しいのも分かるけど,相手の会社にも余裕がないみたいだね。実はテストに割り振るチームの当てはあるけどこの案件で使っていいか迷ってたんだ。そこにさっきのメールが来たでしょ。あれはテスト用のチームを使っていいという幹部からの許可なんだよ。」
筆者「はあ。」
部長「事態が膠着するまで放置するとは何事だ。相手との信頼関係の問題にもなる。さっさと対処しろというプレッシャーもあのメールにはこめられてるんだよ。」
筆者「そうは読めませんでしたが。」
部長「似たような局面で『何事だ!』と怒鳴り散らしたことがあったからね。幹部が課長の頃からのつきあいだから,あれで十分な指示なんだよ。」

まさに以心伝心というやつでしょうか。

posted by まる at 22:45| Comment(0) | TrackBack(0) | 管理者 Chips | このブログの読者になる | 更新情報をチェックする

2005年06月06日

カエサルのものはカエサルへ

今回の記事ではオブジェクトの多態性について解説します。
日本語と英語に対応したメッセージの処理を考えます。メッセージの出力処理として直感的に思いつくのは次のようなコードではないでしょうか。

import java.util.*;

// 日本語メッセージクラス
class Message_ja {
  public Message_ja(){}
  public String getMessage(){ return "日本語メッセージ"; }
}

// 英語メッセージクラス
class Message_en {
  public Message_en(){}
  public String getMessage(){ return "English message"; }
}

// テスト用クラス
class TestMessage
{
  public static void main( String[] args )
  {
    Message_ja msg_ja = new Message_ja();
    Message_en msg_en = new Message_en();

    // メッセージの表示
    Locale loc = Locale.getDefault();
    if( loc == Locale.JAPAN ){
      System.out.println(msg_ja.getMessage());
    } else if( loc == Locale.ENGLISH ){
      System.out.println(msg_en.getMessage());
    }
  }
}

このようなコードでも動作しますがカッコ悪いです。呼び出し側(この場合はmain)にメッセージ出力用の条件分岐があるあたりにセンスのなさを感じます。メッセージを出力するたびに条件分岐を書けということでしょうか。コードを書いたのが後輩だったら体育館の裏に呼び出してヤキを入れるところです。
呼び出し側で条件分岐を書いてしまうと保守性が格段に悪くなります。たとえば日本語,英語の他にドイツ語をサポートする場合は呼び出し側の全てのif文を修正しなければなりません。一箇所でも漏らすとバグとなるのでホントに勘弁してくださいって感じです。

こういった場合はインターフェースを共有するか共通の親を持つ子クラスを作成します。

import java.util.*;

// メッセージクラス
abstract class Message {
  public static Message getInstance(){
    try{
      // ロケールに応じたインスタンスを生成
      Class c = Class.forName( "Message_" + Locale.getDefault().getLanguage() );
      return (Message)c.newInstance();
    } catch( Exception e ){
      e.printStackTrace();
      return null;
    }
  }

  abstract public String getMessage();

  // 日本語メッセージクラス
  class Message_ja extends Message {
    public Message_ja(){}
    public String getMessage(){ return "日本語メッセージ"; }
  }

  // 英語メッセージクラス
  class Message_en extends Message {
    public Message_en(){}
    public String getMessage(){ return "English message"; }
  }
}

// テスト用クラス
class TestMessage
{
  public static void main( String[] args )
  {
    // メッセージの表示
    Message msg = Message.getInstance();
    System.out.println(msg.getMessage());
  }
}

このコードではエラー処理をサボっています。納品するソースがこのままだったらやはり体育館の裏に呼び出すでしょう。
多態性を利用することで,呼び出し側は抽象クラスのメッセージ出力処理を記述するだけでよく,英語と日本語を判定する余分な処理から解放されます。 メッセージ出力処理はメッセージ出力クラスの責任なのでメッセージ出力クラスに仕事をさせるべきです。

「カエサルのものはカエサルへ,神のものは神に返しなさい」

人に仕事をおしつけないように配慮してクラス設計を行いましょう。

posted by まる at 22:49| Comment(0) | TrackBack(0) | プログラマ Chips | このブログの読者になる | 更新情報をチェックする

広告


この広告は60日以上更新がないブログに表示がされております。

以下のいずれかの方法で非表示にすることが可能です。

・記事の投稿、編集をおこなう
・マイブログの【設定】 > 【広告設定】 より、「60日間更新が無い場合」 の 「広告を表示しない」にチェックを入れて保存する。


×

この広告は180日以上新しい記事の投稿がないブログに表示されております。