bigbench 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. data/README.textile +29 -249
  2. data/bigbench.gemspec +1 -0
  3. data/bin/bigbench +1 -1
  4. data/dev/request_sequence.dot +235 -0
  5. data/dev/request_sequence.pdf +0 -0
  6. data/dev/sequence.rb +48 -0
  7. data/doc/Array.html +5 -5
  8. data/doc/BigBench.html +27 -60
  9. data/doc/BigBench/Benchmark.html +5 -5
  10. data/doc/BigBench/Benchmark/Benchmark.html +8 -8
  11. data/doc/BigBench/Benchmark/Looper.html +5 -5
  12. data/doc/BigBench/Bot.html +5 -5
  13. data/doc/BigBench/Configuration.html +29 -53
  14. data/doc/BigBench/Executor.html +14 -95
  15. data/doc/BigBench/Executor/Executable.html +551 -0
  16. data/doc/BigBench/Fragment.html +5 -5
  17. data/doc/BigBench/Fragment/Fragment.html +5 -5
  18. data/doc/BigBench/Output.html +7 -8
  19. data/doc/BigBench/PostProcessor.html +8 -8
  20. data/doc/BigBench/PostProcessor/Context.html +219 -0
  21. data/doc/BigBench/PostProcessor/Environment.html +5 -5
  22. data/doc/BigBench/PostProcessor/Environment/Appearings.html +5 -5
  23. data/doc/BigBench/PostProcessor/Environment/AttributeCluster.html +5 -5
  24. data/doc/BigBench/PostProcessor/Environment/BenchmarkNotFound.html +5 -5
  25. data/doc/BigBench/PostProcessor/Environment/Cluster.html +5 -5
  26. data/doc/BigBench/PostProcessor/Environment/NormalDistribution.html +5 -5
  27. data/doc/BigBench/PostProcessor/Environment/PolynomialRegression.html +5 -5
  28. data/doc/BigBench/PostProcessor/Environment/Statistics.html +5 -5
  29. data/doc/BigBench/PostProcessor/Graphs.html +5 -5
  30. data/doc/BigBench/PostProcessor/Graphs/LineGraph.html +5 -5
  31. data/doc/BigBench/PostProcessor/Graphs/PieGraph.html +5 -5
  32. data/doc/BigBench/PostProcessor/InvalidProcessor.html +6 -6
  33. data/doc/BigBench/PostProcessor/Processor.html +6 -6
  34. data/doc/BigBench/PostProcessor/Statistics.html +5 -5
  35. data/doc/BigBench/PostProcessor/Test.html +6 -6
  36. data/doc/BigBench/PostProcessor/TestPretty.html +249 -0
  37. data/doc/BigBench/Runner.html +5 -5
  38. data/doc/BigBench/Runner/NoBenchmarksDefined.html +5 -5
  39. data/doc/BigBench/Store.html +8 -8
  40. data/doc/BigBench/Tracker.html +5 -5
  41. data/doc/BigBench/Tracker/Tracker.html +5 -5
  42. data/doc/EventMachineLoop.html +5 -5
  43. data/doc/Float.html +5 -5
  44. data/doc/Gemfile.html +5 -5
  45. data/doc/Helpers.html +5 -5
  46. data/doc/Object.html +24 -5
  47. data/doc/README_rdoc.html +51 -281
  48. data/doc/Rakefile.html +5 -5
  49. data/doc/created.rid +46 -46
  50. data/doc/index.html +51 -281
  51. data/doc/js/search_index.js +1 -1
  52. data/doc/lib/bigbench/help/executor_txt.html +14 -29
  53. data/doc/table_of_contents.html +63 -68
  54. data/lib/bigbench.rb +2 -0
  55. data/lib/bigbench/benchmark.rb +3 -3
  56. data/lib/bigbench/configuration.rb +29 -68
  57. data/lib/bigbench/executor.rb +100 -130
  58. data/lib/bigbench/help/executor.txt +9 -22
  59. data/lib/bigbench/output.rb +2 -3
  60. data/lib/bigbench/post_processor.rb +16 -4
  61. data/lib/bigbench/runner.rb +0 -1
  62. data/lib/bigbench/store.rb +2 -2
  63. data/lib/bigbench/templates/test_plan.rb.erb +17 -0
  64. data/lib/bigbench/version.rb +1 -1
  65. data/spec/configure_spec.rb +7 -18
  66. data/spec/executor_spec.rb +25 -35
  67. data/spec/post_processor_spec.rb +31 -1
  68. data/spec/post_processors/environment_spec.rb +5 -3
  69. data/spec/post_processors/graphs_spec.rb +8 -3
  70. data/spec/post_processors/statistics_spec.rb +6 -1
  71. data/spec/runner_spec.rb +7 -6
  72. data/spec/store_spec.rb +4 -3
  73. data/spec/tests/local.rb +5 -5
  74. data/spec/tests/with_post_processor.rb +5 -5
  75. data/spec/tracker_spec.rb +12 -8
  76. metadata +48 -31
  77. data/dev/test.rb +0 -13
