autobench 0.0.1alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +16 -0
  3. data/README.md +123 -0
  4. data/bin/autobench +180 -0
  5. data/bin/autobench-config +162 -0
  6. data/lib/autobench.rb +28 -0
  7. data/lib/autobench/client.rb +78 -0
  8. data/lib/autobench/common.rb +49 -0
  9. data/lib/autobench/config.rb +62 -0
  10. data/lib/autobench/render.rb +102 -0
  11. data/lib/autobench/version.rb +3 -0
  12. data/lib/autobench/yslow.rb +75 -0
  13. data/lib/phantomas/README.md +296 -0
  14. data/lib/phantomas/core/formatter.js +65 -0
  15. data/lib/phantomas/core/helper.js +64 -0
  16. data/lib/phantomas/core/modules/requestsMonitor/requestsMonitor.js +214 -0
  17. data/lib/phantomas/core/pads.js +16 -0
  18. data/lib/phantomas/core/phantomas.js +418 -0
  19. data/lib/phantomas/lib/args.js +27 -0
  20. data/lib/phantomas/lib/modules/_coffee-script.js +2 -0
  21. data/lib/phantomas/lib/modules/assert.js +326 -0
  22. data/lib/phantomas/lib/modules/events.js +216 -0
  23. data/lib/phantomas/lib/modules/http.js +55 -0
  24. data/lib/phantomas/lib/modules/path.js +441 -0
  25. data/lib/phantomas/lib/modules/punycode.js +510 -0
  26. data/lib/phantomas/lib/modules/querystring.js +214 -0
  27. data/lib/phantomas/lib/modules/tty.js +7 -0
  28. data/lib/phantomas/lib/modules/url.js +625 -0
  29. data/lib/phantomas/lib/modules/util.js +520 -0
  30. data/lib/phantomas/modules/ajaxRequests/ajaxRequests.js +15 -0
  31. data/lib/phantomas/modules/assetsTypes/assetsTypes.js +21 -0
  32. data/lib/phantomas/modules/cacheHits/cacheHits.js +28 -0
  33. data/lib/phantomas/modules/caching/caching.js +66 -0
  34. data/lib/phantomas/modules/cookies/cookies.js +54 -0
  35. data/lib/phantomas/modules/domComplexity/domComplexity.js +130 -0
  36. data/lib/phantomas/modules/domQueries/domQueries.js +148 -0
  37. data/lib/phantomas/modules/domains/domains.js +49 -0
  38. data/lib/phantomas/modules/globalVariables/globalVariables.js +44 -0
  39. data/lib/phantomas/modules/headers/headers.js +48 -0
  40. data/lib/phantomas/modules/localStorage/localStorage.js +14 -0
  41. data/lib/phantomas/modules/requestsStats/requestsStats.js +71 -0
  42. data/lib/phantomas/modules/staticAssets/staticAssets.js +40 -0
  43. data/lib/phantomas/modules/waterfall/waterfall.js +62 -0
  44. data/lib/phantomas/modules/windowPerformance/windowPerformance.js +36 -0
  45. data/lib/phantomas/package.json +27 -0
  46. data/lib/phantomas/phantomas.js +35 -0
  47. data/lib/phantomas/run-multiple.js +177 -0
  48. data/lib/yslow.js +5 -0
  49. metadata +135 -0
