rack-mini-profiler 0.1.18 → 0.1.23

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.

Potentially problematic release.


This version of rack-mini-profiler might be problematic. Click here for more details.

Files changed (38) hide show
  1. data/{CHANGELOG → Ruby/CHANGELOG} +107 -83
  2. data/{README.md → Ruby/README.md} +22 -9
  3. data/{lib → Ruby/lib}/html/includes.css +0 -0
  4. data/{lib → Ruby/lib}/html/includes.js +80 -16
  5. data/{lib → Ruby/lib}/html/includes.less +0 -0
  6. data/{lib → Ruby/lib}/html/includes.tmpl +39 -15
  7. data/{lib → Ruby/lib}/html/jquery.1.7.1.js +1 -1
  8. data/{lib → Ruby/lib}/html/jquery.tmpl.js +1 -1
  9. data/{lib → Ruby/lib}/html/list.css +0 -0
  10. data/{lib → Ruby/lib}/html/list.js +7 -6
  11. data/{lib → Ruby/lib}/html/list.tmpl +0 -0
  12. data/Ruby/lib/html/profile_handler.js +1 -0
  13. data/{lib → Ruby/lib}/html/share.html +0 -0
  14. data/{lib → Ruby/lib}/mini_profiler/client_settings.rb +0 -0
  15. data/{lib → Ruby/lib}/mini_profiler/client_timer_struct.rb +1 -1
  16. data/{lib → Ruby/lib}/mini_profiler/config.rb +54 -52
  17. data/{lib → Ruby/lib}/mini_profiler/context.rb +0 -0
  18. data/Ruby/lib/mini_profiler/custom_timer_struct.rb +22 -0
  19. data/Ruby/lib/mini_profiler/gc_profiler.rb +103 -0
  20. data/{lib → Ruby/lib}/mini_profiler/page_timer_struct.rb +7 -2
  21. data/{lib → Ruby/lib}/mini_profiler/profiler.rb +81 -21
  22. data/{lib → Ruby/lib}/mini_profiler/profiling_methods.rb +10 -2
  23. data/{lib → Ruby/lib}/mini_profiler/request_timer_struct.rb +20 -1
  24. data/{lib → Ruby/lib}/mini_profiler/sql_timer_struct.rb +0 -0
  25. data/{lib → Ruby/lib}/mini_profiler/storage/abstract_store.rb +0 -0
  26. data/{lib → Ruby/lib}/mini_profiler/storage/file_store.rb +0 -0
  27. data/Ruby/lib/mini_profiler/storage/memcache_store.rb +51 -0
  28. data/{lib → Ruby/lib}/mini_profiler/storage/memory_store.rb +0 -0
  29. data/{lib → Ruby/lib}/mini_profiler/storage/redis_store.rb +44 -44
  30. data/{lib → Ruby/lib}/mini_profiler/timer_struct.rb +0 -0
  31. data/Ruby/lib/mini_profiler/version.rb +5 -0
  32. data/{lib → Ruby/lib}/mini_profiler_rails/railtie.rb +3 -2
  33. data/Ruby/lib/patches/net_patches.rb +14 -0
  34. data/{lib → Ruby/lib}/patches/sql_patches.rb +20 -1
  35. data/{lib → Ruby/lib}/rack-mini-profiler.rb +2 -1
  36. data/rack-mini-profiler.gemspec +8 -6
  37. metadata +45 -40
  38. data/lib/html/profile_handler.js +0 -62
