Skip to content

Commit b0342b2

Browse files
committed
Improve summary of allocations and time spent rendering
It turns out emitted `render` events from Rails overlap cumulatively if you render a partial in a partial, and there's no nice way to differentiate parent partials from children, so the duration and allocations counts can be way off when the totals from the events are summed. View time can end up being twice as much as the total time, which is obviously impossible. Rails cheats a bit for it's rendering totals by taking the whole page template, but that doesn't work for SR, so allocations and rendering time have to be calculated a bit differently.
1 parent 2924ee0 commit b0342b2

File tree

2 files changed

+24
-8
lines changed

2 files changed

+24
-8
lines changed

lib/stimulus_reflex/instrumentation.rb

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,33 @@ def self.track(reflex)
66
return yield unless reflex.logger && StimulusReflex.config.instrument_reflexes
77

88
events = []
9+
start_allocations = current_allocations
910

10-
time = Benchmark.realtime do
11-
ActiveSupport::Notifications.subscribed(proc { |event| events << event }, /^sql.active_record|^render/) do
11+
total_time = Benchmark.ms do
12+
ActiveSupport::Notifications.subscribed(proc { |event| events << event }, /^sql.active_record|reflex.render/) do
1213
yield
1314
end
1415
end
1516

16-
sql, views = events.partition { |e| e.name.match?(/^sql/) }
17+
end_allocations = current_allocations
18+
sql, rendering = events.partition { |e| e.name.match?(/^sql/) }
1719

18-
reflex.logger.info "Processed #{reflex.class.name}##{reflex.method_name} in #{(time * 1000).round(1)}ms " \
19-
"(Views: #{views.sum(&:duration).round(1)}ms | " \
20-
"ActiveRecord: #{sql.sum(&:duration).round(1)}ms | " \
21-
"Allocations: #{events.sum(&:allocations)}) \n"
20+
reflex.logger.info "Processed #{reflex.class.name}##{reflex.method_name} in #{total_time.round(1)}ms " \
21+
"(Views: #{rendering.sum(&:duration).round(1)}ms | " \
22+
"ActiveRecord: #{sql.sum(&:duration).round(1)}ms | " \
23+
"Allocations: #{end_allocations - start_allocations}) \n"
24+
end
25+
26+
def self.instrument(reflex, event_name)
27+
return yield unless reflex.logger && StimulusReflex.config.instrument_reflexes
28+
29+
ActiveSupport::Notifications.instrument event_name, this: :data do
30+
yield
31+
end
32+
end
33+
34+
def self.current_allocations
35+
GC.stat.key?(:total_allocated_objects) ? GC.stat(:total_allocated_objects) : 0
2236
end
2337
end
2438
end

lib/stimulus_reflex/reflex.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,9 @@ def render(*args)
118118
options = args.extract_options!
119119
(options[:locals] ||= {}).reverse_merge!(params: params)
120120
args << options.reverse_merge(layout: false)
121-
controller_class.renderer.new(connection.env.merge("SCRIPT_NAME" => "")).render(*args)
121+
StimulusReflex::Instrumentation.instrument self, "reflex.render" do
122+
controller_class.renderer.new(connection.env.merge("SCRIPT_NAME" => "")).render(*args)
123+
end
122124
end
123125

124126
# Invoke the reflex action specified by `name` and run all callbacks

0 commit comments

Comments
 (0)