Class: FrontEndLoader::Experiment

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeExperiment

Returns a new instance of Experiment.



21
22
23
24
25
26
27
28
29
30
# File 'lib/front_end_loader/experiment.rb', line 21

def initialize
  @screen = Screen.new(self)
  @running = false
  @mutex = Mutex.new
  @debug_mutex = Mutex.new
  @loop_count = -1
  @paused = false
  @run_completed_time = nil
  clear_data
end

Instance Attribute Details

#basic_auth_enabledObject (readonly)

Returns the value of attribute basic_auth_enabled.



9
10
11
# File 'lib/front_end_loader/experiment.rb', line 9

def basic_auth_enabled
  @basic_auth_enabled
end

#basic_auth_passwordObject (readonly)

Returns the value of attribute basic_auth_password.



11
12
13
# File 'lib/front_end_loader/experiment.rb', line 11

def basic_auth_password
  @basic_auth_password
end

#basic_auth_userObject (readonly)

Returns the value of attribute basic_auth_user.



10
11
12
# File 'lib/front_end_loader/experiment.rb', line 10

def basic_auth_user
  @basic_auth_user
end

#call_error_countsObject (readonly)

Returns the value of attribute call_error_counts.



18
19
20
# File 'lib/front_end_loader/experiment.rb', line 18

def call_error_counts
  @call_error_counts
end

#call_max_timesObject (readonly)

Returns the value of attribute call_max_times.



19
20
21
# File 'lib/front_end_loader/experiment.rb', line 19

def call_max_times
  @call_max_times
end

#call_timesObject (readonly)

Returns the value of attribute call_times.



17
18
19
# File 'lib/front_end_loader/experiment.rb', line 17

def call_times
  @call_times
end

#connect_timeoutObject

Returns the value of attribute connect_timeout.



8
9
10
# File 'lib/front_end_loader/experiment.rb', line 8

def connect_timeout
  @connect_timeout
end

#default_headersObject

Returns the value of attribute default_headers.



7
8
9
# File 'lib/front_end_loader/experiment.rb', line 7

def default_headers
  @default_headers
end

#default_parametersObject

Returns the value of attribute default_parameters.



6
7
8
# File 'lib/front_end_loader/experiment.rb', line 6

def default_parameters
  @default_parameters
end

#domainObject

Returns the value of attribute domain.



3
4
5
# File 'lib/front_end_loader/experiment.rb', line 3

def domain
  @domain
end

#loop_countObject

Returns the value of attribute loop_count.



5
6
7
# File 'lib/front_end_loader/experiment.rb', line 5

def loop_count
  @loop_count
end

#run_completed_timeObject (readonly)

Returns the value of attribute run_completed_time.



15
16
17
# File 'lib/front_end_loader/experiment.rb', line 15

def run_completed_time
  @run_completed_time
end

#run_start_timeObject (readonly)

Returns the value of attribute run_start_time.



14
15
16
# File 'lib/front_end_loader/experiment.rb', line 14

def run_start_time
  @run_start_time
end

#runningObject (readonly)

Returns the value of attribute running.



16
17
18
# File 'lib/front_end_loader/experiment.rb', line 16

def running
  @running
end

#screenObject (readonly)

Returns the value of attribute screen.



12
13
14
# File 'lib/front_end_loader/experiment.rb', line 12

def screen
  @screen
end

#timeoutObject

Returns the value of attribute timeout.



8
9
10
# File 'lib/front_end_loader/experiment.rb', line 8

def timeout
  @timeout
end

#user_countObject

Returns the value of attribute user_count.



4
5
6
# File 'lib/front_end_loader/experiment.rb', line 4

def user_count
  @user_count
end

Instance Method Details

#add_timeout(name) ⇒ Object



220
221
222
223
224
225
226
227
# File 'lib/front_end_loader/experiment.rb', line 220

def add_timeout(name)
  @mutex.synchronize do
    @call_counts[name] += 1
    @call_times[name] += 0
    @call_error_counts[name] += 1
    @error_counts_by_type['Timeout'] += 1
  end
