Class: LiquidProf::Profiler

Inherits:
Object
  • Object
show all
Defined in:
lib/liquidprof/profiler.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#statsObject

Returns the value of attribute stats.



3
4
5
# File 'lib/liquidprof/profiler.rb', line 3

def stats
  @stats
end

#templatesObject

Returns the value of attribute templates.



3
4
5
# File 'lib/liquidprof/profiler.rb', line 3

def templates
  @templates
end

Class Method Details

.all_tagsObject



137
138
139
# File 'lib/liquidprof/profiler.rb', line 137

def all_tags
  ObjectSpace.each_object(Class).select { |klass| klass <= Liquid::Tag }
end

.dfs(root, &block) ⇒ Object



141
142
143
144
145
146
147
148
149
# File 'lib/liquidprof/profiler.rb', line 141

def dfs(root, &block)
  block.yield(root, :pre)
  if root.respond_to?(:nodelist) && root.nodelist
    root.nodelist.each do |child|
      dfs(child, &block)
    end
  end
  block.yield(root, :post)
end

.hook(method_name, tags, &block) ⇒ Object



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/liquidprof/profiler.rb', line 151

def hook(method_name, tags, &block)
  [tags].flatten.each do |tag|
    tag.class_exec(block, tag) do |block, tag|
      hooked_name = LiquidProf::Profiler.hooked(method_name, tag)
      unhooked_name = LiquidProf::Profiler.unhooked(method_name, tag)

      define_method(hooked_name) do |*args|
        owner = self.class.instance_method(method_name).owner
        if method_name != :render || (self.class == owner && owner == tag)
          block.yield(self, method(unhooked_name), args)
        else
          send(unhooked_name, *args)
        end
      end

      alias_method unhooked_name, method_name
      alias_method method_name, hooked_name
    end
  end
end

.hooked(method_name, tag) ⇒ Object



184
185
186
# File 'lib/liquidprof/profiler.rb', line 184

def hooked(method_name, tag)
  "#{method_name}_#{tag}_hooked"
end

.profile(iterations = 1, &block) ⇒ Object



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/liquidprof/profiler.rb', line 113

def profile(iterations=1, &block)
  prof = Profiler.start

  hook(:parse, Liquid::Template) do |template, method, args|
    method.(*args)
  end

  hook(:render, Liquid::Template) do |template, method, args|
    output = ""
    prof.templates << template
    iterations.times do
      prof.stats_init(template)
      output = method.(*args)
    end
    output
  end

  yield

  unhook(:parse, Liquid::Template)
  unhook(:render, Liquid::Template)
  Profiler.stop
end

.profilerObject



95
96
97
# File 'lib/liquidprof/profiler.rb', line 95

def profiler
  @@profiler
end

.startObject



99
100
101
# File 'lib/liquidprof/profiler.rb', line 99

def start
  @@profiler ||= Profiler.new(Profiler.all_tags() + [Liquid::Variable])
end

.stopObject



103
104
105
106
107
108
109
110
111
# File 'lib/liquidprof/profiler.rb', line 103

def stop
  return unless @@profiler
  tags = Profiler.all_tags() + [Liquid::Variable]
  @@profiler.remove_profiling(tags)
  @@profiler.remove_raw_markup()
  prof = @@profiler
  @@profiler = nil
  prof
end

.unhook(method_name, tags) ⇒ Object



172
173
174
175
176
177
178
179
180
181
182
# File 'lib/liquidprof/profiler.rb', line 172

def unhook(method_name, tags)
  [tags].flatten.each do |tag|
    tag.class_eval do |tag|
      if method_defined?(LiquidProf::Profiler.hooked(method_name, tag))
        alias_method method_name, LiquidProf::Profiler.unhooked(method_name, tag)
        remove_method LiquidProf::Profiler.hooked(method_name, tag)
        remove_method LiquidProf::Profiler.unhooked(method_name, tag)
      end
    end
  end
end

.unhooked(method_name, tag) ⇒ Object



188
189
190
# File 'lib/liquidprof/profiler.rb', line 188

def unhooked(method_name, tag)
  "#{method_name}_#{tag}_unhooked"
end

Instance Method Details

#add_profiling(tags) ⇒ Object



58
59
60
61
62
63
64
65
66
67
# File 'lib/liquidprof/profiler.rb', line 58

def add_profiling(tags)
  Profiler.hook(:render, tags) do |node, method, args|
    output = nil
    start = Time.now
    output = method.(*args)
    time = Time.now - start
    stats_inc(node, time, output.to_s.length)
    output
  end
end

#add_raw_markupObject



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/liquidprof/profiler.rb', line 33

def add_raw_markup
  Profiler.hook(:create_variable, Liquid::Block) do |node, method, args|
    var = method.(*args)
    var.instance_variable_set :@raw_markup, args.first
    var.class.class_eval { attr_reader :raw_markup }
    var
  end

  Profiler.hook(:initialize, Liquid::Tag) do |node, method, args|
    method.(*args)
    node.instance_variable_set :@raw_markup, "{% " + (args[0].strip + " " + args[1].strip).strip + " %}"
    node.class.class_eval { attr_reader :raw_markup }
  end

  Profiler.hook(:end_tag, Liquid::Block) do |node, method, args|
    node.instance_variable_set :@raw_markup_end, "{% #{node.block_delimiter} %}"
    node.class.class_eval { attr_reader :raw_markup_end }
    method.(*args)
  end
end

#profile(template, iterations = 1, *args) ⇒ Object



17
18
19
20
21
22
23
24
25
# File 'lib/liquidprof/profiler.rb', line 17

def profile(template, iterations=1, *args)
  output = ""
  @templates << template
  iterations.times do
    stats_init(template)
    output = template.render!(*args)
  end
  output
end

#remove_profiling(tags) ⇒ Object



54
55
56
# File 'lib/liquidprof/profiler.rb', line 54

def remove_profiling(tags)
  Profiler.unhook(:render, tags)
end

#remove_raw_markupObject



27
28
29
30
31
# File 'lib/liquidprof/profiler.rb', line 27

def remove_raw_markup
  Profiler.unhook(:create_variable, Liquid::Block)
  Profiler.unhook(:initialize, Liquid::Tag)
  Profiler.unhook(:end_tag, Liquid::Block)
end

#stats_init(root) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
# File 'lib/liquidprof/profiler.rb', line 5

def stats_init(root)
  if root.class == Liquid::Template
    return stats_init(root.root)
  end

  Profiler.dfs(root) do |node, pos|
    next unless pos == :pre
    next if node.class == String
    stats_init_node(node)
  end
end