@@ -31,12 +31,12 @@ h2. Test Receipts
31
31
 
32
32
  How do the test receipts look like? As easy as possible. For example like this in @example.rb@:
33
33
 
34
- bc.. configure => {
35
- :duration => 2.minutes,
36
- :output => "example.ljson",
37
- :users => 5,
38
- :basic_auth => ['username', 'password']
39
- }
34
+ bc.. BigBench.configure do |config|
35
+ config.duration = 2.minutes
36
+ config.output = "example.ljson"
37
+ config.users = 5
38
+ config.basic_auth = ['username', 'password']
39
+ end
40
40
 
41
41
  benchmark "default website pages" => "http://localhost:3000" do
42
42
  get "/"
@@ -52,7 +52,11 @@ end
52
52
 
53
53
  post_process :statistics
54
54
 
55
+ h3. Generator
56
+
57
+ You can have your test receipts generated!
55
58
 
59
+ bc.. bigbench generate sample
56
60
 
57
61
  h2. Single Host vs. Multiple Hosts Testing
58
62
 
@@ -62,21 +66,21 @@ h3. Single Host
62
66
 
63
67
  BigBench allows you to run your tests against every host from your local machine. The command for this looks like this:
64
68
 
65
- bc.. bigbench run local example.rb
69
+ bc.. bigbench local example.rb
66
70
 
67
71
  h3. Multiple Hosts with Bots
68
72
 
69
73
  BigBench uses a bot design pattern which means you can run your tests from multiple hosts. Everything you need for this is a redis that is reachable from all testing hosts. Every host simply starts a bot that is checking for a new test receipt every minute like this:
70
74
 
71
- bc.. bigbench start bot redis_url:port redis_password
75
+ bc.. bigbench bot redis_url:port redis_password
72
76
 
73
77
  p. Then to run the tests from all hosts simply use the same receipt as you would use for a local run and call it like this:
74
78
 
75
- bc.. bigbench run bots example.rb redis_url:port redis_password
79
+ bc.. bigbench bots example.rb redis_url:port redis_password
76
80
 
77
81
  p. This will upload the test receipt to all bots and make them run it. Every bot reports its results back to the redis and the local machine then combines, and writes them to the output file. So you test with the same receipts and get the same results, no matter if your testing from the local host or with multiple bots.
78
82
 
79
- !http://southdesign.github.com/bigbench/images/structure.png(BigBench Request Structure)!
83
+ !http://southdesign.github.com/bigbench/graphs/structure.png(BigBench Request Structure)!
80
84
 
81
85
  h2. Output
82
86
 
@@ -124,7 +128,7 @@ post_process do
124
128
 
125
129
  end
126
130
 
127
- p. It's very easy to write a post processor. The basic structure is like this:
131
+ p. It's also very easy to write an own post processor. The basic structure is like this:
128
132
 
129
133
  bc.. module BigBench
130
134
  module PostProcessor
@@ -144,260 +148,30 @@ bc.. post_process :sample_post_processor
144
148
  # or
145
149
  post_process BigBench::PostProcessor::SamplePostProcessor
146
150
 
147
- h3. Post Processor Environment
148
-
149
- Post processors by default offer a great load of functionality that helps to evaluate the benchmarks. The available methods are:
150
-
151
- h4. each_tracking
152
-
153
- Iterate over each of the tracking elements. The trackings are read line-by-line. This is the fastest approach and should be used for huge datasets because the trackings are not loaded completely into memory.
151
+ h3. Post Processor Environment API
154
152
 
155
- bc.. total_trackings, total_errors = 0, 0
156
- each_tracking do |tracking|
157
- total_trackings += 1
158
- total_errors += 1 unless tracking[:status] == 200
159
- end
160
-
161
- h4. trackings
153
+ BigBench automatically supports a great load of functionality for every post processor it would need anyways. This functionality is offered through the
162
154
 
