stackprof-webnav 0.0.1

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.
@@ -0,0 +1,410 @@
1
+ /*! normalize.css v2.1.2 | MIT License | git.io/normalize */
2
+
3
+ /* ==========================================================================
4
+ HTML5 display definitions
5
+ ========================================================================== */
6
+
7
+ /**
8
+ * Correct `block` display not defined in IE 8/9.
9
+ */
10
+
11
+ article,
12
+ aside,
13
+ details,
14
+ figcaption,
15
+ figure,
16
+ footer,
17
+ header,
18
+ hgroup,
19
+ main,
20
+ nav,
21
+ section,
22
+ summary {
23
+ display: block;
24
+ }
25
+
26
+ /**
27
+ * Correct `inline-block` display not defined in IE 8/9.
28
+ */
29
+
30
+ audio,
31
+ canvas,
32
+ video {
33
+ display: inline-block;
34
+ }
35
+
36
+ /**
37
+ * Prevent modern browsers from displaying `audio` without controls.
38
+ * Remove excess height in iOS 5 devices.
39
+ */
40
+
41
+ audio:not([controls]) {
42
+ display: none;
43
+ height: 0;
44
+ }
45
+
46
+ /**
47
+ * Address `[hidden]` styling not present in IE 8/9.
48
+ * Hide the `template` element in IE, Safari, and Firefox < 22.
49
+ */
50
+
51
+ [hidden],
52
+ template {
53
+ display: none;
54
+ }
55
+
56
+ script {
57
+ display: none !important;
58
+ }
59
+
60
+ /* ==========================================================================
61
+ Base
62
+ ========================================================================== */
63
+
64
+ /**
65
+ * 1. Set default font family to sans-serif.
66
+ * 2. Prevent iOS text size adjust after orientation change, without disabling
67
+ * user zoom.
68
+ */
69
+
70
+ html {
71
+ font-family: sans-serif; /* 1 */
72
+ -ms-text-size-adjust: 100%; /* 2 */
73
+ -webkit-text-size-adjust: 100%; /* 2 */
74
+ }
75
+
76
+ /**
77
+ * Remove default margin.
78
+ */
79
+
80
+ body {
81
+ margin: 0;
82
+ }
83
+
84
+ /* ==========================================================================
85
+ Links
86
+ ========================================================================== */
87
+
88
+ /**
89
+ * Remove the gray background color from active links in IE 10.
90
+ */
91
+
92
+ a {
93
+ background: transparent;
94
+ }
95
+
96
+ /**
97
+ * Address `outline` inconsistency between Chrome and other browsers.
98
+ */
99
+
100
+ a:focus {
101
+ outline: thin dotted;
102
+ }
103
+
104
+ /**
105
+ * Improve readability when focused and also mouse hovered in all browsers.
106
+ */
107
+
108
+ a:active,
109
+ a:hover {
110
+ outline: 0;
111
+ }
112
+
113
+ /* ==========================================================================
114
+ Typography
115
+ ========================================================================== */
116
+
117
+ /**
118
+ * Address variable `h1` font-size and margin within `section` and `article`
119
+ * contexts in Firefox 4+, Safari 5, and Chrome.
120
+ */
121
+
122
+ h1 {
123
+ font-size: 2em;
124
+ margin: 0.67em 0;
125
+ }
126
+
127
+ /**
128
+ * Address styling not present in IE 8/9, Safari 5, and Chrome.
129
+ */
130
+
131
+ abbr[title] {
132
+ border-bottom: 1px dotted;
133
+ }
134
+
135
+ /**
136
+ * Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
137
+ */
138
+
139
+ b,
140
+ strong {
141
+ font-weight: bold;
142
+ }
143
+
144
+ /**
145
+ * Address styling not present in Safari 5 and Chrome.
146
+ */
147
+
148
+ dfn {
149
+ font-style: italic;
150
+ }
151
+
152
+ /**
153
+ * Address differences between Firefox and other browsers.
154
+ */
155
+
156
+ hr {
157
+ -moz-box-sizing: content-box;
158
+ box-sizing: content-box;
159
+ height: 0;
160
+ }
161
+
162
+ /**
163
+ * Address styling not present in IE 8/9.
164
+ */
165
+
166
+ mark {
167
+ background: #ff0;
168
+ color: #000;
169
+ }
170
+
171
+ /**
172
+ * Correct font family set oddly in Safari 5 and Chrome.
173
+ */
174
+
175
+ code,
176
+ kbd,
177
+ pre,
178
+ samp {
179
+ font-family: monospace, serif;
180
+ font-size: 1em;
181
+ }
182
+
183
+ /**
184
+ * Improve readability of pre-formatted text in all browsers.
185
+ */
186
+
187
+ pre {
188
+ white-space: pre-wrap;
189
+ }
190
+
191
+ /**
192
+ * Set consistent quote types.
193
+ */
194
+
195
+ q {
196
+ quotes: "\201C" "\201D" "\2018" "\2019";
197
+ }
198
+
199
+ /**
200
+ * Address inconsistent and variable font size in all browsers.
201
+ */
202
+
203
+ small {
204
+ font-size: 80%;
205
+ }
206
+
207
+ /**
208
+ * Prevent `sub` and `sup` affecting `line-height` in all browsers.
209
+ */
210
+
211
+ sub,
212
+ sup {
213
+ font-size: 75%;
214
+ line-height: 0;
215
+ position: relative;
216
+ vertical-align: baseline;
217
+ }
218
+
219
+ sup {
220
+ top: -0.5em;
221
+ }
222
+
223
+ sub {
224
+ bottom: -0.25em;
225
+ }
226
+
227
+ /* ==========================================================================
228
+ Embedded content
229
+ ========================================================================== */
230
+
231
+ /**
232
+ * Remove border when inside `a` element in IE 8/9.
233
+ */
234
+
235
+ img {
236
+ border: 0;
237
+ }
238
+
239
+ /**
240
+ * Correct overflow displayed oddly in IE 9.
241
+ */
242
+
243
+ svg:not(:root) {
244
+ overflow: hidden;
245
+ }
246
+
247
+ /* ==========================================================================
248
+ Figures
249
+ ========================================================================== */
250
+
251
+ /**
252
+ * Address margin not present in IE 8/9 and Safari 5.
253
+ */
254
+
255
+ figure {
256
+ margin: 0;
257
+ }
258
+
259
+ /* ==========================================================================
260
+ Forms
261
+ ========================================================================== */
262
+
263
+ /**
264
+ * Define consistent border, margin, and padding.
265
+ */
266
+
267
+ fieldset {
268
+ border: 1px solid #c0c0c0;
269
+ margin: 0 2px;
270
+ padding: 0.35em 0.625em 0.75em;
271
+ }
272
+
273
+ /**
274
+ * 1. Correct `color` not being inherited in IE 8/9.
275
+ * 2. Remove padding so people aren't caught out if they zero out fieldsets.
276
+ */
277
+
278
+ legend {
279
+ border: 0; /* 1 */
280
+ padding: 0; /* 2 */
281
+ }
282
+
283
+ /**
284
+ * 1. Correct font family not being inherited in all browsers.
285
+ * 2. Correct font size not being inherited in all browsers.
286
+ * 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome.
287
+ */
288
+
289
+ button,
290
+ input,
291
+ select,
292
+ textarea {
293
+ font-family: inherit; /* 1 */
294
+ font-size: 100%; /* 2 */
295
+ margin: 0; /* 3 */
296
+ }
297
+
298
+ /**
299
+ * Address Firefox 4+ setting `line-height` on `input` using `!important` in
300
+ * the UA stylesheet.
301
+ */
302
+
303
+ button,
304
+ input {
305
+ line-height: normal;
306
+ }
307
+
308
+ /**
309
+ * Address inconsistent `text-transform` inheritance for `button` and `select`.
310
+ * All other form control elements do not inherit `text-transform` values.
311
+ * Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+.
312
+ * Correct `select` style inheritance in Firefox 4+ and Opera.
313
+ */
314
+
315
+ button,
316
+ select {
317
+ text-transform: none;
318
+ }
319
+
320
+ /**
321
+ * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
322
+ * and `video` controls.
323
+ * 2. Correct inability to style clickable `input` types in iOS.
324
+ * 3. Improve usability and consistency of cursor style between image-type
325
+ * `input` and others.
326
+ */
327
+
328
+ button,
329
+ html input[type="button"], /* 1 */
330
+ input[type="reset"],
331
+ input[type="submit"] {
332
+ -webkit-appearance: button; /* 2 */
333
+ cursor: pointer; /* 3 */
334
+ }
335
+
336
+ /**
337
+ * Re-set default cursor for disabled elements.
338
+ */
339
+
340
+ button[disabled],
341
+ html input[disabled] {
342
+ cursor: default;
343
+ }
344
+
345
+ /**
346
+ * 1. Address box sizing set to `content-box` in IE 8/9.
347
+ * 2. Remove excess padding in IE 8/9.
348
+ */
349
+
350
+ input[type="checkbox"],
351
+ input[type="radio"] {
352
+ box-sizing: border-box; /* 1 */
353
+ padding: 0; /* 2 */
354
+ }
355
+
356
+ /**
357
+ * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
358
+ * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
359
+ * (include `-moz` to future-proof).
360
+ */
361
+
362
+ input[type="search"] {
363
+ -webkit-appearance: textfield; /* 1 */
364
+ -moz-box-sizing: content-box;
365
+ -webkit-box-sizing: content-box; /* 2 */
366
+ box-sizing: content-box;
367
+ }
368
+
369
+ /**
370
+ * Remove inner padding and search cancel button in Safari 5 and Chrome
371
+ * on OS X.
372
+ */
373
+
374
+ input[type="search"]::-webkit-search-cancel-button,
375
+ input[type="search"]::-webkit-search-decoration {
376
+ -webkit-appearance: none;
377
+ }
378
+
379
+ /**
380
+ * Remove inner padding and border in Firefox 4+.
381
+ */
382
+
383
+ button::-moz-focus-inner,
384
+ input::-moz-focus-inner {
385
+ border: 0;
386
+ padding: 0;
387
+ }
388
+
389
+ /**
390
+ * 1. Remove default vertical scrollbar in IE 8/9.
391
+ * 2. Improve readability and alignment in all browsers.
392
+ */
393
+
394
+ textarea {
395
+ overflow: auto; /* 1 */
396
+ vertical-align: top; /* 2 */
397
+ }
398
+
399
+ /* ==========================================================================
400
+ Tables
401
+ ========================================================================== */
402
+
403
+ /**
404
+ * Remove most spacing between table cells.
405
+ */
406
+
407
+ table {
408
+ border-collapse: collapse;
409
+ border-spacing: 0;
410
+ }
@@ -0,0 +1,85 @@
1
+ require 'better_errors'
2
+ require 'stringio'
3
+
4
+ module StackProf
5
+ module Webnav
6
+ class Presenter
7
+ attr_reader :report
8
+ def initialize report
9
+ @report = report
10
+ end
11
+
12
+ def file_overview path
13
+ buffer = StringIO.new
14
+ report.print_file(path, buffer)
15
+ data = buffer.string.split("\n").map {|l| l.split('|').first}
16
+
17
+ {
18
+ :lineinfo => data,
19
+ :code => BetterErrors::CodeFormatter::HTML.new(path, 0, 9999).output
20
+ }
21
+ end
22
+
23
+ def overview_frames
24
+ report.frames.map do |frame, info|
25
+ call, total = info.values_at(:samples, :total_samples)
26
+ {
27
+ :total => total,
28
+ :total_pct => percent(total.to_f/report.overall_samples),
29
+ :samples => call,
30
+ :samples_pct => percent(call.to_f/report.overall_samples),
31
+ :method => info[:name]
32
+ }
33
+ end
34
+ end
35
+
36
+ def method_info name
37
+ name = /#{Regexp.escape name}/ unless Regexp === name
38
+ frames = report.frames.select do |frame, info|
39
+ info[:name] =~ name
40
+ end.map do |frame, info|
41
+ file, line = info.values_at(:file, :line)
42
+
43
+ {
44
+ :callers => callers(frame, info),
45
+ :callees => callees(frame, info),
46
+ :location => file,
47
+ :source => BetterErrors::CodeFormatter::HTML.new(file, line).output
48
+ }
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def percent value
55
+ "%2.2f%" % (value*100)
56
+ end
57
+
58
+ def callers frame, info
59
+ report.data[:frames].select do |id, other|
60
+ other[:edges] && other[:edges].include?(frame)
61
+ end.map do |id, other|
62
+ [other[:name], other[:edges][frame]]
63
+ end.sort_by(&:last).reverse.map do |name, weight|
64
+ {
65
+ :weight => weight,
66
+ :pct => percent(weight.to_f/info[:total_samples]),
67
+ :method => name
68
+ }
69
+ end
70
+ end
71
+
72
+ def callees frame, info
73
+ (info[:edges] || []).map do |k, weight|
74
+ [report.data[:frames][k][:name], weight]
75
+ end.sort_by { |k,v| -v }.map do |name, weight|
76
+ {
77
+ :weight => weight,
78
+ :pct => percent(weight.to_f/(info[:total_samples]-info[:samples])),
79
+ :method => name
80
+ }
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,68 @@
1
+ require 'nyny'
2
+ require 'haml'
3
+ require "stackprof"
4
+ require 'sprockets'
5
+ require_relative 'presenter'
6
+
7
+ module StackProf
8
+ module Webnav
9
+ class Server < NYNY::App
10
+ class << self
11
+ attr_accessor :report_dump_path
12
+
13
+ def presenter
14
+ report = StackProf::Report.new(Marshal.load(File.open(report_dump_path).read))
15
+ @presenter ||= Presenter.new(report)
16
+ end
17
+ end
18
+
19
+ helpers do
20
+ def template_path name
21
+ File.join(__dir__, name)
22
+ end
23
+
24
+ def render_with_layout *args
25
+ args[0] = template_path("views/#{args[0]}.haml")
26
+ render(template_path('views/layout.haml')) { render(*args) }
27
+ end
28
+
29
+ def presenter
30
+ Server.presenter
31
+ end
32
+
33
+ def method_url name
34
+ "/method?name=#{URI.escape(name)}"
35
+ end
36
+
37
+ def file_url path
38
+ "/file?path=#{URI.escape(path)}"
39
+ end
40
+ end
41
+
42
+ sprockets = Sprockets::Environment.new do |env|
43
+ env.append_path(File.join(__dir__, 'css'))
44
+ end.index
45
+ builder.map('/assets'){ run sprockets }
46
+
47
+ get '/' do
48
+ @file = Server.report_dump_path
49
+ @action = "overview"
50
+ @frames = presenter.overview_frames
51
+ render_with_layout :overview
52
+ end
53
+
54
+ get '/method' do
55
+ @action = params[:name]
56
+ @frames = presenter.method_info(params[:name])
57
+ render_with_layout :method
58
+ end
59
+
60
+ get '/file' do
61
+ path = params[:path]
62
+ @path = path
63
+ @data = presenter.file_overview(path)
64
+ render_with_layout :file
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,73 @@
1
+ require 'better_errors'
2
+
3
+ module StackProf
4
+ module Webnav
5
+ class Presenter
6
+ attr_reader :report
7
+ def initialize report
8
+ @report = report
9
+ end
10
+
11
+ def overview_frames
12
+ report.frames.map do |frame, info|
13
+ call, total = info.values_at(:samples, :total_samples)
14
+ {
15
+ :total => total,
16
+ :total_pct => percent(total.to_f/report.overall_samples),
17
+ :samples => call,
18
+ :samples_pct => percent(call.to_f/report.overall_samples),
19
+ :method => info[:name]
20
+ }
21
+ end
22
+ end
23
+
24
+ def method_info name
25
+ name = /#{Regexp.escape name}/ unless Regexp === name
26
+ frames = report.frames.select do |frame, info|
27
+ info[:name] =~ name
28
+ end.map do |frame, info|
29
+ file, line = info.values_at(:file, :line)
30
+
31
+ {
32
+ :callers => callers(frame, info),
33
+ :callees => callees(frame, info),
34
+ :location => "#{file}:#{line}",
35
+ :source => BetterErrors::CodeFormatter::HTML.new(file, line).output
36
+ }
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def percent value
43
+ "%2.2f%" % (value*100)
44
+ end
45
+
46
+ def callers frame, info
47
+ report.data[:frames].select do |id, other|
48
+ other[:edges] && other[:edges].include?(frame)
49
+ end.map do |id, other|
50
+ [other[:name], other[:edges][frame]]
51
+ end.sort_by(&:last).reverse.map do |name, weight|
52
+ {
53
+ :weight => weight,
54
+ :pct => percent(weight.to_f/info[:total_samples]),
55
+ :method => name
56
+ }
57
+ end
58
+ end
59
+
60
+ def callees frame, info
61
+ (info[:edges] || []).map do |k, weight|
62
+ [report.data[:frames][k][:name], weight]
63
+ end.sort_by { |k,v| -v }.map do |name, weight|
64
+ {
65
+ :weight => weight,
66
+ :pct => percent(weight.to_f/(info[:total_samples]-info[:samples])),
67
+ :method => name
68
+ }
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,5 @@
1
+ module StackProf
2
+ module Webnav
3
+ VERSION = '0.0.1'
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ %h3 StackProf Navigator - #{@path}
2
+ %hr
3
+
4
+ %a{:href => '/'} &#8592; Back to overview
5
+ %br
6
+ %br
7
+
8
+ .code_linenums
9
+ - @data[:lineinfo].each do |l|
10
+ %span= l
11
+ != @data[:code]
@@ -0,0 +1,9 @@
1
+ %html
2
+ %head
3
+ %title Stackprof navigator
4
+ %link(rel="stylesheet" href="/assets/application.css")
5
+
6
+ %body
7
+ .row
8
+ .large-12.columns
9
+ = yield
@@ -0,0 +1,46 @@
1
+ %h3 StackProf Navigator - #{@action} (#{@frames.count} frames)
2
+ %hr
3
+
4
+ %a{:href => '/'} &#8592; Back to overview
5
+ %br
6
+
7
+ - @frames.each do |frame|
8
+ %h4
9
+ %a{:href => file_url(frame[:location])}= frame[:location]
10
+ - if frame[:callers].any?
11
+ %table
12
+ %thead
13
+ %th Callers
14
+ %th
15
+ %th
16
+ %th
17
+ %tbody
18
+ - frame[:callers].each do |caller|
19
+ %tr
20
+ %td
21
+ %td= caller[:weight]
22
+ %td= caller[:pct]
23
+ %td
24
+ %a{:href => method_url(caller[:method])}
25
+ = caller[:method]
26
+
27
+ - if frame[:callees].any?
28
+ %table
29
+ %thead
30
+ %th Callees
31
+ %th
32
+ %th
33
+ %th
34
+ %tbody
35
+ - frame[:callees].each do |caller|
36
+ %tr
37
+ %td
38
+ %td= caller[:weight]
39
+ %td= caller[:pct]
40
+ %td
41
+ %a{:href => method_url(caller[:method])}
42
+ = caller[:method]
43
+
44
+ %h4 Code
45
+ != frame[:source]
46
+ %hr