end

#average_timesObject



237
238
239
240
241
242
243
244
245
246
# File 'lib/front_end_loader/experiment.rb', line 237

def average_times
  @call_times.keys.inject({}) do |hash, name|
    if @call_counts[name] == 0
      hash[name] = 0.0
    else
      hash[name] = @call_times[name] / @call_counts[name].to_f
    end
    hash
  end
end

#basic_auth(user, password) ⇒ Object



87
88
89
90
91
# File 'lib/front_end_loader/experiment.rb', line 87

def basic_auth(user, password)
  @basic_auth_enabled = true
  @basic_auth_user = user
  @basic_auth_password = password
end

#call_countsObject



229
230
231
# File 'lib/front_end_loader/experiment.rb', line 229

def call_counts
  @call_counts.dup
end

#clear_dataObject



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/front_end_loader/experiment.rb', line 59

def clear_data
  @mutex.synchronize do
    @call_counts ||= Hash.new { |h,k| h[k] = 0 }
    @call_counts.keys.each { |k| @call_counts[k] = 0 }

    @call_times ||= Hash.new { |h,k| h[k] = 0.0 }
    @call_times.keys.each { |k| @call_times[k] = 0.0 }

    @call_max_times ||= Hash.new { |h,k| h[k] = 0.0 }
    @call_max_times.keys.each { |k| @call_max_times[k] = 0.0 }

    @call_error_counts ||= Hash.new { |h,k| h[k] = 0 }
    @call_error_counts .keys.each { |k| @call_error_counts[k] = 0 }

    @call_times_last_25 ||= Hash.new { |h,k| h[k] = [] }
    @call_times_last_25.keys.each { |k| @call_times_last_25[k] = [] }

    @error_counts_by_type ||= Hash.new { |h,k| h[k] = 0 }
    @error_counts_by_type.keys.each { |k| @error_counts_by_type[k] = 0 }

    if @run_start_time
      @run_start_time = Time.now
    else
      @run_start_time = nil
    end
  end
end

#debug=(file) ⇒ Object



38
39
40
# File 'lib/front_end_loader/experiment.rb', line 38

def debug=(file)
  @debug_file = File.open(file, 'a')
end

#error_countsObject



252
253
254
# File 'lib/front_end_loader/experiment.rb', line 252

def error_counts
  @call_error_counts.dup
end

#error_percentsObject



260
261
262
263
264
265
266
267
268
269
# File 'lib/front_end_loader/experiment.rb', line 260

def error_percents
  @call_counts.keys.inject({}) do |hash, name|
    if @call_counts[name] && @call_counts[name] > 0 && @call_error_counts[name] && @call_error_counts[name] > 0
      hash[name] = (@call_error_counts[name].to_f / @call_counts[name].to_f) * 100.0
    else
      hash[name] = 0.0
    end
    hash
  end
end

#error_typesObject



256
257
258
# File 'lib/front_end_loader/experiment.rb', line 256

def error_types
  @error_counts_by_type.dup
end

#goObject



185
186
187
# File 'lib/front_end_loader/experiment.rb', line 185

def go
  @paused = false
end

#http_sessionObject



162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/front_end_loader/experiment.rb', line 162

def http_session
  Patron::Session.new.tap do |session|
    session.base_url = domain
    session.insecure = true
    session.max_redirects = 0
    if basic_auth_enabled
      session.auth_type = :basic
      session.username = basic_auth_user
      session.password = basic_auth_password
    end
    session.connect_timeout = connect_timeout || 10
    session.timeout = timeout || 500
  end
end

#max_timesObject



248
249
250
# File 'lib/front_end_loader/experiment.rb', line 248

def max_times
  @call_max_times.dup
end

#pauseObject



181
182
183
# File 'lib/front_end_loader/experiment.rb', line 181

def pause
  @paused = true
end

#paused?Boolean

Returns:

  • (Boolean)


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

def paused?
  @paused
end

#quitObject



