require 'open3' class PerfmonProcGetter attr_reader :pid # Initializes the PerfmonProcGetter class def initialize @all_counters = `#{get_all_counters_command}` end # Creates a new process that runs typeperf to collect perfmon metrics # [counters] Array of counter names, such as ["\\Processor(_Total)\\% Processor Time"] # [interval] The number, in seconds, to wait between each round of collecting metrics # [output_queue] The queue to add each new message to def start_process(counters, interval, output_queue) cmd = get_typeperf_command(counters, interval) Open3.popen3(cmd) do |w, r, e, thr| while line = r.gets if @pid.nil? @pid = thr.pid end next if counters.any? { |counter| line.include? counter } # don't show lines that contain headers line.gsub!('"', '') # remove quotes line.strip! output_queue << line end end end # Kills the typeperf process def stop_process Process.kill(9, @pid) @pid = nil end # Gets a value indicating whether the typeperf # process is currently running def proc_is_running? if @pid.nil? return false else return true end end # Gets a value indicating whether the given counter # exists on the system # [counter_name] The name of the counter, such as "\\Processor(_Total)\\% Processor Time" def counter_exists?(counter_name) counter_name = counter_name.gsub(/\(.+\)/, '(*)') return @all_counters.downcase.include?(counter_name.downcase) end # Gets the typeperf command line # [counters] Array of counter names, such as ["\\Processor(_Total)\\% Processor Time"] # [interval] The number, in seconds, to wait between each round of collecting metrics def get_typeperf_command(counters, interval) cmd = "typeperf " counters.each { |counter| cmd << "\"#{counter}\" " } cmd << "-si #{interval.to_s} " return cmd.strip! end # Gets the command line that lists all available # perf counters on the system def get_all_counters_command "typeperf -q" end # Waits until the typeperf process is running def wait_for_process_to_start sleep 0.5 until proc_is_running? end end