class Instrumentality::Profiler

Attributes

app_pid[R]
config[R]
dtrace_pid[R]
script_path[R]
verbose[R]
xcodebuild_pid[R]

Public Class Methods

new(config, verbose = false) click to toggle source
# File lib/instrumentality/profiler.rb, line 16
def initialize(config, verbose = false)
  @config = config
  @verbose = verbose
  script = config.script.dup
  script.prepend(Constants::EXPERIMENTAL) if @config.experimental
  @script_path = Finder.path_for_script(script)
  raise ProfilerError, "This intrument doesn't support --experimental flag".red unless File.exist?(script_path)
end

Public Instance Methods

profile() click to toggle source
# File lib/instrumentality/profiler.rb, line 25
def profile
  return interactive if @config.interactive
  current_directory = Dir.pwd
  Dir.mktmpdir do |tmpdir|
    compile(current_directory, tmpdir)
    Simctl.execute_with_simulator_ready(Constants::DEFAULT_RUNTIME, Constants::DEFAULT_DEVICE) do |device_udid|
      run_tests(tmpdir, device_udid)
      find_app_pid
      notify_server
      attach_dtrace(tmpdir)
      wait
    end
    process_dtrace_output(current_directory, tmpdir)
  end
end

Private Instance Methods

attach_dtrace(temporary_directory) click to toggle source
# File lib/instrumentality/profiler.rb, line 86
def attach_dtrace(temporary_directory)
  dtrace_cmd = %w[sudo dtrace]
  dtrace_cmd += %W[-q -s #{script_path}]
  dtrace_cmd += %W[-p #{app_pid}]
  dtrace_cmd += %W[> #{temporary_directory}/#{Constants::DTRACE_OUTPUT}]
  cmd = dtrace_cmd.join(' ')
  @dtrace_pid = Executor.execute_async(cmd)
end
compile(current_directory, temporary_directory) click to toggle source
# File lib/instrumentality/profiler.rb, line 49
def compile(current_directory, temporary_directory)
  xcodebuild_cmd = %w[xcodebuild]
  xcodebuild_cmd += if config.workspace
                      %W[-workspace #{current_directory}/#{config.workspace}]
                    else
                      %W[-project #{current_directory}/#{config.project}]
                    end
  xcodebuild_cmd += %W[-scheme #{config.scheme}]
  xcodebuild_cmd += %w[-sdk iphonesimulator]
  xcodebuild_cmd += %W[-derivedDataPath #{temporary_directory}/derivedData]
  xcodebuild_cmd += %w[clean build-for-testing]
  cmd = xcodebuild_cmd.join(' ')
  Executor.execute(cmd, verbose)
end
find_app_pid() click to toggle source
# File lib/instrumentality/profiler.rb, line 74
def find_app_pid
  @app_pid = Executor.timeout(config.process)
end
interactive() click to toggle source
# File lib/instrumentality/profiler.rb, line 43
def interactive()
  find_app_pid
  attach_dtrace('.')
  stream_dtrace_output
end
notify_server() click to toggle source
# File lib/instrumentality/profiler.rb, line 78
def notify_server
  uri = URI.parse("http://localhost:#{config.server_port}/")
  http = Net::HTTP.new(uri.host, uri.port)
  http.request(Net::HTTP::Get.new(uri.request_uri))
rescue
  retry
end
process_dtrace_output(current_directory, temporary_directory) click to toggle source
# File lib/instrumentality/profiler.rb, line 100
def process_dtrace_output(current_directory, temporary_directory)
  report = "timeStamp,elapsed,label,responseCode,success\n"
  epoch = Time.now.to_i
  File.readlines("#{temporary_directory}/#{Constants::DTRACE_OUTPUT}").each do |line|
    to_parse = line.strip
    next if to_parse.empty?
    values = to_parse.split(Constants::TRACE_SCRIPT_DELIMITER)
    view_controller = values[0]
    elapsed = values[1].to_f / 1000000
    report += "#{epoch},%.0f,#{view_controller},#{Constants::RESPONSE_CODE},#{Constants::SUCCESS}\n" % elapsed
  end
  File.write("#{current_directory}/#{Constants::JTL_REPORT}", report)
end
run_tests(temporary_directory, device_udid) click to toggle source
# File lib/instrumentality/profiler.rb, line 64
def run_tests(temporary_directory, device_udid)
  xctestrun = Finder.find_xctestrun(temporary_directory)
  xcodebuild_cmd = %w[xcodebuild]
  xcodebuild_cmd += %W[-xctestrun #{xctestrun}]
  xcodebuild_cmd += %W[-destination 'platform=iOS Simulator,id=#{device_udid}']
  xcodebuild_cmd += %w[test-without-building]
  cmd = xcodebuild_cmd.join(' ')
  @xcodebuild_pid = Executor.execute_async(cmd)
end
stream_dtrace_output() click to toggle source
# File lib/instrumentality/profiler.rb, line 114
def stream_dtrace_output
  output_file = Constants::DTRACE_OUTPUT
  FileUtils.rm_rf(output_file) if File.exist? output_file
  touch_cmd = %W[touch "#{output_file}"]
  cmd = touch_cmd.join(' ')
  Executor.execute(cmd, verbose)
  stream = IO.new(IO.sysopen(output_file))
  Logger.log("Started interactive session. #{"Press CTRL+C to finish.".blue}")
  begin
    loop do
      output = stream.gets
      puts output unless output.nil?
    end
  rescue SignalException => e
    raise ProfilerInterruptError, "Interactive session ended. Full output at ./#{output_file}".green
  end
end
wait() click to toggle source
# File lib/instrumentality/profiler.rb, line 95
def wait
  Process.wait(xcodebuild_pid)
  Process.kill("QUIT", dtrace_pid)
end