data/lib/autobench.rb ADDED
@@ -0,0 +1,28 @@
1
+ require 'autobench/common'
2
+ require 'autobench/config'
3
+ require 'autobench/render'
4
+ require 'autobench/yslow'
5
+ require 'autobench/client'
6
+
7
+ class Autobench
8
+ attr_accessor :config
9
+
10
+ LIB_DIR ||= File.dirname(__FILE__)
11
+ def initialize config, overides={}
12
+ @config = Autobench::Config.new(config, overides)
13
+ end
14
+
15
+ def render
16
+ @render ||= Autobench::Render.new(@config)
17
+ end
18
+
19
+ def yslow
20
+ @yslow ||= Autobench::YSlow.new(@config)
21
+ end
22
+
23
+ def client
24
+ @client ||= Autobench::Client.new(@config)
25
+ end
26
+ end
27
+
28
+ # vim: ft=ruby:
@@ -0,0 +1,78 @@
1
+ class Autobench
2
+ class Client
3
+ include Common
4
+ def initialize config
5
+ @config = config
6
+ @thresholds = @config["thresholds"]["client"] rescue []
7
+ @full_results = []
8
+ @failures = []
9
+ @successes = []
10
+ end
11
+
12
+ def benchmark
13
+ begin
14
+ @full_results = JSON.parse(%x{#{command}}.strip)
15
+ @thresholds.each do |key,threshold|
16
+ if fetch(key) > threshold
17
+ @failures.push("#{key} is #{fetch(key)}, threshold is #{threshold}")
18
+ else
19
+ @successes.push("#{key} is #{fetch(key)}, threshold is #{threshold}")
20
+ end
21
+ end
22
+ @full_results
23
+ rescue
24
+ puts "COMMAND FAILED: #{command}"
25
+ raise
26
+ end
27
+ end
28
+
29
+ def [](key)
30
+ return fetch(key)
31
+ end
32
+
33
+ def fetch(key)
34
+ return median(raw_results.map {|i| i[key] })
35
+ end
36
+
37
+ # backdoor hook to @full_results
38
+ def raw_results
39
+ raise "missing benchmarks" unless @full_results
40
+ @full_results
41
+ end
42
+
43
+ # generate result set that is only medians by default
44
+ def full_results
45
+ r = {}
46
+ raw_results.first.keys.each do |key|
47
+ r[key] = fetch(key)
48
+ end
49
+ return r
50
+ end
51
+
52
+ private
53
+ def command
54
+ "cd #{@config.phantomas} && #{@config.node} ./run-multiple.js #{modules} --url=#{url} --runs=#{@config["runs"]} --format=json"
55
+ end
56
+
57
+ def url
58
+ "http://#{@config['server']}#{(@config['port'] == 80 ? "" : ":#{@config['port']}")}#{@config['uri']}"
59
+ end
60
+
61
+ def modules
62
+ mod_str = ""
63
+ if @config.has_key?("phantomas") && @config["phantomas"].has_key?("modules")
64
+ mod_str << "--modules="+@config["phantomas"]["modules"].join(",")
65
+ end
66
+ return mod_str
67
+ end
68
+
69
+ def median(array)
70
+ sorted = array.sort
71
+ len = sorted.length
72
+ return (sorted[(len - 1) / 2] + sorted[len / 2]) / 2.0
73
+ end
74
+ end
75
+ end
76
+
77
+ # vim: ft=ruby:
78
+
@@ -0,0 +1,49 @@
1
+ class Autobench
2
+ module Common
3
+ def [](key)
4
+ full_results[key.to_sym]
5
+ end
6
+
7
+ def clean_keys results, ignored
8
+ raise "missing benchmarks" unless @full_results
9
+ results.each_key do |key|
10
+ results.delete(key) if ignored.include?(key)
11
+ end
12
+ return results
13
+ end
14
+
15
+ def failures
16
+ return "none" if passed?
17
+ out = ""
18
+ @failures.each_with_index do |f,i|
19
+ out << "[#{i+1}] #{f}\n"
20
+ end
21
+ return out
22
+ end
23
+
24
+ def successes
25
+ raise "missing benchmarks" unless @full_results
26
+ return "none" if @successes.empty?
27
+ out = ""
28
+ @successes.each_with_index do |f,i|
29
+ out << "[#{i+1}] #{f}\n"
30
+ end
31
+ return out
32
+ end
33
+
34
+ def passed?
35
+ raise "missing benchmarks" unless @full_results
36
+ return @failures.empty?
37
+ end
38
+
39
+ def failed?
40
+ !passed?
41
+ end
42
+
43
+ def thresholds?
44
+ return !@thresholds.empty?
45
+ end
46
+
47
+ end
48
+ end
49
+
@@ -0,0 +1,62 @@
1
+ require "yaml"
2
+ require "json"
3
+
4
+ class Autobench
5
+ LIB_DIR ||= File.expand_path('..', File.dirname(__FILE__))
6
+ class Config
7
+ attr_accessor :basedir
8
+ def initialize config, overides={}
9
+ @config = if config.is_a?(String)
10
+ YAML.load_file(config).merge(overides)
11
+ elsif config.is_a?(Hash)
12
+ config.merge(overides)
13
+ else
14
+ raise "invalid config"
15
+ end
16
+ end
17
+
18
+ def phantomas
19
+ default = File.join(::Autobench::LIB_DIR, "phantomas")
20
+ begin
21
+ return default if @config["paths"]["phantomas"].nil?
22
+ return @config["paths"]["phantomas"]
23
+ rescue NoMethodError
24
+ return default
25
+ end
26
+ end
27
+
28
+ def yslow
29
+ default = ::Autobench::LIB_DIR
30
+ begin
31
+ return default if @config["paths"]["yslow"].nil?
32
+ return @config["paths"]["yslow"]
33
+ rescue NoMethodError
34
+ return default
35
+ end
36
+ end
37
+
38
+ %w{ httperf node phantomjs }.each do |bin|
39
+ define_method(bin) do
40
+ return @config["paths"][bin] rescue bin
41
+ end
42
+ end
43
+ #def httperf
44
+ #return @config["paths"]["httperf"] rescue "httperf"
45
+ #end
46
+
47
+ #def node
48
+ #return @config["paths"]["node"] rescue "node"
49
+ #end
50
+
51
+ #def phantomjs
52
+ #return @config["paths"]["phantomjs"] rescue "phantomjs"
53
+ #end
54
+
55
+
56
+ def method_missing(meth, *args, &block)
57
+ @config.send(meth.to_sym, *args, &block) rescue super
58
+ end
59
+ end
60
+ end
61
+
62
+ # vim: ft=ruby:
@@ -0,0 +1,102 @@
1
+ require 'httperf'
2
+ class Autobench
3
+ LIB_DIR ||= File.expand_path('..', File.dirname(__FILE__))
4
+ class Render
5
+ include Common
6
+ def initialize config
7
+ @config = config
8
+ @thresholds = config["thresholds"]["render"] rescue []
9
+ @failures = []
10
+ @successes = []
11
+ setup_httperf_configuration(config)
12
+ end
13
+
14
+ def benchmark
15
+ httperf = HTTPerf.new(@httperf_config, @config.httperf)
16
+ httperf.parse = true
17
+
18
+ @full_results = httperf.run.inject({}){|memo,(k,v)| memo[k.to_s] = v; memo}
19
+ # keys: sym -> str
20
+
21
+ @thresholds.each do |key,threshold|
22
+ if higher_is_better.include?(key)
23
+ if (full_results[key].to_f < threshold.to_f)
24
+ @failures.push("#{key} is #{full_results[key].to_f}, threshold is #{threshold.to_f}")
25
+ else
26
+ @successes.push("#{key} is #{full_results[key].to_f}, threshold is #{threshold.to_f}")
27
+ end
28
+ else
29
+ if (full_results[key].to_f > threshold.to_f)
30
+ @failures.push("#{key} is #{full_results[key].to_f}, threshold is #{threshold.to_f}")
31
+ else
32
+ @successes.push("#{key} is #{full_results[key].to_f}, threshold is #{threshold.to_f}")
33
+ end
34
+ end
35
+ end
36
+
37
+ ignored_keys.each do |key|
38
+ @full_results.delete(key)
39
+ end
40
+
41
+ @full_results
42
+ end
43
+
44
+ def full_results
45
+ return clean_keys(@full_results, %w[ command connection_times ])
46
+ end
47
+
48
+ private
49
+ def setup_httperf_configuration config
50
+ @httperf_config = {} # defaults
51
+
52
+ if config.has_key?("httperf")
53
+ puts config["httperf"]
54
+ @httperf_config.merge!(config["httperf"])
55
+ end
56
+
57
+ # all required
58
+ %w{ server port uri }.each do |key|
59
+ raise "Autobench::Render missing `#{key}`." unless config.has_key?(key)
60
+ @httperf_config[key] = config[key]
61
+ end
62
+
63
+ if config.has_key?("runs")
64
+ @httperf_config["num-conns"] = config["runs"]
65
+ end
66
+
67
+ @httperf_config.merge!(httperf_forced_options)
68
+ end
69
+
70
+ def httperf_forced_options
71
+ { "verbose" => true }
72
+ end
73
+
74
+ def higher_is_better
75
+ %w[
76
+ connection_rate_per_sec
77
+ request_rate_per_sec
78
+ reply_status_2xx
79
+ total_connections
80
+ total_requests
81
+ total_replies
82
+ ]
83
+ end
84
+ def ignored_keys
85
+ %w[
86
+ max_connect_burst_length
87
+ cpu_time_system_pct
88
+ cpu_time_total_pct
89
+ cpu_time_user_sec
90
+ cpu_time_system_sec
91
+ cpu_time_user_pct
92
+ reply_rate_min
93
+ reply_rate_avg
94
+ reply_rate_max
95
+ reply_rate_stddev
96
+ reply_rate_samples
97
+ connection_length
98
+ ]
99
+ end
100
+ end
101
+ end
102
+ # vim: ft=ruby:
@@ -0,0 +1,3 @@
1
+ class Autobench
2
+ VERSION = '0.0.1alpha1'
3
+ end
@@ -0,0 +1,75 @@
1
+ require 'json'
2
+ class Autobench
3
+ LIB_DIR ||= File.expand_path('..', File.dirname(__FILE__))
4
+ class YSlow
5
+ include Common
6
+ def initialize config
7
+ @config = config
8
+ @thresholds = config["thresholds"]["yslow"] rescue []
9
+ @failures = []
10
+ @successes = []
11
+ end
12
+
13
+ def benchmark
14
+ begin
15
+ @full_results = JSON.parse(%x{#{command}}.strip)
16
+ rescue
17
+ raise "Error running: #{command}"
18
+ end
19
+ @thresholds.each do |key,threshold|
20
+ # U-G-L-Y
21
+ if key == "overall"
22
+ if full_results[mappings[key]].to_i < threshold.to_i
23
+ @failures.push("#{key} is #{full_results[mappings[key]]}, threshold is #{threshold}");
24
+ else
25
+ @successes.push("#{key} is #{full_results[mappings[key]]}, threshold is #{threshold}");
26
+ end
27
+ else
28
+ if full_results[mappings[key]].to_i > threshold.to_i
29
+ @failures.push("#{key} is #{full_results[mappings[key]]}, threshold is #{threshold}");
30
+ else
31
+ @successes.push("#{key} is #{full_results[mappings[key]]}, threshold is #{threshold}");
32
+ end
33
+ end
34
+ end
35
+ @full_results
36
+ end
37
+
38
+ def [](key)
39
+ return full_results[mappings[key]] if mappings.keys.include?(key)
40
+ return full_results[key] if mappings.values.include?(key)
41
+ return nil
42
+ end
43
+
44
+ def full_results
45
+ return clean_keys(@full_results, ['u','i'])
46
+ end
47
+
48
+ def mappings
49
+ {
50
+ "overall" => "o",
51
+ "loadtime" => "lt",
52
+ "requests" => "r",
53
+ "size" => "w"
54
+ }
55
+ end
56
+
57
+ private
58
+ def command
59
+ "cd #{@config.yslow} && #{@config.phantomjs} ./yslow.js --info basic #{options} http://#{@config['server']}#{(@config.has_key?("port") ? ":#{@config['port']}" : "")}#{@config['uri']}"
60
+ end
61
+
62
+ def options
63
+ return "" unless @config.has_key?("yslow")
64
+
65
+ ret = []
66
+ %w{ ruleset ua headers viewport }.each do |key|
67
+ ret.push "--#{key} #{@config["yslow"][key]}" if @config["yslow"].has_key?(key)
68
+ end
69
+
70
+ return ret.join(" ")
71
+ end
72
+ end
73
+ end
74
+
75
+ # vim: ft=ruby:
@@ -0,0 +1,296 @@
1
+ phantomas
2
+ =========
3
+
4
+ ![GitHub Logo](http://upload.wikimedia.org/wikipedia/en/a/a5/Fantomas.jpg)
5
+
6
+ PhantomJS-based modular web performance metrics collector.
7
+
8
+ And why phantomas? Well, [because](http://en.wikipedia.org/wiki/Fantômas) :)
9
+
10
+ ## Requirements
11
+
12
+ * [PhantomJS 1.7+](http://phantomjs.org/)
13
+ * [NodeJS](http://nodejs.org) (for `run-multiple.js` script)
14
+
15
+ ## Installation
16
+
17
+ ```
18
+ npm install phantomas
19
+ ```
20
+
21
+ ## Dependencies
22
+
23
+ phantomas uses the following 3rd party libraries (located in `/lib` directory):
24
+
25
+ * CommonJS modules from [phantomjs-nodify](https://github.com/jgonera/phantomjs-nodify) and nodejs source
26
+
27
+ ## Let's make Web a bit faster!
28
+
29
+ * [Best Practices for Speeding Up Your Web Site](http://developer.yahoo.com/performance/rules.html) (by Yahoo!)
30
+ * [Web Performance Best Practices](https://developers.google.com/speed/docs/best-practices/rules_intro) (by Google)
31
+
32
+ ## Contributors
33
+
34
+ * [macbre](https://github.com/macbre)
35
+ * [jmosney](https://github.com/jmosney)
36
+ * All the [contributors](https://github.com/macbre/phantomas/graphs/contributors)
37
+
38
+ ## Usage
39
+
40
+ ### Single run
41
+
42
+ ``` bash
43
+ ./phantomas.js --url=https://github.com/macbre/phantomas --verbose
44
+ ```
45
+
46
+ #### Parameters
47
+
48
+ * `--url` URL of the page to generate metrics for (required)
49
+ * `--format=[json|csv|plain]` output format (``plain`` is the default one)
50
+ * `--timeout=[seconds]` timeout for phantomas run (defaults to 15 seconds)
51
+ * `--viewport=[width]x[height]` phantomJS viewport dimensions (1280x1024 is the default)
52
+ * `--verbose` writes debug messages to the console
53
+ * `--silent` don't write anything to the console
54
+ * `--modules=[moduleOne],[moduleTwo]` run only selected modules
55
+ * `--user-agent='Custom user agent'` provide a custom user agent (will default to something similar to ``phantomas/0.4 (PhantomJS/1.7.0; 64bit)``)
56
+
57
+ ### Multiple runs
58
+
59
+ This helper script requires NodeJS.
60
+
61
+ ``` bash
62
+ ./run-multiple.js --url=https://github.com/macbre/phantomas --runs=5
63
+ ```
64
+
65
+ #### Parameters
66
+
67
+ * `--url` URL of the page to generate metrics for (required)
68
+ * `--runs` number of runs to perform (defaults to 3)
69
+ * `--modules=[moduleOne],[moduleTwo]` run only selected modules
70
+
71
+ ## Features
72
+
73
+ * Modular approach - each metric is generated by a separate "module"
74
+ * phantomas "core" acts as an [events emitter](https://github.com/macbre/phantomas/wiki/Events) that each module can hook into
75
+ * JSON and CSV as available output formats for easy integration with automated reporting / monitoring tools
76
+
77
+ ## Metrics
78
+
79
+ _Current number of metrics: 64_
80
+
81
+ Units:
82
+
83
+ * ms for time
84
+ * bytes for size
85
+
86
+ ```
87
+ ./phantomas.js --url=https://github.com/macbre/phantomas
88
+
89
+ phantomas metrics for <https://github.com/macbre/phantomas>:
90
+
91
+ * requests: 22
92
+ * gzipRequests: 9
93
+ * postRequests: 0
94
+ * redirects: 0
95
+ * notFound: 0
96
+ * timeToFirstByte: 503
97
+ * timeToLastByte: 520
98
+ * bodySize: 675125
99
+ * contentLength: 708206
100
+ * ajaxRequests: 0
101
+ * htmlCount: 1
102
+ * htmlSize: 50728
103
+ * cssCount: 2
104
+ * cssSize: 174949
105
+ * jsCount: 4
106
+ * jsSize: 322932
107
+ * imageCount: 12
108
+ * imageSize: 49287
109
+ * base64Count: 0
110
+ * base64Size: 0
111
+ * otherCount: 3
112
+ * otherSize: 77229
113
+ * cacheHits: 0
114
+ * cacheMisses: 0
115
+ * cachingNotSpecified: 3
116
+ * cachingTooShort: 2
117
+ * cachingDisabled: 0
118
+ * headersCount: 265
119
+ * headersSentCount: 65
120
+ * headersRecvCount: 200
121
+ * headersSize: 10205
122
+ * headersSentSize: 3850
123
+ * headersRecvSize: 6355
124
+ * assetsNotGzipped: 0
125
+ * assetsWithQueryString: 9
126
+ * smallImages: 2
127
+ * httpTrafficCompleted: 2460
128
+ * domains: 5
129
+ * DOMqueries: 39
130
+ * DOMinserts: 19
131
+ * jQuerySelectors: 0
132
+ * jQueryOnDOMReadyFunctions: 0
133
+ * cookiesSent: 0
134
+ * cookiesRecv: 268
135
+ * domainsWithCookies: 1
136
+ * documentCookiesLength: 387
137
+ * documentCookiesCount: 12
138
+ * bodyHTMLSize: 47769
139
+ * commentsSize: 452
140
+ * hiddenContentSize: 15635
141
+ * whiteSpacesSize: 2378
142
+ * DOMelementsCount: 554
143
+ * DOMelementMaxDepth: 13
144
+ * iframesCount: 0
145
+ * nodesWithInlineCSS: 5
146
+ * imagesWithoutDimensions: 3
147
+ * globalVariables: 18
148
+ * localStorageEntries: 0
149
+ * smallestResponse: 35
150
+ * biggestResponse: 239453
151
+ * fastestResponse: 43
152
+ * slowestResponse: 984
153
+ * medianResponse: 130.5
154
+ * onDOMReadyTime: 482
155
+ * windowOnLoadTime: 1716
156
+ ```
157
+
158
+ ### Requests monitor (core module)
159
+
160
+ * requests: total number of HTTP requests made
161
+ * gzipRequests: number of gzipped HTTP responses
162
+ * postRequests: number of POST requests
163
+ * redirects: number of HTTP redirects (either 301 or 302)
164
+ * notFound: number of HTTP 404 responses
165
+ * timeToFirstByte: time it took to receive the first byte of the first response
166
+ * timeToLastByte: time it took to receive the last byte of the first response
167
+ * bodySize: size of the content of all responses
168
+ * contentLength: size of the content of all responses (based on ``Content-Length`` header)
169
+ * httpTrafficCompleted: time it took to receive the last byte of the last HTTP response
170
+
171
+ ### AJAX requests
172
+
173
+ * ajaxRequests: number of AJAX requests
174
+
175
+ ### Assets types
176
+
177
+ * htmlCount: number of html responses
178
+ * htmlSize: size of html responses
179
+ * cssCount: number of css responses
180
+ * cssSize: size of css responses
181
+ * jsCount: number of js responses
182
+ * jsSize: size of js responses
183
+ * imageCount: number of image responses
184
+ * imageSize: size of image responses
185
+ * base64Count: number of base64 encoded "responses" (no HTTP request was made)
186
+ * base64Size: size of base64 encoded "responses"
187
+ * otherCount: number of other responses
188
+ * otherSize: size of other responses
189
+
190
+ ### Cache Hits
191
+
192
+ _Metrics are calculated based on ``X-Cache`` header added by Varnish / Squid servers._
193
+
194
+ * cacheHits: number of cache hits
195
+ * cacheMisses: number of cache misses
196
+
197
+ ### Headers
198
+
199
+ * headersCount: number of requests and responses headers
200
+ * headersSentCount: number of headers sent in requests
201
+ * headersRecvCount: number of headers received in responses
202
+ * headersSize: size of all headers
203
+ * headersSentSize: size of sent headers
204
+ * headersRecvSize: size of received headers
205
+
206
+ ### Domains
207
+
208
+ * domains: number of domains used to fetch the page
209
+
210
+ ### Cookies
211
+
212
+ * cookiesSent: length of cookies sent in HTTP requests
213
+ * cookiesRecv: length of cookies received in HTTP responses
214
+ * domainsWithCookies: number of domains with cookies set
215
+ * documentCookiesLength: length of `document.cookie`
216
+ * documentCookiesCount: number of cookies in `document.cookie`
217
+
218
+ ### DOM complexity
219
+
220
+ * globalVariables: number of JS globals variables
221
+ * bodyHTMLSize: the size of body tag content
222
+ * commentsSize: the size of HTML comments on the page
223
+ * hiddenContentSize: the size of content of hidden elements on the page (with CSS ``display: none``)
224
+ * whiteSpacesSize: the size of text nodes with whitespaces only
225
+ * DOMelementsCount: total number of HTML element nodes
226
+ * DOMelementMaxDepth: maximum level on nesting of HTML element node
227
+ * iframesCount: number of iframe nodes
228
+ * nodesWithInlineCSS: number of nodes with inline CSS styling (with `style` attribute)
229
+ * imagesWithoutDimensions: number of ``<img>`` nodes without both ``width`` and ``height`` attribute
230
+
231
+ ### DOM queries
232
+
233
+ * DOMqueries: number of `document.getElementById` and `document.getElementsByClassName` calls
234
+ * DOMinserts: number of DOM nodes inserts
235
+ * jQuerySelectors: number of jQuery selectors calls (e.g. `$('#foo > .bar')`)
236
+ * jQueryOnDOMReadyFunctions: number of functions bound to onDOMready event
237
+
238
+ ### Window performance
239
+
240
+ * onDOMReadyTime: time it took to fire onDOMready event
241
+ * windowOnLoadTime: time it took to fire window.load event
242
+
243
+ ### Requests statistics
244
+
245
+ * smallestResponse: the size of the smallest response
246
+ * biggestResponse: the size of the biggest response
247
+ * fastestResponse: the time to the last byte of the fastest response
248
+ * slowestResponse: the time to the last byte of the slowest response
249
+ * medianResponse: median value of time to the last byte for all responses
250
+
251
+ ### localStorage
252
+
253
+ * localStorageEntries: number of entries in local storage
254
+
255
+ ### Static assets
256
+
257
+ * assetsNotGzipped: static assets that were not gzipped
258
+ * assetsWithQueryString: static assets requested with query string (e.g. ?foo) in URL
259
+ * smallImages: images smaller than 2 kB that can be base64 encoded
260
+
261
+ ### Caching
262
+
263
+ * cachingNotSpecified: responses with no caching header sent (either `Cache-Control` or `Expires`)
264
+ * cachingTooShort: responses with too short (less than a week) caching time
265
+ * cachingDisabled: responses with caching disabled (`max-age=0`)
266
+
267
+ ## Notices
268
+
269
+ phantomas apart from "raw" metrics data, when in `--verbose` mode, emits notices with more in-depth data:
270
+
271
+ ```
272
+ > Caching period is less than a week for <https://ssl.google-analytics.com/ga.js> (set to 43200 s)
273
+ > No caching specified for <https://secure.gaug.es/track.js>
274
+ > Caching period is less than a week for <https://secure.gravatar.com/avatar/57548e3255bfa0e74afff98289dae839?s=140&d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png> (set to 300 s)
275
+ > https://secure.gravatar.com/avatar/57548e3255bfa0e74afff98289dae839?s=140&d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png (IMAGE) served with query string
276
+ > Requests per domain:
277
+ > github.com: 1 request(s)
278
+ > a248.e.akamai.net: 16 request(s)
279
+ > ssl.google-analytics.com: 2 request(s)
280
+ > secure.gaug.es: 2 request(s)
281
+ > secure.gravatar.com: 1 request(s)
282
+ >
283
+ > JavaScript globals (18): html5, Modernizr, moment, $, jQuery, $stats, jQuery18302483161953277886, GitHub, DateInput, clippyCopiedCallback, debug, _gaq, _gauges, CommandBar, stringDistance, fuzzyScore, _gat, gaGlobal
284
+ >
285
+ > The smallest response (0.03 kB): https://ssl.google-analytics.com/__utm.gif?utmwv=5.3.8&utms=1&utmn=396347331&utmhn=github.com&utmcs=UTF-8&utmsr=1024x768&utmvp=1024x1280&utmsc=32-bit&utmul=pl-pl&utmje=0&utmfl=-&utmdt=macbre%2Fphantomas%20%C2%B7%20GitHub&utmhid=1963809109&utmr=-&utmp=%2Fmacbre%2Fphantomas&utmac=UA-3769691-2&utmcc=__utma%3D1.1523233271.1353260190.1353260190.1353260190.1%3B%2B__utmz%3D1.1353260190.1.1.utmcsr%3D(direct)%7Cutmccn%3D(direct)%7Cutmcmd%3D(none)%3B&utmu=qB~
286
+ > The biggest response (233.84 kB): https://a248.e.akamai.net/assets.github.com/assets/github-81433815e4751f68e04d42ec948cba14ab028c2d.js
287
+ >
288
+ > The fastest response (43 ms): https://a248.e.akamai.net/assets.github.com/images/modules/header/logov7@4x.png?1340659561
289
+ > The slowest response (984 ms): https://secure.gravatar.com/avatar/57548e3255bfa0e74afff98289dae839?s=140&d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png
290
+ ```
291
+
292
+ ## For developers
293
+
294
+ * [Project's wiki](https://github.com/macbre/phantomas/wiki)
295
+ * Description of [events fired by phantomas core](https://github.com/macbre/phantomas/wiki/Events)
296
+ * [TODO list](https://github.com/macbre/phantomas/wiki/TODO)