ruby-prof 2.0.2 → 2.0.3

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.
@@ -1,168 +1,169 @@
1
- # encoding: utf-8
2
-
3
- require 'erb'
4
- require 'fileutils'
5
- require 'base64'
6
- require 'set'
7
- require 'stringio'
8
-
9
- module RubyProf
10
- # Prints a HTML visualization of the call tree.
11
- #
12
- # To use the printer:
13
- #
14
- # result = RubyProf.profile do
15
- # [code to profile]
16
- # end
17
- #
18
- # printer = RubyProf::CallStackPrinter.new(result)
19
- # printer.print(STDOUT)
20
-
21
- class CallStackPrinter < AbstractPrinter
22
- include ERB::Util
23
-
24
- # Specify print options.
25
- #
26
- # output - Any IO object, including STDOUT or a file.
27
- #
28
- # Keyword arguments:
29
- # title: - a String to override the default "ruby-prof call stack"
30
- # title of the report.
31
- #
32
- # threshold: - a float from 0 to 100 that sets the threshold of
33
- # results displayed.
34
- # Default value is 1.0
35
- #
36
- # expansion: - a float from 0 to 100 that sets the threshold of
37
- # results that are expanded, if the percent_total
38
- # exceeds it.
39
- # Default value is 10.0
40
- #
41
- # application: - a String to override the name of the application,
42
- # as it appears on the report.
43
- #
44
- # Also accepts min_percent:, max_percent:, filter_by:, and sort_method:
45
- # from AbstractPrinter.
46
- def print(output = STDOUT, title: "ruby-prof call stack", threshold: 1.0,
47
- expansion: 10.0, application: $PROGRAM_NAME,
48
- min_percent: 0, max_percent: 100, filter_by: :self_time, sort_method: nil, **)
49
- @min_percent = min_percent
50
- @max_percent = max_percent
51
- @filter_by = filter_by
52
- @sort_method = sort_method
53
- @title = title
54
- @threshold = threshold
55
- @expansion = expansion
56
- @application = application
57
- output << ERB.new(self.template).result(binding)
58
- end
59
-
60
- def print_stack(output, visited, call_tree, parent_time)
61
- total_time = call_tree.total_time
62
- percent_parent = (total_time/parent_time)*100
63
- percent_total = (total_time/@overall_time)*100
64
- return unless percent_total > min_percent
65
- color = self.color(percent_total)
66
- visible = percent_total >= threshold
67
- expanded = percent_total >= expansion
68
- display = visible ? "block" : "none"
69
-
70
- output << "<li class=\"color#{color}\" style=\"display:#{display}\">" << "\n"
71
-
72
- if visited.include?(call_tree)
73
- output << "<a href=\"#\" class=\"toggle empty\" ></a>" << "\n"
74
- output << "<span>%s %s</span>" % [link(call_tree.target, true), graph_link(call_tree)] << "\n"
75
- else
76
- visited << call_tree
77
-
78
- if call_tree.children.empty?
79
- output << "<a href=\"#\" class=\"toggle empty\" ></a>" << "\n"
80
- else
81
- visible_children = call_tree.children.any?{|ci| (ci.total_time/@overall_time)*100 >= threshold}
82
- image = visible_children ? (expanded ? "minus" : "plus") : "empty"
83
- output << "<a href=\"#\" class=\"toggle #{image}\" ></a>" << "\n"
84
- end
85
- output << "<span>%4.2f%% (%4.2f%%) %s %s</span>" % [percent_total, percent_parent,
86
- link(call_tree.target, false), graph_link(call_tree)] << "\n"
87
-
88
- unless call_tree.children.empty?
89
- output << (expanded ? '<ul>' : '<ul style="display:none">') << "\n"
90
- call_tree.children.sort_by{|c| -c.total_time}.each do |child_call_tree|
91
- print_stack(output, visited, child_call_tree, total_time)
92
- end
93
- output << '</ul>' << "\n"
94
- end
95
-
96
- visited.delete(call_tree)
97
- end
98
- output << '</li>' << "\n"
99
- end
100
-
101
- def name(call_tree)
102
- method = call_tree.target
103
- method.full_name
104
- end
105
-
106
- def link(method, recursive)
107
- method_name = "#{recursive ? '*' : ''}#{method.full_name}"
108
- if method.source_file.nil?
109
- h method_name
110
- else
111
- file = File.expand_path(method.source_file)
112
- "<a href=\"file://#{file}##{method.line}\">#{h method_name}</a>"
113
- end
114
- end
115
-
116
- def graph_link(call_tree)
117
- total_calls = call_tree.target.called
118
- totals = total_calls.to_s
119
- "[#{call_tree.called} calls, #{totals} total]"
120
- end
121
-
122
- def method_href(method)
123
- h(method.full_name.gsub(/[><#\.\?=:]/,"_"))
124
- end
125
-
126
- def total_time(call_trees)
127
- sum(call_trees.map{|ci| ci.total_time})
128
- end
129
-
130
- def sum(a)
131
- a.inject(0.0){|s,t| s+=t}
132
- end
133
-
134
- def dump(ci)
135
- $stderr.printf "%s/%d t:%f s:%f w:%f \n", ci, ci.object_id, ci.total_time, ci.self_time, ci.wait_time
136
- end
137
-
138
- def color(p)
139
- case i = p.to_i
140
- when 0..5
141
- "01"
142
- when 5..10
143
- "05"
144
- when 100
145
- "9"
146
- else
147
- "#{i/10}"
148
- end
149
- end
150
-
151
- attr_reader :application, :title, :threshold, :expansion
152
-
153
- def arguments
154
- ARGV.join(' ')
155
- end
156
-
157
- def base64_image
158
- @data ||= begin
159
- file = open_asset('call_stack_printer.png')
160
- Base64.encode64(file).gsub(/\n/, '')
161
- end
162
- end
163
-
164
- def template
165
- open_asset('call_stack_printer.html.erb')
166
- end
167
- end
168
- end
1
+ # encoding: utf-8
2
+
3
+ require 'erb'
4
+ require 'fileutils'
5
+ require 'base64'
6
+ require 'set'
7
+ require 'stringio'
8
+
9
+ module RubyProf
10
+ # Prints a HTML visualization of the call tree.
11
+ #
12
+ # To use the printer:
13
+ #
14
+ # result = RubyProf.profile do
15
+ # [code to profile]
16
+ # end
17
+ #
18
+ # printer = RubyProf::CallStackPrinter.new(result)
19
+ # printer.print(STDOUT)
20
+
21
+ class CallStackPrinter < AbstractPrinter
22
+ include ERB::Util
23
+
24
+ # Specify print options.
25
+ #
26
+ # output - Any IO object, including STDOUT or a file.
27
+ #
28
+ # Keyword arguments:
29
+ # title: - a String to override the default "ruby-prof call stack"
30
+ # title of the report.
31
+ #
32
+ # threshold: - a float from 0 to 100 that sets the threshold of
33
+ # results displayed.
34
+ # Default value is 1.0
35
+ #
36
+ # expansion: - a float from 0 to 100 that sets the threshold of
37
+ # results that are expanded, if the percent_total
38
+ # exceeds it.
39
+ # Default value is 10.0
40
+ #
41
+ # application: - a String to override the name of the application,
42
+ # as it appears on the report.
43
+ #
44
+ # Also accepts min_percent:, max_percent:, filter_by:, and sort_method:
45
+ # from AbstractPrinter.
46
+ def print(output = STDOUT, title: "ruby-prof call stack", threshold: 1.0,
47
+ expansion: 10.0, application: $PROGRAM_NAME,
48
+ min_percent: 0, max_percent: 100, filter_by: :self_time, sort_method: nil, max_depth: nil, **)
49
+ @min_percent = min_percent
50
+ @max_percent = max_percent
51
+ @filter_by = filter_by
52
+ @sort_method = sort_method
53
+ @max_depth = max_depth
54
+ @title = title
55
+ @threshold = threshold
56
+ @expansion = expansion
57
+ @application = application
58
+ output << ERB.new(self.template).result(binding)
59
+ end
60
+
61
+ def print_stack(output, visited, call_tree, parent_time, depth = 0)
62
+ total_time = call_tree.total_time
63
+ percent_parent = (total_time/parent_time)*100
64
+ percent_total = (total_time/@overall_time)*100
65
+ return unless percent_total > min_percent
66
+ color = self.color(percent_total)
67
+ visible = percent_total >= threshold
68
+ expanded = percent_total >= expansion
69
+ display = visible ? "block" : "none"
70
+
71
+ output << "<li class=\"color#{color}\" style=\"display:#{display}\">" << "\n"
72
+
73
+ if visited.include?(call_tree)
74
+ output << "<a href=\"#\" class=\"toggle empty\" ></a>" << "\n"
75
+ output << "<span>%s %s</span>" % [link(call_tree.target, true), graph_link(call_tree)] << "\n"
76
+ else
77
+ visited << call_tree
78
+
79
+ if call_tree.children.empty? || (@max_depth && depth >= @max_depth)
80
+ output << "<a href=\"#\" class=\"toggle empty\" ></a>" << "\n"
81
+ else
82
+ visible_children = call_tree.children.any?{|ci| (ci.total_time/@overall_time)*100 >= threshold}
83
+ image = visible_children ? (expanded ? "minus" : "plus") : "empty"
84
+ output << "<a href=\"#\" class=\"toggle #{image}\" ></a>" << "\n"
85
+ end
86
+ output << "<span>%4.2f%% (%4.2f%%) %s %s</span>" % [percent_total, percent_parent,
87
+ link(call_tree.target, false), graph_link(call_tree)] << "\n"
88
+
89
+ unless call_tree.children.empty? || (@max_depth && depth >= @max_depth)
90
+ output << (expanded ? '<ul>' : '<ul style="display:none">') << "\n"
91
+ call_tree.children.sort_by{|c| -c.total_time}.each do |child_call_tree|
92
+ print_stack(output, visited, child_call_tree, total_time, depth + 1)
93
+ end
94
+ output << '</ul>' << "\n"
95
+ end
96
+
97
+ visited.delete(call_tree)
98
+ end
99
+ output << '</li>' << "\n"
100
+ end
101
+
102
+ def name(call_tree)
103
+ method = call_tree.target
104
+ method.full_name
105
+ end
106
+
107
+ def link(method, recursive)
108
+ method_name = "#{recursive ? '*' : ''}#{method.full_name}"
109
+ if method.source_file.nil?
110
+ h method_name
111
+ else
112
+ file = File.expand_path(method.source_file)
113
+ "<a href=\"file://#{file}##{method.line}\">#{h method_name}</a>"
114
+ end
115
+ end
116
+
117
+ def graph_link(call_tree)
118
+ total_calls = call_tree.target.called
119
+ totals = total_calls.to_s
120
+ "[#{call_tree.called} calls, #{totals} total]"
121
+ end
122
+
123
+ def method_href(method)
124
+ h(method.full_name.gsub(/[><#\.\?=:]/,"_"))
125
+ end
126
+
127
+ def total_time(call_trees)
128
+ sum(call_trees.map{|ci| ci.total_time})
129
+ end
130
+
131
+ def sum(a)
132
+ a.inject(0.0){|s,t| s+=t}
133
+ end
134
+
135
+ def dump(ci)
136
+ $stderr.printf "%s/%d t:%f s:%f w:%f \n", ci, ci.object_id, ci.total_time, ci.self_time, ci.wait_time
137
+ end
138
+
139
+ def color(p)
140
+ case i = p.to_i
141
+ when 0..5
142
+ "01"
143
+ when 5..10
144
+ "05"
145
+ when 100
146
+ "9"
147
+ else
148
+ "#{i/10}"
149
+ end
150
+ end
151
+
152
+ attr_reader :application, :title, :threshold, :expansion
153
+
154
+ def arguments
155
+ ARGV.join(' ')
156
+ end
157
+
158
+ def base64_image
159
+ @data ||= begin
160
+ file = open_asset('call_stack_printer.png')
161
+ Base64.encode64(file).gsub(/\n/, '')
162
+ end
163
+ end
164
+
165
+ def template
166
+ open_asset('call_stack_printer.html.erb')
167
+ end
168
+ end
169
+ end
@@ -1,79 +1,78 @@
1
- # encoding: utf-8
2
-
3
- require 'erb'
4
- require 'json'
5
-
6
- module RubyProf
7
- # Prints a HTML flame graph visualization of the call tree.
8
- #
9
- # To use the printer:
10
- #
11
- # result = RubyProf.profile do
12
- # [code to profile]
13
- # end
14
- #
15
- # printer = RubyProf::FlameGraphPrinter.new(result)
16
- # printer.print(STDOUT)
17
-
18
- class FlameGraphPrinter < AbstractPrinter
19
- include ERB::Util
20
-
21
- # Specify print options.
22
- #
23
- # output - Any IO object, including STDOUT or a file.
24
- #
25
- # Keyword arguments:
26
- # title: - a String to override the default "ruby-prof flame graph"
27
- # title of the report.
28
- #
29
- # Also accepts min_percent:, max_percent:, filter_by:, and sort_method:
30
- # from AbstractPrinter.
31
- def print(output = STDOUT, title: "ruby-prof flame graph",
32
- min_percent: 0, max_percent: 100, filter_by: :self_time, sort_method: nil, **)
33
- @min_percent = min_percent
34
- @max_percent = max_percent
35
- @filter_by = filter_by
36
- @sort_method = sort_method
37
- @title = title
38
- output << ERB.new(self.template).result(binding)
39
- end
40
-
41
- attr_reader :title
42
-
43
- def build_flame_data(call_tree, visited = Set.new)
44
- node = {
45
- name: call_tree.target.full_name,
46
- value: call_tree.total_time,
47
- self_value: call_tree.self_time,
48
- called: call_tree.called,
49
- children: []
50
- }
51
-
52
- unless visited.include?(call_tree.target)
53
- visited.add(call_tree.target)
54
- call_tree.children.sort_by { |c| -c.total_time }.each do |child|
55
- node[:children] << build_flame_data(child, visited)
56
- end
57
- visited.delete(call_tree.target)
58
- end
59
-
60
- node
61
- end
62
-
63
- def flame_data_json
64
- threads = @result.threads.map do |thread|
65
- {
66
- id: thread.id,
67
- fiber_id: thread.fiber_id,
68
- total_time: thread.total_time,
69
- data: build_flame_data(thread.call_tree)
70
- }
71
- end
72
- JSON.generate(threads)
73
- end
74
-
75
- def template
76
- open_asset('flame_graph_printer.html.erb')
77
- end
78
- end
79
- end
1
+ # encoding: utf-8
2
+
3
+ require 'erb'
4
+ require 'json'
5
+
6
+ module RubyProf
7
+ # Prints a HTML flame graph visualization of the call tree.
8
+ #
9
+ # To use the printer:
10
+ #
11
+ # result = RubyProf.profile do
12
+ # [code to profile]
13
+ # end
14
+ #
15
+ # printer = RubyProf::FlameGraphPrinter.new(result)
16
+ # printer.print(STDOUT)
17
+
18
+ class FlameGraphPrinter < AbstractPrinter
19
+ include ERB::Util
20
+
21
+ # Specify print options.
22
+ #
23
+ # output - Any IO object, including STDOUT or a file.
24
+ #
25
+ # Keyword arguments:
26
+ # title: - a String to override the default "ruby-prof flame graph"
27
+ # title of the report.
28
+ #
29
+ # Also accepts min_percent:, max_percent:, filter_by:, and sort_method:
30
+ # from AbstractPrinter.
31
+ def print(output = STDOUT, title: "ruby-prof flame graph",
32
+ min_percent: 0, max_percent: 100, filter_by: :self_time, sort_method: nil, max_depth: nil, **)
33
+ @min_percent = min_percent
34
+ @max_percent = max_percent
35
+ @filter_by = filter_by
36
+ @sort_method = sort_method
37
+ @max_depth = max_depth
38
+ @title = title
39
+ output << ERB.new(self.template).result(binding)
40
+ end
41
+
42
+ attr_reader :title
43
+
44
+ def build_flame_data(call_tree, depth = 0)
45
+ node = {
46
+ name: call_tree.target.full_name,
47
+ value: call_tree.total_time,
48
+ self_value: call_tree.self_time,
49
+ called: call_tree.called,
50
+ children: []
51
+ }
52
+
53
+ if @max_depth.nil? || depth < @max_depth
54
+ call_tree.children.each do |child|
55
+ node[:children] << build_flame_data(child, depth + 1)
56
+ end
57
+ end
58
+
59
+ node
60
+ end
61
+
62
+ def flame_data_json
63
+ threads = @result.threads.map do |thread|
64
+ {
65
+ id: thread.id,
66
+ fiber_id: thread.fiber_id,
67
+ total_time: thread.total_time,
68
+ data: build_flame_data(thread.call_tree)
69
+ }
70
+ end
71
+ JSON.generate(threads)
72
+ end
73
+
74
+ def template
75
+ open_asset('flame_graph_printer.html.erb')
76
+ end
77
+ end
78
+ end
@@ -1,3 +1,3 @@
1
- module RubyProf
2
- VERSION = "2.0.2"
3
- end
1
+ module RubyProf
2
+ VERSION = "2.0.3"
3
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-prof
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shugo Maeda, Charlie Savage, Roger Pack, Stefan Kaes
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-02-17 00:00:00.000000000 Z
10
+ date: 2026-02-28 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: base64
@@ -236,7 +236,7 @@ metadata:
236
236
  bug_tracker_uri: https://github.com/ruby-prof/ruby-prof/issues
237
237
  changelog_uri: https://github.com/ruby-prof/ruby-prof/blob/master/CHANGELOG.md
238
238
  documentation_uri: https://ruby-prof.github.io/
239
- source_code_uri: https://github.com/ruby-prof/ruby-prof/tree/v2.0.2
239
+ source_code_uri: https://github.com/ruby-prof/ruby-prof/tree/v2.0.3
240
240
  rdoc_options: []
241
241
  require_paths:
242
242
  - lib