163
- An array with all tracking hashes in it. The creation might take some time at the first usage, afterwards the array is cached automatically.
155
+ * "Post Processor Environment API":https://github.com/southdesign/bigbench/wiki/Post-Processor-Environment-API
164
156
 
165
- bc.. trackings.size # => 650456
166
- trackings.each do |tracking|
167
- puts tracking[:duration]
168
- end
169
-
170
- h4. statistics
171
-
172
- Computes the default statistics for any attribute
173
-
174
- bc.. # Unclustered statistics
175
- statistics.durations.max # => 78.2
176
- statistics.durations.min # => 12.3
177
-
178
- statistics.durations.mean # => 45.2
179
- statistics.durations.average # => 45.2
180
-
181
- statistics.durations.standard_deviation # => 11.3
182
- statistics.durations.sd # => 11.3
183
-
184
- statistics.durations.squared_deviation # => 60.7
185
- statistics.durations.variance # => 60.7
186
-
187
- # Time clustered statistics - 1.second
188
- statistics.requests.max # => 42.1
189
- statistics.requests.min # => 12.3
190
- statistics.methods(:get).max # => 42.1
191
- statistics.methods(:get).average # => 33.1
192
- statistics.benchmark("index page").average # => 32.9
193
- statistics.paths("/").average # => 12.5
194
-
195
- h4. cluster
196
-
197
- Clusters the resulting trackings by a timebase. The default timebase is @1.second@ which means, that it groups all trackings to full seconds and calculates the amount of requests and the average duration.
198
-
199
- bc.. # Duration is 120 seconds for this example
200
-
201
- # 1.second
202
- cluster.timesteps # => [1, 2, ..., 120]
203
- cluster.durations # => [43, 96, ..., 41]
204
- cluster.requests # => [503, 541, ..., 511]
205
- cluster.methods(:get) # => [200, 204, ..., 209]
206
- cluster.methods(:post) # => [201, 102, ..., 401]
207
- cluster.statuses(200) # => [501, 502, ..., 102]
208
- cluster.statuses(404) # => [3, 1, ..., 0]
209
- cluster.paths("/") # => [401, 482, ..., 271]
210
- cluster.paths("/logout") # => [56, 51, ..., 38]
211
- cluster.benchmark("index") # => [342, 531, ..., 234]
212
- cluster.benchmark("user") # => [22, 41, ..., 556]
213
-
214
- # 1.minute
215
- cluster(1.minute).timesteps # => [0, 1]
216
- cluster(1.minute).durations # => [42, 44]
217
- cluster(1.minute).requests # => [24032, 21893]
218
- cluster(1.minute).methods(:get) # => [200, 204]
219
- cluster(1.minute).statuses(200) # => [501, 502]
220
- cluster(1.minute).paths("/") # => [401, 482]
221
- cluster(1.minute).benchmark("user") # => [22, 41]
222
-
223
- # 30.seconds
224
- cluster(30.seconds).timesteps # => [0, 1, 2, 3]
225
- cluster(30.seconds).durations # => [42, 44, 41, 40]
226
- cluster(30.seconds).requests # => [11023, 10234, 12345, 13789]
227
- cluster(30.seconds).methods(:get) # => [200, 204, 34, 124]
228
- cluster(30.seconds).statuses(200) # => [501, 502, 243, 57]
229
- cluster(30.seconds).paths("/") # => [401, 482, 124, 234]
230
- cluster(30.seconds).benchmark("user") # => [22, 41, 12, 51]
231
-
232
- h4. appearing
233
-
234
- Lists the unique attribute values that appeared in all trackings or the selected tracking scope.
235
-
236
- bc.. appearing.statuses # => [200, 404]
237
- appearing.methods # => ["get", "post"]
238
- appearing.paths # => ["/", "/basic/auth"
239
-
240
- h4. polynomial_regression
241
-
242
- The polynomial regression creates a function that tries to map the test data best. With this function you have the ability do derivate and thereby plot the changes of the tested system over time. The degree of the regression can be freely chosen.
243
-
244
- bc.. # Linear regression by default
245
- polynomial_regression.durations.x # => [1, 2, ..., 120]
246
- polynomial_regression.durations.y # => [45, 23, ..., 36]
247
- polynomial_regression.requests.y # => [43, 45, ..., 62]
248
- polynomial_regression.methods(:get).y # => [23, 62, ..., 23]
249
- polynomial_regression.statuses(200).y # => [51, 22, ..., 15]
250
- polynomial_regression.paths("/").y # => [78, 12, ..., 63]
251
- polynomial_regression.benchmarks("index page").y # => [12, 45, ..., 23]
252
- polynomial_regression.durations.degree # => 1
253
- polynomial_regression.durations.formula # => "43.00886000234 + 0.0167548964060689x^1"
254
-
255
- # 1. Derivation
256
- polynomial_regression.durations.derivation(1) # => [0.01, 0.01, ..., 0.01]
257
- polynomial_regression.requests.derivation(1) # => [405, 405, ..., 406]
258
- polynomial_regression.methods(:get).derivation(1) # => [23, 62, ..., 23]
259
- polynomial_regression.statuses(200).derivation(1) # => [51, 22, ..., 15]
260
- polynomial_regression.paths("/").derivation(1) # => [78, 12, ..., 63]
261
- polynomial_regression.benchmarks("index page").derivation(1) # => [12, 45, ..., 23]
262
- polynomial_regression.durations.formula(1) # => "0.0167548964060689"
263
-
264
- # Quadratic regression
265
- polynomial_regression(:degree => 2).requests.x # => [1, 2, ..., 120]
266
- polynomial_regression(:degree => 2).durations.y # => [43, 41, ..., 44]
267
- polynomial_regression(:degree => 2).requests.y # => [43, 41, ..., 44]
268
- polynomial_regression(:degree => 2).methods(:get).y # => [23, 62, ..., 23]
269
- polynomial_regression(:degree => 2).statuses(200).y # => [51, 22, ..., 15]
270
- polynomial_regression(:degree => 2).paths("/").y # => [78, 12, ..., 63]
271
- polynomial_regression(:degree => 2).benchmarks("index page").y # => [12, 45, ..., 23]
272
- polynomial_regression(:degree => 2).requests.formula # => "33.00886000234 + 0.0167548964060689x^1 + 0.0167548964060689x^2"
273
-
274
- # Different timebase clustering
275
- polynomial_regression(:degree => 2, :timebase => 1.minute).requests.x # => [0, 1]
276
- polynomial_regression(:degree => 2, :timebase => 1.minute).requests.y # => [24032, 21893]
277
- polynomial_regression(:degree => 2, :timebase => 1.minute).durations.y # => [43, 41]
278
- polynomial_regression(:degree => 2, :timebase => 1.minute).requests.y # => [43, 41]
279
- polynomial_regression(:degree => 2, :timebase => 1.minute).methods(:get).y # => [23, 62]
280
- polynomial_regression(:degree => 2, :timebase => 1.minute).statuses(200).y # => [51, 22]
281
- polynomial_regression(:degree => 2, :timebase => 1.minute).paths("/").y # => [78, 12]
282
- polynomial_regression(:degree => 2, :timebase => 1.minute).benchmarks("index page").y # => [12, 45]
283
-
284
- h4. normal_distribution
285
-
286
- The normal distribution method creates a Gaussian bell function that visualizes the distribution of a special attribute. If you want to know if all your requests take about the same time, or if they vary a lot this is method to use. The x-values are automatically scaled to 4-times the variance around the mean, so it should map the whole bell all the time.
287
-
288
- bc.. # Normal distribution without time clustering
289
- normal_distribution.durations.x # => [1, 2, ..., 120]
290
- normal_distribution.durations.y # => [45, 23, ..., 36]
291
- normal_distribution.durations.formula # => "(1 / (10.242257627240862 * sqrt(2*PI))) * exp(-1 * ((x - 2.04671984377919)^2) / (2*10.242257627240862))"
292
-
293
- # Normal distribution with default time slicing of 1.second
294
- normal_distribution.requests.y # => [43, 45, ..., 62]
295
- normal_distribution.methods(:get).y # => [23, 62, ..., 23]
296
- normal_distribution.statuses(200).y # => [51, 22, ..., 15]
297
- normal_distribution.paths("/").y # => [78, 12, ..., 63]
298
- normal_distribution.benchmarks("index page").y # => [12, 45, ..., 23]
299
-
300
- # Normal distribution with custom time slicing
301
- normal_distribution(1.minute).requests.y # => [43, 45, ..., 62]
302
- normal_distribution(1.minute).methods(:get).y # => [23, 62, ..., 23]
303
- normal_distribution(1.minute).statuses(200).y # => [51, 22, ..., 15]
304
- normal_distribution(1.minute).paths("/").y # => [78, 12, ..., 63]
305
- normal_distribution(1.minute).benchmarks("index page").y # => [12, 45, ..., 23]
306
-
307
- h4. scope_to_benchmark
308
-
309
- The scope_to_benchmark method lets you scope any result to a single benchmark. The values computed in this block have entirely been created by this benchmark.
310
-
311
- bc.. # Results for the index page benchmark
312
- scope_to_benchmark "index page" do
313
- cluster.durations # => [43, 96, ..., 41]
314
- cluster.requests # => [503, 541, ..., 511]
315
- cluster.methods(:get) # => [200, 204, ..., 209]
316
- cluster.methods(:post) # => [201, 102, ..., 401]
317
- polynomial_regression.durations.x # => [1, 2, ..., 120]
318
- polynomial_regression.durations.y # => [45, 23, ..., 36]
319
- normal_distribution.requests.y # => [43, 45, ..., 62]
320
- normal_distribution.methods(:get).y # => [23, 62, ..., 23]
321
- normal_distribution.statuses(200).y # => [51, 22, ..., 15]
322
- end
157
+ h3. Included Post Processors
323
158
 
