負荷テストの分析グラフ

JMeter VS プログラマー自作ツールで書いたのだが、JMterではどうしてもできない負荷テスト(HTTPリクエストと同等の内容をDB渡し)があり、JMeterの前処理を書いて、CSVJMeterに渡そうかなと思ったのだがやめた。複雑すぎる。なので、自作の負荷テストツールを改造して使用することにした。
自作テストツールがJMeterと違うところは、指定時間でスレッドが階乗的に増えて行き、指定数まで増えたら、スレッドが一回ごとに終了しないでそのまま、リクエスト送信、レスポンス受信を繰り返すことだ。実際のイントラシステムでWEB渡ししてるところは、こんな感じの処理のほうが多いのではなかろうか?自作テストツールのソースは今度、機会があるときに載せます。このくらいであれば、誰でも作れそうな気はするが・・・
で・・・一番大きな問題は、自作負荷テストツールでテストするのは良いとして・・・最新のJMeterが出すような分析グラフが無い。膨大なログをエビデンスでつけたとして、「何これ?」と言われそう。困った。そんな時、岡崎さんという方のスループットを計測、分析しよう(3) 〜JMeterから取得したデータの分析〜を見た。これは、ちょっと昔、JMeterにグラフ表示が無かったときに、エクセルでスループットの分析グラフを出す方法。そうだ!自作ツールも通信ログはこのカタチで出せば、この方法で分析グラフができるではないか!おお!岡崎さん!ありがとう。感謝。謝謝!
当方テスト環境にACTIVE-PERLを入れ込むことは無理なので、岡崎さんの書いたPERLのプログラムをC#(visualStudio-Express edition)で書き直してみた。しかし、やってみると、テキスト(CSV)とか仮想配列を使用した時のPerlのすごさをあらためて知らされた次第。以下、C#に移植したPG。
calcfd hogehoge.csv > outfile.csv として使用する。出力CSVの分析グラフはスループットを計測、分析しよう(3) 〜JMeterから取得したデータの分析〜を請参にしてください。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Calcfd
{
    class Program
    {
        const int timegrid = 1000;
        private static int start_time, elapsed_time, return_code, grid_begin, grid_end;
        private static string url;

        static void Main(string[] args)
        {
            try{
                System.IO.StreamReader streamReader = new System.IO.StreamReader(args[0], System.Text.Encoding.GetEncoding("Shift_JIS"));

                Dictionary<string, int> concurrency = new Dictionary<string, int>();	
                Dictionary<string, int> throughput  = new Dictionary<string, int>();	
        
                while (streamReader.Peek() != -1)
                {
                    string[] stringBuffer;
	                stringBuffer = streamReader.ReadLine().Split(',');
	                start_time =  int.Parse(stringBuffer[0].ToString());
                    elapsed_time = int.Parse(stringBuffer[1].ToString());
                    url = stringBuffer[2].ToString();
	                return_code  = int.Parse(stringBuffer[3].ToString());
	                grid_begin = (int)(start_time / timegrid);
	                grid_end = (int)((start_time + elapsed_time) / timegrid);

                    for (int g = grid_begin; g <= grid_end; g++) {
		                if( !concurrency.ContainsKey(g.ToString()) ){
                            concurrency[g.ToString()] = 1;
		                }
                        else{
			                concurrency[g.ToString()]++;
		                }   
	                }
                    if( !throughput.ContainsKey(grid_end.ToString())){
		                throughput[grid_end.ToString()] = 1;        
	                }
                    else{
		                throughput[grid_end.ToString()]++;
	                }
                }
                streamReader.Close();
                Console.Write( "time(ms),concurrency(time grid=" + timegrid + "ms),throughput(tps)\n");

                SortedDictionary<string, int> sconcurrency = new SortedDictionary<string, int>(concurrency);

                foreach (KeyValuePair<string, int> kvp in sconcurrency) {
      	            if( !throughput.ContainsKey(kvp.Key) ){
                        throughput[kvp.Key] = 0;
	                }
                    Console.WriteLine(@"{0},{1},{2}", int.Parse(kvp.Key) * timegrid, kvp.Value, throughput[kvp.Key]);
                }
            }
            catch (Exception e){
                Console.WriteLine("{0} Exception caught.", e);
            }
         }
     }
}

以上です。