Class: ABProf::ABHarnessProcess

Inherits:
Object
  • Object
show all
Defined in:
lib/abprof.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(command_line, opts = {}) ⇒ ABHarnessProcess

Returns a new instance of ABHarnessProcess.



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/abprof.rb', line 183

def initialize command_line, opts = {}
  debug "Controller of nobody yet: SPAWN"
  @in_reader, @in_writer = IO.pipe
  @out_reader, @out_writer = IO.pipe
  @in_writer.sync = true
  @out_writer.sync = true
  @debug = opts[:debug]

  @pid = fork do
    STDOUT.reopen(@out_writer)
    STDIN.reopen(@in_reader)
    @out_reader.close
    @in_writer.close

    ENV['ABDEBUG'] = @debug.inspect

    if command_line.respond_to?(:call)
      STDERR.puts "Caution! An ABProf Harness process (non-bare) is being used with a block. This is almost never what you want!"
      command_line.call
    elsif command_line.respond_to?(:to_s)
      exec command_line.to_s
    else
      raise "Don't know how to execute benchmark code: #{command_line.inspect}!"
    end
    exit! 0
  end
  @out_writer.close
  @in_reader.close

  debug "Controller spawned #{@pid} (debug: #{@debug.inspect})"
end

Instance Attribute Details

#last_itersObject (readonly)

Returns the value of attribute last_iters.



177
178
179
# File 'lib/abprof.rb', line 177

def last_iters
  @last_iters
end

#last_runObject (readonly)

Returns the value of attribute last_run.



176
177
178
# File 'lib/abprof.rb', line 176

def last_run
  @last_run
end

Instance Method Details

#debug(string) ⇒ Object



179
180
181
# File 'lib/abprof.rb', line 179

def debug string
  STDERR.puts(string) if @debug
end

#killObject



220
221
222
223
224
# File 'lib/abprof.rb', line 220

def kill
  debug "Controller of #{@pid}: DIE"
  ::Process.detach @pid
  ::Process.kill "TERM", @pid
end

#quitObject



215
216
217
218
# File 'lib/abprof.rb', line 215

def quit
  debug "Controller of #{@pid}: QUIT"
  @in_writer.write "QUIT\n"
end

#run_iters(n) ⇒ Object



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# File 'lib/abprof.rb', line 226

def run_iters(n)
  debug "Controller of #{@pid}: #{n} ITERS"
  @in_writer.write "ITERS #{n.to_i}\n"

  ignored_out = 0
  state = :failed
  t_start = Time.now
  loop do
    # Read and block
    output = @out_reader.gets
    ignored_out += output.length
    debug "Controller of #{@pid} out: #{output.inspect}"
    if output =~ /^VALUES/ # These anchors match newlines, too
      state = :succeeded
      vals = MultiJson.load output[7..-1]
      raise "Must return an array value from iterations!" unless vals.is_a?(Array)
      raise "Must return an array of numbers from iterations!" unless vals[0].is_a?(Numeric)
      @last_run = vals
      break
    elsif output =~ /^VALUE/ # These anchors match newlines, too
      state = :succeeded
      val = output[6..-1].to_f
      raise "Must return a number from iterations!" unless val.is_a?(Numeric)
      @last_run = [ val ]
      break
    elsif output =~ /^OK$/   # These anchors match newlines, too
      state = :succeeded_get_time
      break
    elsif output =~ /^NOT OK$/ # These anchors match newlines, too
      # Failed, break
      state = :explicit_not_ok
      break
    elsif ignored_out > 10_000
      # 10k of output and no OK? Bail with failed state.
      state = :too_much_output_without_status
      break
    end
    # None of these? Loop again.
  end
  t_end = Time.now
  unless [:succeeded, :succeeded_get_time].include?(state)
    self.kill
    STDERR.puts "Killing process #{@pid} after failed iterations, error code #{state.inspect}"
  end

  @last_run = [ (t_end - t_start).to_f ] if state == :succeeded_get_time
  @last_iters = n

  @last_run
end