324
- # Results for the login and logout benchmark
325
- scope_to_benchmark "login and logout" do
326
- cluster.durations # => [43, 96, ..., 41]
327
- cluster.requests # => [300, 141, ..., 511]
328
- cluster.methods(:get) # => [100, 204, ..., 209]
329
- cluster.methods(:post) # => [101, 102, ..., 401]
330
- polynomial_regression.durations.x # => [1, 2, ..., 120]
331
- polynomial_regression.durations.y # => [45, 23, ..., 36]
332
- normal_distribution.requests.y # => [43, 45, ..., 62]
333
- normal_distribution.methods(:get).y # => [23, 62, ..., 23]
334
- normal_distribution.statuses(200).y # => [51, 22, ..., 15]
335
- end
159
+ By default BigBench ships with a few very useful post processors that might already fit your needs perfectly. The full list of included post processors is shown in the wiki:
336
160
 
337
- h4. each_benchmark
338
-
339
- Iterates over all benchmarks and automatically scopes the results at each iteration to the current benchmark. This is useful if you want to access the detailed differences of each benchmark.
340
-
341
- bc.. # Iterate over all benchmarks and calculate the results
342
- each_benchmark do |benchmark|
343
- benchmark.name # => "index page" then "login and logout"
344
-
345
- cluster.durations # => [43, 96, ..., 41]
346
- cluster.requests # => [300, 141, ..., 511]
347
- cluster.methods(:get) # => [100, 204, ..., 209]
348
- cluster.methods(:post) # => [101, 102, ..., 401]
349
- polynomial_regression.durations.x # => [1, 2, ..., 120]
350
- polynomial_regression.durations.y # => [45, 23, ..., 36]
351
- normal_distribution.requests.y # => [43, 45, ..., 62]
352
- normal_distribution.methods(:get).y # => [23, 62, ..., 23]
353
- normal_distribution.statuses(200).y # => [51, 22, ..., 15]
354
- end
161
+ * "Post Processors":https://github.com/southdesign/bigbench/wiki/Post-Processors
355
162
 
