module Beaker::DSL::BeakerBenchmark::Helpers

Constants

DISK_READ_INDEX
DISK_WRITE_INDEX
IDLE_CPU_INDEX
IOWAIT_CPU_INDEX
MEASURE_TYPE_INDEX

Column indexes for atop CSV style output

MEM_INDEX
PROC_CPU_INDEX
PROC_DISK_READ_INDEX
PROC_DISK_WRITE_INDEX
PROC_MEM_INDEX
PROC_PID_INDEX
SYSTEM_CPU_INDEX
TMP_DIR
USR_CPU_INDEX

Public Instance Methods

add_process_measure(measure_type, pid, value) click to toggle source
# File lib/beaker-benchmark/helpers.rb, line 174
def add_process_measure measure_type, pid, value
  if @processes_to_monitor.keys.include? pid
    @processes_to_monitor[pid][measure_type].push value
  end
end
measure_perf_on(infrastructure_host, action_name, include_processes=false, process_regex='/opt/puppetlabs') { || ... } click to toggle source

Example usage: test_name('measure_perf_on_puppetserver_start') {

on(master, 'puppet resource service pe-puppetserver ensure=stopped')
result = measure_perf_on(master, 'start_pe-puppetserver', true) {
  on(master, 'puppet resource service pe-puppetserver ensure=running')
  # on(master, 'facter fqdn')
}
raise("pe-puppetserver restart took longer than 120 seconds: #{result.duration} seconds") if result.duration > 120
raise("pe-puppetserver restart used an average of more than 1gb of memory: #{result.avg_mem} bytes") if result.avg_mem > 1073741824
process_cpu = result.processes.select{ |pid, process| process[:cmd] =~ /puppet-server-release.jar/ }.values[0][:avg_cpu]
raise("pe-puppetserver restart caused pe-puppetserver service to use more than 95% of CPU: #{process_cpu}") if process_cpu > 95

}

# File lib/beaker-benchmark/helpers.rb, line 50
def measure_perf_on(infrastructure_host, action_name, include_processes=false, process_regex='/opt/puppetlabs', &block)
  # Append action name to test case name if test name is available
  action_name = metadata[:case][:name] + "_#{action_name}" if defined? metadata && metadata[:case] && metadata[:case][:name]

  start_monitoring(infrastructure_host, action_name, include_processes)

  yield

  stop_monitoring(infrastructure_host, include_processes.nil? ? nil : process_regex)
end
parse_atop_log(infrastructure_host, duration) click to toggle source
# File lib/beaker-benchmark/helpers.rb, line 101
def parse_atop_log(infrastructure_host, duration)
  unless infrastructure_host.file_exist?(@atop_log_filename)
    raise("atop log does not exist at #{@atop_log_filename}")
  end

  log_dir = "#{TMP_DIR}/#{infrastructure_host.hostname}"
  FileUtils::mkdir_p log_dir unless Dir.exist? log_dir

  # tar the atop log file before copying to avoid timeouts for large files (e.g. 2 week soak test)
  tar_file_name = "#{@atop_log_filename}.tar.gz"
  compress_cmd = "tar czf #{tar_file_name} #{@atop_log_filename}"
  on infrastructure_host, compress_cmd

  # copy the atop log file
  scp_from(infrastructure_host, tar_file_name, log_dir)

  # extract the tar file
  tgz = Zlib::GzipReader.new(File.open("#{log_dir}/#{tar_file_name}", "rb"))
  Archive::Tar::Minitar.unpack(tgz, log_dir)

  cpu_usage  = []
  mem_usage  = []
  disk_read  = []
  disk_write = []

  skip = true
  CSV.parse(File.read(File.expand_path(@atop_log_filename, log_dir)), { :col_sep => ' ' }) do |row|
    #skip the first entry, until the first separator 'SEP'.
    measure_type = row[MEASURE_TYPE_INDEX]
    if skip
      skip = (measure_type != 'SEP')
      next
    end
    case measure_type
      when 'CPU'
        # system + usr + iowait
        cpu_active = row[SYSTEM_CPU_INDEX].to_i + row[USR_CPU_INDEX].to_i + row[IOWAIT_CPU_INDEX].to_i
        # active + idle
        cpu_total = cpu_active + row[IDLE_CPU_INDEX].to_i
        cpu_percent = cpu_active * 100 / cpu_total
        cpu_usage.push(cpu_percent)
      when 'SWP'
        mem_usage.push(row[MEM_INDEX].to_i)
      when 'DSK'
        disk_read.push(row[DISK_READ_INDEX].to_i)
        disk_write.push(row[DISK_WRITE_INDEX].to_i)
      when 'PRC'
        add_process_measure(:cpu_usage, row[PROC_PID_INDEX], row[PROC_CPU_INDEX].to_i)
      when 'PRM'
        add_process_measure(:mem_usage, row[PROC_PID_INDEX], row[PROC_MEM_INDEX].to_i)
      when 'PRD'
        add_process_measure(:disk_read, row[PROC_PID_INDEX], row[PROC_DISK_READ_INDEX].to_i)
        add_process_measure(:disk_write, row[PROC_PID_INDEX], row[PROC_DISK_WRITE_INDEX].to_i)
    end
  end

  # rounding duration to improve results formatting
  PerformanceResult.new({ :cpu => cpu_usage, :mem => mem_usage, :disk_read => disk_read, :disk_write => disk_write, :action => @action_name, :duration => duration.round(2), :processes => @processes_to_monitor, :logger => @logger, :hostname => infrastructure_host})