@@ -1,83 +1,107 @@
1
- 28-June-2012 - Sam
2
-
3
- * Started change log
4
- * Corrected profiler so it properly captures POST requests (was supressing non 200s)
5
- * Amended Rack.MiniProfiler.config[:user_provider] to use ip addres for identity
6
- * Fixed bug where unviewed missing ids never got cleared
7
- * Supress all '/assets/' in the rails tie (makes debugging easier)
8
- * record_sql was mega buggy
9
-
10
- 9-July-2012 - Sam
11
-
12
- * Cleaned up mechanism for profiling in production, all you need to do now
13
- is call Rack::MiniProfiler.authorize_request to get profiling working in
14
- production
15
- * Added option to display full backtraces pp=full-backtrace
16
- * Cleaned up railties, got rid of the post authorize callback
17
- * Version 0.1.3
18
-
19
- 12-July-2012 - Sam
20
-
21
- * Fixed incorrect profiling steps (was not indenting or measuring start time right
22
- * Implemented native PG and MySql2 interceptors, this gives way more accurate times
23
- * Refactored context so its a proper class and not a hash
24
- * Added some more client probing built in to rails
25
- * More tests
26
-
27
- 18-July-2012 - Sam
28
-
29
- * Added First Paint time for chrome
30
- * Bug fix to ensure non Rails installs have mini profiler
31
- * Version 0.1.7
32
-
33
- 30-July-2012 - Sam
34
-
35
- * Made compliant with ancient versions of Rack (including Rack used by Rails2)
36
- * Fixed broken share link
37
- * Fixed crashes on startup (in MemoryStore and FileStore)
38
- * Version 0.1.8
39
- * Unicode fix
40
- * Version 0.1.9
41
-
42
- 7-August-2012 - Sam
43
-
44
- * Added option to disable profiler for the current session (pp=disable / pp=enable)
45
- * yajl compatability contributed by Sven Riedel
46
-
47
- 10-August-2012 - Sam
48
-
49
- * Added basic prepared statement profiling for postgres
50
-
51
- 20-August-2012 - Sam
52
-
53
- * 1.12.pre
54
- * Cap X-MiniProfiler-Ids at 10, otherwise the header can get killed
55
-
56
- 3-September-2012 - Sam
57
-
58
- * 1.13.pre
59
- * pg gem prepared statements were not being logged correctly
60
- * added setting config.backtrace_ignores = [] - an array of regexes that match on caller lines that get ignored
61
- * added setting config.backtrace_includes = [] - an array of regexes that get included in the trace by default
62
- * cleaned up the way client settings are stored
63
- * made pp=full-backtrace "sticky"
64
- * added pp=normal-backtrace to clear the "sticky" state
65
- * change "pp=sample" to work with "caller" no need for stack trace gem
66
-
67
- 4-September-2012 - Sam
68
-
69
- * 1.15.pre
70
- * fixed annoying bug where client settings were not sticking
71
- * fixed long standing issue with Rack::ConditionalGet stopping MiniProfiler from working properly
72
-
73
- 5-September-2012 - Sam
74
-
75
- * 1.16
76
- * fixed long standing problem specs (issue with memory store)
77
- * fixed issue where profiler would be dumped when you got a 404 in production (and any time rails is bypassed)
78
- * implemented stacktrace properly
79
-
80
- 9-September-2012 - Sam
81
-
82
- * 1.17
83
- * pp=sample was bust unless stacktrace was installed
1
+ 28-June-2012 - Sam
2
+
3
+ * Started change log
4
+ * Corrected profiler so it properly captures POST requests (was supressing non 200s)
5
+ * Amended Rack.MiniProfiler.config[:user_provider] to use ip addres for identity
6
+ * Fixed bug where unviewed missing ids never got cleared
7
+ * Supress all '/assets/' in the rails tie (makes debugging easier)
8
+ * record_sql was mega buggy
9
+ * added MemcacheStore
10
+
11
+ 9-July-2012 - Sam
12
+
13
+ * Cleaned up mechanism for profiling in production, all you need to do now
14
+ is call Rack::MiniProfiler.authorize_request to get profiling working in
15
+ production
16
+ * Added option to display full backtraces pp=full-backtrace
17
+ * Cleaned up railties, got rid of the post authorize callback
18
+ * Version 0.1.3
19
+
20
+ 12-July-2012 - Sam
21
+
22
+ * Fixed incorrect profiling steps (was not indenting or measuring start time right
23
+ * Implemented native PG and MySql2 interceptors, this gives way more accurate times
24
+ * Refactored context so its a proper class and not a hash
25
+ * Added some more client probing built in to rails
26
+ * More tests
27
+
28
+ 18-July-2012 - Sam
29
+
30
+ * Added First Paint time for chrome
31
+ * Bug fix to ensure non Rails installs have mini profiler
32
+ * Version 0.1.7
33
+
34
+ 30-July-2012 - Sam
35
+
36
+ * Made compliant with ancient versions of Rack (including Rack used by Rails2)
37
+ * Fixed broken share link
38
+ * Fixed crashes on startup (in MemoryStore and FileStore)
39
+ * Version 0.1.8
40
+ * Unicode fix
41
+ * Version 0.1.9
42
+
43
+ 7-August-2012 - Sam
44
+
45
+ * Added option to disable profiler for the current session (pp=disable / pp=enable)
46
+ * yajl compatability contributed by Sven Riedel
47
+
48
+ 10-August-2012 - Sam
49
+
50
+ * Added basic prepared statement profiling for postgres
51
+
52
+ 20-August-2012 - Sam
53
+
54
+ * 1.12.pre
55
+ * Cap X-MiniProfiler-Ids at 10, otherwise the header can get killed
56
+
57
+ 3-September-2012 - Sam
58
+
59
+ * 1.13.pre
60
+ * pg gem prepared statements were not being logged correctly
61
+ * added setting config.backtrace_ignores = [] - an array of regexes that match on caller lines that get ignored
62
+ * added setting config.backtrace_includes = [] - an array of regexes that get included in the trace by default
63
+ * cleaned up the way client settings are stored
64
+ * made pp=full-backtrace "sticky"
65
+ * added pp=normal-backtrace to clear the "sticky" state
66
+ * change "pp=sample" to work with "caller" no need for stack trace gem
67
+
68
+ 4-September-2012 - Sam
69
+
70
+ * 1.15.pre
71
+ * fixed annoying bug where client settings were not sticking
72
+ * fixed long standing issue with Rack::ConditionalGet stopping MiniProfiler from working properly
73
+
74
+ 5-September-2012 - Sam
75
+
76
+ * 1.16
77
+ * fixed long standing problem specs (issue with memory store)
78
+ * fixed issue where profiler would be dumped when you got a 404 in production (and any time rails is bypassed)
79
+ * implemented stacktrace properly
80
+
81
+ 9-September-2012 - Sam
82
+
83
+ * 1.17
84
+ * pp=sample was bust unless stacktrace was installed
85
+
86
+ 10-September-2012 - Sam
87
+
88
+ * 1.19
89
+ * fix compat issue with 1.8.7
90
+
91
+ 12-September-2012 - Sam
92
+
93
+ * 1.20
94
+ * Added pp=profile-gc , it allows you to profile the GC in Ruby 1.9.3
95
+
96
+ 17-September-2012
97
+ * 1.21
98
+ * New MemchacedStore
99
+ * Rails 4 support
100
+
101
+ 17-September-2012
102
+ * Allow rack-mini-profiler to be sourced from github
103
+ * Extracted the pp=profile-gc-time out, the object space profiler needs to disable gc
104
+
105
+ 20-September-2010
106
+ * 1.22
107
+ * Fix permission issue in the gem
@@ -15,7 +15,7 @@ All you have to do is include the Gem and you're good to go in development.
15
15
 
16
16
  rack-mini-profiler is designed with production profiling in mind. To enable that just run `Rack::MiniProfiler.authorize_request` once you know a request is allowed to profile.
17
17
 
18
- For example:
18
+ Using Rails:
19
19
 
20
20
  ```ruby
21
21
  # A hook in your ApplicationController
@@ -47,24 +47,38 @@ class MyApp < Sinatra::Base
47
47
  end
48
48
  ```
49
49
 
50
+ ## Database profiling
51
+
52
+ Currently supports Mysql2, Postgres, and Mongoid3 (with fallback support to ActiveRecord)
53
+
50
54
  ## Storage
51
55
 
52
- By default, rack-mini-profiler stores its results in a memory store:
56
+ rack-mini-profiler stores it's results so they can be shared later and aren't lost at the end of the request.
57
+
58
+ There are 4 storage options: `MemoryStore`, `RedisStore`, `MemcacheStore`, and `FileStore`.
59
+
60
+ `FileStore` is the default in Rails environments and will write files to `tmp/miniprofiler/*`. `MemoryStore` is the default otherwise.
61
+
62
+ To change the default you can create a file in `config/initializers/mini_profiler.rb`
53
63
 
54
64
  ```ruby
55
- # our default
65
+ # set MemoryStore
56
66
  Rack::MiniProfiler.config.storage = Rack::MiniProfiler::MemoryStore
57
- ```
58
67
 
59
- There are 2 other available storage engines, `RedisStore` and `FileStore`.
68
+ # set RedisStore
69
+ if Rails.env.production?
70
+ uri = URI.parse(ENV["REDIS_SERVER_URL"])
71
+ Rack::MiniProfiler.config.storage_options = { :host => uri.host, :port => uri.port, :password => uri.password }
72
+ Rack::MiniProfiler.config.storage = Rack::MiniProfiler::RedisStore
73
+ end
74
+ ```
60
75
 
61
- MemoryStore is stores results in a processes heap - something that does not work well in a multi process environment.
76
+ MemoryStore stores results in a processes heap - something that does not work well in a multi process environment.
62
77
  FileStore stores results in the file system - something that may not work well in a multi machine environment.
78
+ RedisStore/MemcacheStore work in multi process and multi machine environments (RedisStore only saves results for up to 24 hours so it won't continue to fill up Redis).
63
79
 
64
80
  Additionally you may implement an AbstractStore for your own provider.
65
81
 
66
- Rails hooks up a FileStore for all environments.
67
-
68
82
  ## Running the Specs
69
83
 
70
84
  ```
@@ -120,7 +134,6 @@ end
120
134
  * pre_authorize_cb - A lambda callback you can set to determine whether or not mini_profiler should be visible on a given request. Default in a Rails environment is only on in development mode. If in a Rack app, the default is always on.
121
135
  * position - Can either be 'right' or 'left'. Default is 'left'.
122
136
  * skip_schema_queries - Whether or not you want to log the queries about the schema of your tables. Default is 'false', 'true' in rails development.
123
- * use_existing_jquery - Use the version of jQuery on the page as opposed to the self contained one
124
137
  * auto_inject (default true) - when false the miniprofiler script is not injected in the page
125
138
  * backtrace_filter - a regex you can use to filter out unwanted lines from the backtraces
126
139
 
File without changes
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
- var MiniProfiler = (function ($) {
2
+ var MiniProfiler = (function () {
3
+ var $;
3
4
 
4
5
  var options,
5
6
  container,
@@ -449,11 +450,12 @@ var MiniProfiler = (function ($) {
449
450
  };
450
451
 
451
452
  // fetch profile results for any ajax calls
453
+ // note, this does not use $ cause we want to hook into the main jQuery
452
454
  if (jQuery && jQuery(document) && jQuery(document).ajaxComplete) {
453
455
  jQuery(document).ajaxComplete(jQueryAjaxComplete);
454
456
  }
455
457
 
456
- if (jQuery(document).ajaxStart)
458
+ if (jQuery && jQuery(document).ajaxStart)
457
459
  jQuery(document).ajaxStart(function () { ajaxStartTime = new Date(); });
458
460
 
459
461
  // fetch results after ASP Ajax calls
@@ -512,9 +514,42 @@ var MiniProfiler = (function ($) {
512
514
 
513
515
  return {
514
516
 
515
- init: function (opt) {
517
+ init: function () {
518
+ var script = document.getElementById('mini-profiler');
519
+ if (!script || !script.getAttribute) return;
516
520
 
517
- options = opt || {};
521
+ options = (function () {
522
+ var version = script.getAttribute('data-version');
523
+ var path = script.getAttribute('data-path');
524
+
525
+ var currentId = script.getAttribute('data-current-id');
526
+
527
+ var ids = script.getAttribute('data-ids');
528
+ if (ids) ids = ids.split(',');
529
+
530
+ var position = script.getAttribute('data-position');
531
+
532
+ if (script.getAttribute('data-max-traces'))
533
+ var maxTraces = parseInt(script.getAttribute('data-max-traces'));
534
+
535
+ if (script.getAttribute('data-trivial') === 'true') var trivial = true;
536
+ if (script.getAttribute('data-children') == 'true') var children = true;
537
+ if (script.getAttribute('data-controls') == 'true') var controls = true;
538
+ if (script.getAttribute('data-authorized') == 'true') var authorized = true;
539
+
540
+ return {
541
+ ids: ids,
542
+ path: path,
543
+ version: version,
544
+ renderPosition: position,
545
+ showTrivial: trivial,
546
+ showChildrenTime: children,
547
+ maxTracesToShow: maxTraces,
548
+ showControls: controls,
549
+ currentId: currentId,
550
+ authorized: authorized
551
+ }
552
+ })();
518
553
 
519
554
  var doInit = function () {
520
555
  // when rendering a shared, full page, this div will exist
@@ -546,24 +581,50 @@ var MiniProfiler = (function ($) {
546
581
  document.getElementsByTagName('head')[0].appendChild(sc);
547
582
  };
548
583
 
549
- if (options.authorized) {
550
- var url = options.path + "includes.css?v=" + options.version;
551
- if (document.createStyleSheet) {
552
- document.createStyleSheet(url);
584
+ var wait = 0;
585
+ var finish = false;
586
+ var deferInit = function() {
587
+ if (finish) return;
588
+ if (window.performance && window.performance.timing && window.performance.timing.loadEventEnd == 0 && wait < 10000) {
589
+ setTimeout(deferInit, 100);
590
+ wait += 100;
553
591
  } else {
554
- $('head').append($('<link rel="stylesheet" type="text/css" href="' + url + '" />'));
592
+ finish = true;
593
+ init();
555
594
  }
595
+ };
556
596
 
557
- if (!$.tmpl) {
558
- load(options.path + 'jquery.tmpl.js?v=' + options.version, doInit);
559
- } else {
597
+ var init = function() {
598
+ if (options.authorized) {
599
+ var url = options.path + "includes.css?v=" + options.version;
600
+ if (document.createStyleSheet) {
601
+ document.createStyleSheet(url);
602
+ } else {
603
+ $('head').append($('<link rel="stylesheet" type="text/css" href="' + url + '" />'));
604
+ }
605
+ if (!$.tmpl) {
606
+ load(options.path + 'jquery.tmpl.js?v=' + options.version, doInit);
607
+ } else {
608
+ doInit();
609
+ }
610
+ }
611
+ else {
560
612
  doInit();
561
613
  }
562
614
  }
563
- else {
564
- doInit();
565
- }
566
615
 
616
+ if (typeof(jQuery) == 'function') {
617
+ var jQueryVersion = jQuery.fn.jquery.split('.');
618
+ }
619
+ if (jQueryVersion && parseInt(jQueryVersion[0]) < 2 && parseInt(jQueryVersion[1]) >= 7) {
620
+ MiniProfiler.jQuery = $ = jQuery;
621
+ $(deferInit);
622
+ } else {
623
+ load(options.path + "jquery.1.7.1.js?v=" + options.version, function() {
624
+ MiniProfiler.jQuery = $ = jQuery.noConflict(true);
625
+ $(deferInit);
626
+ });
627
+ }
567
628
  },
568
629
 
569
630
  getClientTimingByName: function (clientTiming, name) {
@@ -783,7 +844,10 @@ var MiniProfiler = (function ($) {
783
844
  return (duration || 0).toFixed(1);
784
845
  }
785
846
  };
786
- })(jQueryMP);
847
+ })();
848
+
849
+ MiniProfiler.init();
850
+
787
851
 
788
852
  // prettify.js
789
853
  // http://code.google.com/p/google-code-prettify/
File without changes
@@ -27,10 +27,13 @@
27
27
  {{if HasSqlTimings}}
28
28
  <th colspan="2">query time (ms)</th>
29
29
  {{/if}}
30
+ {{each CustomTimingNames}}
31
+ <th colspan="2">${$value.toLowerCase()} (ms)</th>
32
+ {{/each}}
30
33
  </tr>
31
34
  </thead>
32
35
  <tbody>
33
- {{tmpl(Root) "#timingTemplate"}}
36
+ {{tmpl({timing:Root, page:this.data}) "#timingTemplate"}}
34
37
  </tbody>
35
38
  <tfoot>
36
39
  <tr>
@@ -46,6 +49,12 @@
46
49
  <span class="profiler-unit">% in sql</span>
47
50
  </td>
48
51
  {{/if}}
52
+ {{each CustomTimingNames}}
53
+ <td colspan="2" class="profiler-number profiler-percentage-in-sql" title="${CustomTimingStats[$value].Count} ${$value.toLowerCase()} invocations spent ${MiniProfiler.formatDuration(CustomTimingStats[$value].Duration)} ms of total request time">
54
+ ${MiniProfiler.formatDuration(CustomTimingStats[$value].Duration / DurationMilliseconds * 100)}
55
+ <span class="profiler-unit">% in ${$value.toLowerCase()}</span>
56
+ </td>
57
+ {{/each}}
49
58
  </tr>
50
59
  </tfoot>
51
60
  </table>
@@ -123,37 +132,52 @@
123
132
 
124
133
  <script id="timingTemplate" type="text/x-jquery-tmpl">
125
134
 
126
- <tr class="{{if IsTrivial }}profiler-trivial{{/if}}" data-timing-id="${Id}">
127
- <td class="profiler-label" title="{{if Name && Name.length > 45 }}${Name}{{/if}}">
128
- <span class="profiler-indent">${MiniProfiler.renderIndent(Depth)}</span> ${Name.slice(0,45)}{{if Name && Name.length > 45 }}...{{/if}}
135
+ <tr class="{{if timing.IsTrivial }}profiler-trivial{{/if}}" data-timing-id="${timing.Id}">
136
+ <td class="profiler-label" title="{{if timing.Name && timing.Name.length > 45 }}${timing.Name}{{/if}}">
137
+ <span class="profiler-indent">${MiniProfiler.renderIndent(timing.Depth)}</span> ${timing.Name.slice(0,45)}{{if timing.Name && timing.Name.length > 45 }}...{{/if}}
129
138
  </td>
130
139
  <td class="profiler-duration" title="duration of this step without any children's durations">
131
- ${MiniProfiler.formatDuration(DurationWithoutChildrenMilliseconds)}
140
+ ${MiniProfiler.formatDuration(timing.DurationWithoutChildrenMilliseconds)}
132
141
  </td>
133
142
  <td class="profiler-duration profiler-duration-with-children" title="duration of this step and its children">
134
- ${MiniProfiler.formatDuration(DurationMilliseconds)}
143
+ ${MiniProfiler.formatDuration(timing.DurationMilliseconds)}
135
144
  </td>
136
145
  <td class="profiler-duration time-from-start" title="time elapsed since profiling started">
137
- <span class="profiler-unit">+</span>${MiniProfiler.formatDuration(StartMilliseconds)}
146
+ <span class="profiler-unit">+</span>${MiniProfiler.formatDuration(timing.StartMilliseconds)}
138
147
  </td>
139
148
 
140
- {{if HasSqlTimings}}
141
- <td class="profiler-duration {{if HasDuplicateSqlTimings}}profiler-warning{{/if}}" title="{{if HasDuplicateSqlTimings}}duplicate queries detected - {{/if}}{{if ExecutedReaders > 0 || ExecutedScalars > 0 || ExecutedNonQueries > 0}}${ExecutedReaders} reader, ${ExecutedScalars} scalar, ${ExecutedNonQueries} non-query statements executed{{/if}}">
149
+ {{if timing.HasSqlTimings}}
150
+ <td class="profiler-duration {{if timing.HasDuplicateSqlTimings}}profiler-warning{{/if}}" title="{{if timing.HasDuplicateSqlTimings}}duplicate queries detected - {{/if}}{{if timing.ExecutedReaders > 0 || timing.ExecutedScalars > 0 || timing.ExecutedNonQueries > 0}}${timing.ExecutedReaders} reader, ${timing.ExecutedScalars} scalar, ${timing.ExecutedNonQueries} non-query statements executed{{/if}}">
142
151
  <a class="profiler-queries-show">
143
- {{if HasDuplicateSqlTimings}}<span class="profiler-nuclear">!</span>{{/if}}
144
- ${SqlTimings.length} <span class="profiler-unit">sql</span>
152
+ {{if timing.HasDuplicateSqlTimings}}<span class="profiler-nuclear">!</span>{{/if}}
153
+ ${timing.SqlTimings.length} <span class="profiler-unit">sql</span>
145
154
  </a>
146
155
  </td>
147
156
  <td class="profiler-duration" title="aggregate duration of all queries in this step (excludes children)">
148
- ${MiniProfiler.formatDuration(SqlTimingsDurationMilliseconds)}
157
+ ${MiniProfiler.formatDuration(timing.SqlTimingsDurationMilliseconds)}
149
158
  </td>
159
+ {{else}}
160
+ <td colspan='2'></td>
150
161
  {{/if}}
151
162
 
163
+ {{each page.CustomTimingNames}}
164
+ {{if timing.CustomTimings[$value]}}
165
+ <td class="profiler-duration" title="aggregate number of all ${$value.toLowerCase()} invocations in this step (excludes children)">
166
+ ${timing.CustomTimings[$value].length} ${$value.toLowerCase()}
167
+ </td>
168
+ <td class="profiler-duration" title="aggregate duration of all ${$value.toLowerCase()} invocations in this step (excludes children)">
169
+ ${MiniProfiler.formatDuration(timing.CustomTimingStats[$value].Duration)}
170
+ </td>
171
+ {{else}}
172
+ <td colspan="2"></td>
173
+ {{/if}}
174
+ {{/each}}
175
+
152
176
  </tr>
153
177
 
154
- {{if HasChildren}}
155
- {{each Children}}
156
- {{tmpl($value) "#timingTemplate"}}
178
+ {{if timing.HasChildren}}
179
+ {{each timing.Children}}
180
+ {{tmpl({timing: $value, page: page}) "#timingTemplate"}}
157
181
  {{/each}}
158
182
  {{/if}}
159
183