356
163
  h3. Running Post Processors separately
357
164
 
358
165
  You can also re-run the currently defined post processors or run a separate post processor you never even defined in the first place without collecting the test data again like this:
359
166
 
360
167
  bc.. # Re-run the postprocessors defined in example.rb
361
- bigbench run postprocessors example.rb
168
+ bigbench process example.rb
362
169
 
363
170
  # Run a separate post processor independently - the already defined post processors are ignored
364
- bigbench run postprocessor example.rb statistics
171
+ bigbench process example.rb statistics
365
172
 
366
173
  p. Contribute, create great post processors and send me a pull request!
367
174
 
368
- h3. Statistics
369
-
370
- p. The statistics post processor computes a simple overview of the benchmark and prints it to the terminal like this:
371
-
372
- bc.. BigBench Statistics
373
- +---------------------------+------------------+---------+
374
- | Name | Value | Percent |
375
- +---------------------------+------------------+---------+
376
- | Total Requests: | 52,469 | 100% |
377
- | Total Errors: | 0 | 0.0% |
378
- | | | |
379
- | Average Requests/Second: | 437 Requests/sec | |
380
- | Average Request Duration: | 1 ms | |
381
- | | | |
382
- | Max Request Duration: | 181 ms | |
383
- | Min Request Duration: | 1 ms | |
384
- | | | |
385
- | Status Codes: | | |
386
- | 200 | 52469 | 100.0% |
387
- | | | |
388
- | HTTP Methods | | |
389
- | get | 34980 | 66.7% |
390
- | post | 17489 | 33.3% |
391
- | | | |
392
- | URL Paths: | | |
393
- | / | 34979 | 66.7% |
394
- | /basic/auth | 17490 | 33.3% |
395
- +---------------------------+------------------+---------+
396
- 19 rows in set
397
-
398
-
399
-
400
-
401
175
 