end
set_processes_to_monitor(infrastructure_host, process_regex) click to toggle source
# File lib/beaker-benchmark/helpers.rb, line 161
def set_processes_to_monitor(infrastructure_host, process_regex)
  @processes_to_monitor = {}
  return unless process_regex
  result = on(infrastructure_host, "ps -eo pid,cmd | grep #{process_regex}").output
  result.each_line do |line|
    # use the PID as key and command with args as value
    # also ignore the ps and grep commands executed above.
    unless line.include? "grep #{process_regex}"
      @processes_to_monitor[line.split(' ').first] = { :cmd => line.split(' ')[1..-1].join(' '), :cpu_usage => [], :mem_usage => [], :disk_read => [], :disk_write => [] }
    end
  end
end
setup_atop(infrastructure_host) click to toggle source
# File lib/beaker-benchmark/helpers.rb, line 61
def setup_atop(infrastructure_host)
  # Only install atop once per host
  unless infrastructure_host.check_for_package('atop')
    add_el_extras(infrastructure_host, @options)
    infrastructure_host.install_package('atop')
  end
end
start_monitoring(infrastructure_host, action_name, include_processes=false, sample_interval=1) click to toggle source
# File lib/beaker-benchmark/helpers.rb, line 69
def start_monitoring(infrastructure_host, action_name, include_processes=false, sample_interval=1)
  raise('Monitoring already in progress, call stop_monitoring before calling start_monitoring a second time') unless @beaker_benchmark_start.nil?
  @atop_log_filename = "atop_log_#{action_name.downcase.gsub(/[^a-z0-9]/i, '_')}.log"
  @action_name       = action_name
  setup_atop(infrastructure_host)
  additional_args = ''
  additional_args = ',PRC,PRM,PRD' if include_processes
  atop_cmd        = "sh -c 'nohup atop -P CPU,SWP,DSK#{additional_args} -i #{sample_interval} >  #{@atop_log_filename} 2>&1 &'"

  on(infrastructure_host, atop_cmd)
  @beaker_benchmark_start = Time.now
  return @@session_timestamp
end
stop_monitoring(infrastructure_host, process_regex='.*') click to toggle source
# File lib/beaker-benchmark/helpers.rb, line 83
def stop_monitoring(infrastructure_host, process_regex='.*')
  begin
    if defined?@beaker_benchmark_start && !@beaker_benchmark_start.nil?
      duration = Time.now - @beaker_benchmark_start
    else
      raise('No monitoring in progress, call start_monitoring before calling stop_monitoring')
    end

    # The atop process sticks around unless killed
    # It can also take some time to kill depending on how long it has been running and sampling rate.
    retry_on infrastructure_host, 'pkill -15 -f atop', {:max_retries => 3, :retry_interval => 5}
    set_processes_to_monitor(infrastructure_host, process_regex)
    parse_atop_log(infrastructure_host, duration)
  ensure
    @beaker_benchmark_start = nil
  end
end