193
194
195
# File 'lib/front_end_loader/experiment.rb', line 193

def quit
  @quitting = true
end

#quitting?Boolean

Returns:

  • (Boolean)


189
190
191
# File 'lib/front_end_loader/experiment.rb', line 189

def quitting?
  @quitting
end

#requests(&block) ⇒ Object



93
94
95
# File 'lib/front_end_loader/experiment.rb', line 93

def requests(&block)
  @request_block = block
end

#runObject



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/front_end_loader/experiment.rb', line 101

def run
  @running = true
  @run_start_time = Time.now

  threads = (1..user_count).to_a.map do
    Thread.new(self, @request_block) do |experiment, request_block|
      loops_left = experiment.loop_count
      while(loops_left != 0)
        if experiment.paused?
          sleep(0.25)
        elsif experiment.quitting?
          loops_left = 0
        else
          request_manager = RequestManager.new(experiment, experiment.http_session)
          request_block.call(request_manager)
          loops_left -= 1
        end
      end
      experiment.run_completed!
    end
  end

  threads << Thread.new(self) do |experiment|
    while (!experiment.quitting?)
      if experiment.paused?
        sleep(0.25)
      else
        experiment.screen.refresh
        sleep(0.1)
      end
    end
  end

  threads << Thread.new(self) do |experiment|
    while (!experiment.quitting?)
      ch = Curses.getch
      if ch == 'c'
        experiment.clear_data
      elsif ch == 'd'
        experiment.write_screen_to_debug
      elsif ch == 'p'
        experiment.pause
      elsif ch == 'q'
        experiment.quit
      elsif ch == 's'
        experiment.clear_data
        experiment.go
      end
    end
  end

  begin
    threads.each(&:run)
    threads.each(&:join)
  rescue Interrupt
    @screen.close
  end

  @screen.close
end

#run_completed!Object



97
98
99
# File 'lib/front_end_loader/experiment.rb', line 97

def run_completed!
  @run_completed_time = Time.now
end

#synchronize(&block) ⇒ Object



32
33
34
35
36
# File 'lib/front_end_loader/experiment.rb', line 32

def synchronize(&block)
  @mutex.synchronize do
    block.call
  end
end

#throughputObject



271
272
273
274
275
276
277
# File 'lib/front_end_loader/experiment.rb', line 271

def throughput
  delta = ((@run_completed_time || Time.now) - @run_start_time) / 60.0
  @call_counts.keys.inject({}) do |hash, name|
    hash[name] = @call_counts[name].to_f / delta
    hash
  end
end

#time_call(name, &block) ⇒ Object



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/front_end_loader/experiment.rb', line 197

def time_call(name, &block)
  begin
    start = Time.now
    response = block.call
    time = Time.now - start
    @mutex.synchronize do
      @call_times[name] += time
      @call_max_times[name] = time if time > @call_max_times[name]
      unless response.status >= 200 && response.status < 400
        write_debug(response.body)
        @call_error_counts[name] += 1
        @error_counts_by_type[response.status] += 1
      end
      @call_counts[name] += 1
      @call_times_last_25[name].unshift(time)
      @call_times_last_25[name] = @call_times_last_25[name].slice(0, 25)
    end
    response
  rescue Patron::TimeoutError
    add_timeout(name)
  end
end

#total_timesObject



233
234
235
# File 'lib/front_end_loader/experiment.rb', line 233

def total_times
  @call_times.dup
end

#write_debug(data) ⇒ Object



42
43
44
45
46
47
48
49
# File 'lib/front_end_loader/experiment.rb', line 42

def write_debug(data)
  if @debug_file
    @debug_mutex.synchronize do
      @debug_file.puts(data)
      @debug_file.flush
    end
  end
end

#write_screen_to_debugObject



51
52
53
54
55
56
57
# File 'lib/front_end_loader/experiment.rb', line 51

def write_screen_to_debug
  if @debug_file
    @debug_mutex.synchronize do
      @screen.write_debug(@debug_file)
    end
  end
end