402
176
  h2. Load Comparison
403
177
 
@@ -425,6 +199,12 @@ h3. Test Results
425
199
 
426
200
  h2. Version History
427
201
 
202
+ h3. 0.5
203
+
204
+ * Changed @configure@ syntax to a common ruby pattern block style
205
+ * Refactored and simplified command line usage with thor
206
+ * Added a generator for test files
207
+
428
208
  h3. 0.4
429
209
 
430
210
  * Added command line tool to run the post processors again
@@ -34,4 +34,5 @@ Gem::Specification.new do |s|
34
34
  s.add_runtime_dependency "eventmachine"
35
35
  s.add_runtime_dependency "em-http-request"
36
36
  s.add_runtime_dependency "hirb"
37
+ s.add_runtime_dependency "thor", '>= 0.15.2'
37
38
  end
@@ -3,4 +3,4 @@
3
3
  require 'rubygems'
4
4
  require 'bigbench'
5
5
 
6
- BigBench::Executor.run! ARGV
6
+ BigBench::Executor::Executable.start
@@ -0,0 +1,235 @@
1
+ digraph
2
+ {
3
+ subgraph "benchmark_serving website"
4
+ {
5
+ label = "benchmark 'serving website'";
6
+ subgraph "serving website_0_looper"
7
+ {
8
+ label = "looper user 0";
9
+ subgraph "requests_0"
10
+ {
11
+ label = "requests 0";
12
+ node [ style = filled, color = lightgray ];
13
+ "serving website_0_0" [ label = "Fragment Request 0",shape = box ];
14
+ "serving website_0_1" [ label = "Fragment Request 1",shape = box ];
15
+ "serving website_0_2" [ label = "Fragment Request 2",shape = box ];
16
+ "serving website_0_3" [ label = "Fragment Request 3",shape = box ];
17
+ "serving website_0_0" -> "serving website_0_1";
18
+ "serving website_0_1" -> "serving website_0_2";
19
+ "serving website_0_2" -> "serving website_0_3";
20
+ "serving website_0_3" -> "serving website_0_0";
21
+ };
22
+ "serving website_0" [ label = "looper user #0" ];
23
+ "serving website_0_0";
24
+ "serving website_0" -> "serving website_0_0";
25
+ };
26
+ subgraph "serving website_1_looper"
27
+ {
28
+ label = "looper user 1";
29
+ subgraph "requests_1"
30
+ {
31
+ label = "requests 1";
32
+ node [ style = filled, color = lightgray ];
33
+ "serving website_1_0" [ label = "Fragment Request 0",shape = box ];
34
+ "serving website_1_1" [ label = "Fragment Request 1",shape = box ];
35
+ "serving website_1_2" [ label = "Fragment Request 2",shape = box ];
36
+ "serving website_1_3" [ label = "Fragment Request 3",shape = box ];
37
+ "serving website_1_0" -> "serving website_1_1";
38
+ "serving website_1_1" -> "serving website_1_2";
39
+ "serving website_1_2" -> "serving website_1_3";
40
+ "serving website_1_3" -> "serving website_1_0";
41
+ };
42
+ "serving website_1" [ label = "looper user #1" ];
43
+ "serving website_1_0";
44
+ "serving website_1" -> "serving website_1_0";
45
+ };
46
+ subgraph "serving website_2_looper"
47
+ {
48
+ label = "looper user 2";
49
+ subgraph "requests_2"
50
+ {
51
+ label = "requests 2";
52
+ node [ style = filled, color = lightgray ];
53
+ "serving website_2_0" [ label = "Fragment Request 0",shape = box ];
54
+ "serving website_2_1" [ label = "Fragment Request 1",shape = box ];
55
+ "serving website_2_2" [ label = "Fragment Request 2",shape = box ];
56
+ "serving website_2_3" [ label = "Fragment Request 3",shape = box ];
57
+ "serving website_2_0" -> "serving website_2_1";
58
+ "serving website_2_1" -> "serving website_2_2";
59
+ "serving website_2_2" -> "serving website_2_3";
60
+ "serving website_2_3" -> "serving website_2_0";
61
+ };
62
+ "serving website_2" [ label = "looper user #2" ];
63
+ "serving website_2_0";
64
+ "serving website_2" -> "serving website_2_0";
65
+ };
66
+ subgraph "serving website_3_looper"
67
+ {
68
+ label = "looper user 3";
69
+ subgraph "requests_3"
70
+ {
71
+ label = "requests 3";
72
+ node [ style = filled, color = lightgray ];
73
+ "serving website_3_0" [ label = "Fragment Request 0",shape = box ];
74
+ "serving website_3_1" [ label = "Fragment Request 1",shape = box ];
75
+ "serving website_3_2" [ label = "Fragment Request 2",shape = box ];
76
+ "serving website_3_3" [ label = "Fragment Request 3",shape = box ];
77
+ "serving website_3_0" -> "serving website_3_1";
78
+ "serving website_3_1" -> "serving website_3_2";
79
+ "serving website_3_2" -> "serving website_3_3";
80
+ "serving website_3_3" -> "serving website_3_0";
81
+ };
82
+ "serving website_3" [ label = "looper user #3" ];
83
+ "serving website_3_0";
84
+ "serving website_3" -> "serving website_3_0";
85
+ };
86
+ subgraph "serving website_4_looper"
87
+ {
88
+ label = "looper user 4";
89
+ subgraph "requests_4"
90
+ {
91
+ label = "requests 4";
92
+ node [ style = filled, color = lightgray ];
93
+ "serving website_4_0" [ label = "Fragment Request 0",shape = box ];
94
+ "serving website_4_1" [ label = "Fragment Request 1",shape = box ];
95
+ "serving website_4_2" [ label = "Fragment Request 2",shape = box ];
96
+ "serving website_4_3" [ label = "Fragment Request 3",shape = box ];
97
+ "serving website_4_0" -> "serving website_4_1";
98
+ "serving website_4_1" -> "serving website_4_2";
99
+ "serving website_4_2" -> "serving website_4_3";
100
+ "serving website_4_3" -> "serving website_4_0";
101
+ };
102
+ "serving website_4" [ label = "looper user #4" ];
103
+ "serving website_4_0";
104
+ "serving website_4" -> "serving website_4_0";
105
+ };
106
+ "benchmark 'serving website'";
107
+ "serving website_0";
108
+ "serving website_1";
109
+ "serving website_2";
110
+ "serving website_3";
111
+ "serving website_4";
112
+ "benchmark 'serving website'" -> "serving website_0";
113
+ "benchmark 'serving website'" -> "serving website_1";
114
+ "benchmark 'serving website'" -> "serving website_2";
115
+ "benchmark 'serving website'" -> "serving website_3";
116
+ "benchmark 'serving website'" -> "serving website_4";
117
+ };
118
+ subgraph "benchmark_creating a post"
119
+ {
120
+ label = "benchmark 'creating a post'";
121
+ subgraph "creating a post_0_looper"
122
+ {
123
+ label = "looper user 0";
124
+ subgraph "requests_0"
125
+ {
126
+ label = "requests 0";
127
+ node [ style = filled, color = lightgray ];
128
+ "creating a post_0_0" [ label = "Fragment Request 0",shape = box ];
129
+ "creating a post_0_1" [ label = "Fragment Request 1",shape = box ];
130
+ "creating a post_0_2" [ label = "Fragment Request 2",shape = box ];
131
+ "creating a post_0_3" [ label = "Fragment Request 3",shape = box ];
132
+ "creating a post_0_0" -> "creating a post_0_1";
133
+ "creating a post_0_1" -> "creating a post_0_2";
134
+ "creating a post_0_2" -> "creating a post_0_3";
135
+ "creating a post_0_3" -> "creating a post_0_0";
136
+ };
137
+ "creating a post_0" [ label = "looper user #0" ];
138
+ "creating a post_0_0";
139
+ "creating a post_0" -> "creating a post_0_0";
140
+ };
141
+ subgraph "creating a post_1_looper"
142
+ {
143
+ label = "looper user 1";
144
+ subgraph "requests_1"
145
+ {
146
+ label = "requests 1";
147
+ node [ style = filled, color = lightgray ];
148
+ "creating a post_1_0" [ label = "Fragment Request 0",shape = box ];
149
+ "creating a post_1_1" [ label = "Fragment Request 1",shape = box ];
150
+ "creating a post_1_2" [ label = "Fragment Request 2",shape = box ];
151
+ "creating a post_1_3" [ label = "Fragment Request 3",shape = box ];
152
+ "creating a post_1_0" -> "creating a post_1_1";
153
+ "creating a post_1_1" -> "creating a post_1_2";
154
+ "creating a post_1_2" -> "creating a post_1_3";
155
+ "creating a post_1_3" -> "creating a post_1_0";
156
+ };
157
+ "creating a post_1" [ label = "looper user #1" ];
158
+ "creating a post_1_0";
159
+ "creating a post_1" -> "creating a post_1_0";
160
+ };
161
+ subgraph "creating a post_2_looper"
162
+ {
163
+ label = "looper user 2";
164
+ subgraph "requests_2"
165
+ {
166
+ label = "requests 2";
167
+ node [ style = filled, color = lightgray ];
168
+ "creating a post_2_0" [ label = "Fragment Request 0",shape = box ];
169
+ "creating a post_2_1" [ label = "Fragment Request 1",shape = box ];
170
+ "creating a post_2_2" [ label = "Fragment Request 2",shape = box ];
171
+ "creating a post_2_3" [ label = "Fragment Request 3",shape = box ];
172
+ "creating a post_2_0" -> "creating a post_2_1";
173
+ "creating a post_2_1" -> "creating a post_2_2";
174
+ "creating a post_2_2" -> "creating a post_2_3";
175
+ "creating a post_2_3" -> "creating a post_2_0";
176
+ };
177
+ "creating a post_2" [ label = "looper user #2" ];
178
+ "creating a post_2_0";
179
+ "creating a post_2" -> "creating a post_2_0";
180
+ };
181
+ subgraph "creating a post_3_looper"
182
+ {
183
+ label = "looper user 3";
184
+ subgraph "requests_3"
185
+ {
186
+ label = "requests 3";
187
+ node [ style = filled, color = lightgray ];
188
+ "creating a post_3_0" [ label = "Fragment Request 0",shape = box ];
189
+ "creating a post_3_1" [ label = "Fragment Request 1",shape = box ];
190
+ "creating a post_3_2" [ label = "Fragment Request 2",shape = box ];
191
+ "creating a post_3_3" [ label = "Fragment Request 3",shape = box ];
192
+ "creating a post_3_0" -> "creating a post_3_1";
193
+ "creating a post_3_1" -> "creating a post_3_2";
194
+ "creating a post_3_2" -> "creating a post_3_3";
195
+ "creating a post_3_3" -> "creating a post_3_0";
196
+ };
197
+ "creating a post_3" [ label = "looper user #3" ];
198
+ "creating a post_3_0";
199
+ "creating a post_3" -> "creating a post_3_0";
200
+ };
201
+ subgraph "creating a post_4_looper"
202
+ {
203
+ label = "looper user 4";
204
+ subgraph "requests_4"
205
+ {
206
+ label = "requests 4";
207
+ node [ style = filled, color = lightgray ];
208
+ "creating a post_4_0" [ label = "Fragment Request 0",shape = box ];
209
+ "creating a post_4_1" [ label = "Fragment Request 1",shape = box ];
210
+ "creating a post_4_2" [ label = "Fragment Request 2",shape = box ];
211
+ "creating a post_4_3" [ label = "Fragment Request 3",shape = box ];
212
+ "creating a post_4_0" -> "creating a post_4_1";
213
+ "creating a post_4_1" -> "creating a post_4_2";
214
+ "creating a post_4_2" -> "creating a post_4_3";
215
+ "creating a post_4_3" -> "creating a post_4_0";
216
+ };
217
+ "creating a post_4" [ label = "looper user #4" ];
218
+ "creating a post_4_0";
219
+ "creating a post_4" -> "creating a post_4_0";
220
+ };
221
+ "benchmark 'creating a post'";
222
+ "creating a post_0";
223
+ "creating a post_1";
224
+ "creating a post_2";
225
+ "creating a post_3";
226
+ "creating a post_4";
227
+ "benchmark 'creating a post'" -> "creating a post_0";
228
+ "benchmark 'creating a post'" -> "creating a post_1";
229
+ "benchmark 'creating a post'" -> "creating a post_2";
230
+ "benchmark 'creating a post'" -> "creating a post_3";
231
+ "benchmark 'creating a post'" -> "creating a post_4";
232
+ };
233
+ "EventMachine.run" -> "benchmark 'serving website'";
234
+ "EventMachine.run" -> "benchmark 'creating a post'";
235
+ }