Tuesday, October 12, 2010

Windows OS performance measurements by 'typeperf' in Ruby

I am writing a Windows resource monitoring script with ‘typeperf’ command in Ruby, so that i can centralize to get all my testing server's OS Health status during performance testing.
I simply get measurements like CPU%, Mem utlization, Disk I/O throughput and Network I/O throughput from Perfmon Counters.

perf_mon_util.rb Class Source code:
 class PerfMonUtil  
  @hostIPs = [];  
  def initialize(hostarray)  
   hostarray = hostarray.sub(/\s/, '');  
   @hostIPs = hostarray.split(',');  
   puts "monitor IP(s): " + @hostIPs * ",";  
  end  
  # the unit of duration is set to minutes by default  
  def perfmon(duration = 5,intv = 1, filepath = "C:\\temp_mon\\")  
   puts @hostIPs;  
   puts intv;  
   sampler_count = (duration.to_i * 60) / intv.to_i;  
   @hostIPs.each { |inputIP|  
    machineIP = inputIP.strip;  
    filename = filepath + machineIP.gsub(/\./,'_') + "-" + Time.now.strftime("%Y%m%d-%H%M%S");  
    Thread.new {  
        system("typeperf",  
        "\\processor(_total)\\% processor time", #CPU%  
        "\\processor(_total)\\% user time",  
        "\\processor(_total)\\% privileged time",  
        "\\Memory\\Available Kbytes", #MEM_Utilization  
        "\\physicaldisk(_total)\\% disk read time", #DISK I/O  
        "\\physicaldisk(_total)\\% disk write time",  
        "\\network interface(*#1)\\bytes total/sec", #NetWork I/O  
        "-s", "#{machineIP}","-si","#{intv}", "-sc", "#{sampler_count}", "-o", filename)  
        Process.exit!(1);  
     }  
   }  
  end  
 end  

Perf_mon_runner.rb source code:
 require 'perf_mon_util'  
 case ARGV.length  
 when 0  
  puts "Please assign monitored machines' name, you can access help by type Perf_mon_runner.rb -help"  
  puts "Process exiting..."  
  Process.exit!(1);  
 when 1  
  if ARGV[0] == "-help"  
   puts "usage samples listed: Perf_mon_runner.rb MonitredIPs Duration Interval FilePath"  
   puts "Perf_mon_runner.rb \"ip1,ip2,ip3\" 1 20 \"D:\\\\temp\\\\\""  
   puts "Monitoring object list(Measurements including):"  
   puts " \\processor(_total)\\% processor time"  
   puts " \\processor(_total)\\% user time"  
   puts " \\processor(_total)\\% privileged time"  
   puts " \\Memory\\Available Kbytes"  
   puts " \\physicaldisk(_total)\\% disk read time"  
   puts " \\physicaldisk(_total)\\% disk write time"  
   puts " \\network interface(*#1)\\bytes total/sec"  
   Process.exit!(1);  
  end  
  puts "put your monitoring files in C:\\temp_mon\\"  
  CPU_Utilization= PerfMonUtil.new(ARGV[0]);  
  CPU_Utilization.perfmon();  
 when 2  
  puts "put your monitoring files in C:\\temp_mon\\"  
  CPU_Utilization= PerfMonUtil.new(ARGV[0]);  
  CPU_Utilization.perfmon(ARGV[1]);  
 when 3  
  puts "put your monitoring files in C:\\temp_mon\\"  
  CPU_Utilization= PerfMonUtil.new(ARGV[0]);  
  CPU_Utilization.perfmon(ARGV[1],ARGV[2]);  
 when 4  
  puts "put your monitoring files in " + ARGV[3]  
  CPU_Utilization= PerfMonUtil.new(ARGV[0]);  
  CPU_Utilization.perfmon(ARGV[1],ARGV[2],ARGV[3]);  
 end  

How to use it in command-line:
Perf_mon_runner.rb ["YourIP1,YourIP2"] [Monitor_Duration] [Sample_Interval] [FilePath]

Real Usage sample:
Perf_mon_runner.rb "YourIP1,YourIP2" 1 20 "D:\\temp\\"

PS: The Monitoring result will write in the file path as .CSV format by default.

i am using Gruff to draw the graph of monitoring result:

the code is pretty straightforward:
 require 'csv'  
 require 'gruff'  
 def parserperfmon(csvfile,targetfile)  
  arraycpu = Array.new;  
  i = 0;  
  CSV.foreach(csvfile) do |rec|  
    # CPU% data is put into arraycpu
    arraycpu[i] = rec[1]  
    i = i+1;  
  end  
  #column title is removed
  arraycpu.shift  
  #String need to be converted to float type in arraycpu
  arraycpu.collect! { |item|  
   item.to_f  
  }  
  g = Gruff::Line.new  
  g.title = "CPU% Monitoring Graph";  
  g.data("CPU%", arraycpu)  
  g.write(targetfile)
 end  

 filename = "D:\\TEMP\\10_201_10_173-20101125-153102\.csv"  
 targetname ="D:\\TEMP\\perf_mon.png"
 parserperfmon(filename,targetname);  

will consider to add : \\System\\Processor Queue Length to monitor the Queue length:
An instantaneous count of threads that are in the processor queue.

3 comments:

  1. This blog has turned out quite nice, subscribing :)

    ReplyDelete
  2. How about displaying these metrics on a web page?

    ReplyDelete
  3. @Shaf
    Thanks for subscribing :-)

    @Wilson
    I am also considering to do that soon. I may Persist the Data to MySQL first and parser the data into Web page, then.
    Any suggestions or thoughts are highly welcomed :)

    ReplyDelete