ruby-prof 1.4.3 → 1.6.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.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +59 -9
  3. data/{README.rdoc → README.md} +2 -2
  4. data/Rakefile +4 -4
  5. data/bin/ruby-prof +100 -87
  6. data/ext/ruby_prof/rp_allocation.c +140 -85
  7. data/ext/ruby_prof/rp_allocation.h +8 -6
  8. data/ext/ruby_prof/rp_call_tree.c +502 -369
  9. data/ext/ruby_prof/rp_call_tree.h +47 -43
  10. data/ext/ruby_prof/rp_call_trees.c +16 -8
  11. data/ext/ruby_prof/rp_measure_allocations.c +10 -13
  12. data/ext/ruby_prof/rp_measure_memory.c +8 -4
  13. data/ext/ruby_prof/rp_measure_process_time.c +7 -6
  14. data/ext/ruby_prof/rp_measurement.c +147 -20
  15. data/ext/ruby_prof/rp_measurement.h +4 -1
  16. data/ext/ruby_prof/rp_method.c +142 -83
  17. data/ext/ruby_prof/rp_method.h +63 -62
  18. data/ext/ruby_prof/rp_profile.c +933 -900
  19. data/ext/ruby_prof/rp_profile.h +1 -0
  20. data/ext/ruby_prof/rp_thread.c +433 -362
  21. data/ext/ruby_prof/rp_thread.h +39 -39
  22. data/ext/ruby_prof/ruby_prof.c +0 -2
  23. data/ext/ruby_prof/ruby_prof.h +8 -0
  24. data/ext/ruby_prof/vc/ruby_prof.vcxproj +11 -8
  25. data/lib/ruby-prof/assets/call_stack_printer.html.erb +2 -1
  26. data/lib/ruby-prof/compatibility.rb +14 -0
  27. data/lib/ruby-prof/method_info.rb +8 -1
  28. data/lib/ruby-prof/printers/abstract_printer.rb +2 -1
  29. data/lib/ruby-prof/printers/call_tree_printer.rb +4 -10
  30. data/lib/ruby-prof/printers/graph_html_printer.rb +1 -1
  31. data/lib/ruby-prof/printers/multi_printer.rb +17 -17
  32. data/lib/ruby-prof/profile.rb +70 -37
  33. data/lib/ruby-prof/rack.rb +31 -21
  34. data/lib/ruby-prof/version.rb +1 -1
  35. data/lib/ruby-prof.rb +1 -1
  36. data/ruby-prof.gemspec +2 -3
  37. data/test/abstract_printer_test.rb +1 -0
  38. data/test/alias_test.rb +97 -106
  39. data/test/call_tree_builder.rb +126 -0
  40. data/test/call_tree_test.rb +94 -0
  41. data/test/call_tree_visitor_test.rb +1 -6
  42. data/test/call_trees_test.rb +6 -6
  43. data/test/{basic_test.rb → compatibility_test.rb} +8 -2
  44. data/test/duplicate_names_test.rb +5 -5
  45. data/test/dynamic_method_test.rb +24 -15
  46. data/test/enumerable_test.rb +1 -1
  47. data/test/exceptions_test.rb +2 -2
  48. data/test/exclude_methods_test.rb +3 -8
  49. data/test/exclude_threads_test.rb +4 -9
  50. data/test/fiber_test.rb +74 -8
  51. data/test/gc_test.rb +11 -9
  52. data/test/inverse_call_tree_test.rb +33 -34
  53. data/test/line_number_test.rb +37 -61
  54. data/test/marshal_test.rb +16 -3
  55. data/test/measure_allocations.rb +1 -5
  56. data/test/measure_allocations_test.rb +642 -357
  57. data/test/{measure_memory_trace_test.rb → measure_memory_test.rb} +180 -616
  58. data/test/measure_process_time_test.rb +1566 -741
  59. data/test/measure_wall_time_test.rb +179 -193
  60. data/test/measurement_test.rb +82 -0
  61. data/test/merge_test.rb +146 -0
  62. data/test/method_info_test.rb +95 -0
  63. data/test/multi_printer_test.rb +0 -5
  64. data/test/no_method_class_test.rb +1 -1
  65. data/test/pause_resume_test.rb +12 -16
  66. data/test/printer_call_stack_test.rb +2 -2
  67. data/test/printer_call_tree_test.rb +4 -4
  68. data/test/printer_flat_test.rb +1 -1
  69. data/test/printer_graph_html_test.rb +2 -2
  70. data/test/printer_graph_test.rb +2 -2
  71. data/test/printers_test.rb +14 -20
  72. data/test/printing_recursive_graph_test.rb +2 -2
  73. data/test/profile_test.rb +85 -0
  74. data/test/recursive_test.rb +374 -155
  75. data/test/scheduler.rb +363 -0
  76. data/test/singleton_test.rb +1 -1
  77. data/test/stack_printer_test.rb +5 -8
  78. data/test/start_stop_test.rb +11 -14
  79. data/test/test_helper.rb +11 -8
  80. data/test/thread_test.rb +106 -15
  81. data/test/unique_call_path_test.rb +28 -12
  82. data/test/yarv_test.rb +11 -7
  83. metadata +17 -29
  84. data/ext/ruby_prof/rp_aggregate_call_tree.c +0 -59
  85. data/ext/ruby_prof/rp_aggregate_call_tree.h +0 -13
  86. data/test/measure_allocations_trace_test.rb +0 -375
  87. data/test/temp.rb +0 -20
@@ -1,39 +1,39 @@
1
- /* Copyright (C) 2005-2019 Shugo Maeda <shugo@ruby-lang.org> and Charlie Savage <cfis@savagexi.com>
2
- Please see the LICENSE file for copyright and distribution information */
3
-
4
- #ifndef __RP_THREAD__
5
- #define __RP_THREAD__
6
-
7
- #include "ruby_prof.h"
8
- #include "rp_stack.h"
9
-
10
- /* Profiling information for a thread. */
11
- typedef struct thread_data_t
12
- {
13
- // Runtime
14
- VALUE object; /* Cache to wrapped object */
15
- VALUE fiber; /* Fiber */
16
- prof_stack_t* stack; /* Stack of frames */
17
- bool trace; /* Are we tracking this thread */
18
- prof_call_tree_t* call_tree; /* The root of the call tree*/
19
- VALUE thread_id; /* Thread id */
20
- VALUE fiber_id; /* Fiber id */
21
- VALUE methods; /* Array of RubyProf::MethodInfo */
22
- st_table* method_table; /* Methods called in the thread */
23
- } thread_data_t;
24
-
25
- void rp_init_thread(void);
26
- st_table* threads_table_create(void);
27
- thread_data_t* threads_table_lookup(void* profile, VALUE fiber);
28
- thread_data_t* threads_table_insert(void* profile, VALUE fiber);
29
- void threads_table_free(st_table* table);
30
-
31
- thread_data_t* prof_get_thread(VALUE self);
32
- VALUE prof_thread_wrap(thread_data_t* thread);
33
- void prof_thread_mark(void* data);
34
-
35
- void switch_thread(void* profile, thread_data_t* thread_data, double measurement);
36
- int pause_thread(st_data_t key, st_data_t value, st_data_t data);
37
- int unpause_thread(st_data_t key, st_data_t value, st_data_t data);
38
-
39
- #endif //__RP_THREAD__
1
+ /* Copyright (C) 2005-2019 Shugo Maeda <shugo@ruby-lang.org> and Charlie Savage <cfis@savagexi.com>
2
+ Please see the LICENSE file for copyright and distribution information */
3
+
4
+ #ifndef __RP_THREAD__
5
+ #define __RP_THREAD__
6
+
7
+ #include "ruby_prof.h"
8
+ #include "rp_stack.h"
9
+
10
+ /* Profiling information for a thread. */
11
+ typedef struct thread_data_t
12
+ {
13
+ prof_owner_t owner; /* Who owns this object */
14
+ VALUE object; /* Cache to wrapped object */
15
+ VALUE fiber; /* Fiber */
16
+ prof_stack_t* stack; /* Stack of frames */
17
+ bool trace; /* Are we tracking this thread */
18
+ prof_call_tree_t* call_tree; /* The root of the call tree*/
19
+ VALUE thread_id; /* Thread id */
20
+ VALUE fiber_id; /* Fiber id */
21
+ VALUE methods; /* Array of RubyProf::MethodInfo */
22
+ st_table* method_table; /* Methods called in the thread */
23
+ } thread_data_t;
24
+
25
+ void rp_init_thread(void);
26
+ st_table* threads_table_create(void);
27
+ thread_data_t* threads_table_lookup(void* profile, VALUE fiber);
28
+ thread_data_t* threads_table_insert(void* profile, VALUE fiber);
29
+ void threads_table_free(st_table* table);
30
+
31
+ thread_data_t* prof_get_thread(VALUE self);
32
+ VALUE prof_thread_wrap(thread_data_t* thread);
33
+ void prof_thread_mark(void* data);
34
+
35
+ void switch_thread(void* profile, thread_data_t* thread_data, double measurement);
36
+ int pause_thread(st_data_t key, st_data_t value, st_data_t data);
37
+ int unpause_thread(st_data_t key, st_data_t value, st_data_t data);
38
+
39
+ #endif //__RP_THREAD__
@@ -29,7 +29,6 @@
29
29
  #include "rp_measurement.h"
30
30
  #include "rp_method.h"
31
31
  #include "rp_call_tree.h"
32
- #include "rp_aggregate_call_tree.h"
33
32
  #include "rp_call_trees.h"
34
33
  #include "rp_profile.h"
35
34
  #include "rp_stack.h"
@@ -43,7 +42,6 @@ void Init_ruby_prof()
43
42
 
44
43
  rp_init_allocation();
45
44
  rp_init_call_tree();
46
- rp_init_aggregate_call_tree();
47
45
  rp_init_call_trees();
48
46
  rp_init_measure();
49
47
  rp_init_method_info();
@@ -23,4 +23,12 @@ extern VALUE mProf;
23
23
  // This method is not exposed in Ruby header files - at least not as of Ruby 2.6.3 :(
24
24
  extern size_t rb_obj_memsize_of(VALUE);
25
25
 
26
+ typedef enum
27
+ {
28
+ OWNER_UNKNOWN = 0,
29
+ OWNER_RUBY = 1,
30
+ OWNER_C = 2
31
+ } prof_owner_t;
32
+
33
+
26
34
  #endif //__RUBY_PROF_H__
@@ -29,19 +29,21 @@
29
29
  <ConfigurationType>DynamicLibrary</ConfigurationType>
30
30
  <UseDebugLibraries>true</UseDebugLibraries>
31
31
  <CharacterSet>Unicode</CharacterSet>
32
+ <PlatformToolset>v143</PlatformToolset>
32
33
  </PropertyGroup>
33
34
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
34
35
  <ConfigurationType>DynamicLibrary</ConfigurationType>
35
36
  <UseDebugLibraries>false</UseDebugLibraries>
36
37
  <WholeProgramOptimization>true</WholeProgramOptimization>
37
38
  <CharacterSet>Unicode</CharacterSet>
39
+ <PlatformToolset>v143</PlatformToolset>
38
40
  </PropertyGroup>
39
41
  <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
40
- <PlatformToolset>v142</PlatformToolset>
42
+ <PlatformToolset>v143</PlatformToolset>
41
43
  <ConfigurationType>DynamicLibrary</ConfigurationType>
42
44
  </PropertyGroup>
43
45
  <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
44
- <PlatformToolset>v142</PlatformToolset>
46
+ <PlatformToolset>v143</PlatformToolset>
45
47
  </PropertyGroup>
46
48
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
47
49
  <ImportGroup Label="ExtensionSettings">
@@ -64,7 +66,7 @@
64
66
  </PropertyGroup>
65
67
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
66
68
  <TargetExt>.so</TargetExt>
67
- <OutDir>..\..\..\lib\</OutDir>
69
+ <OutDir>$(SolutionDir)\..</OutDir>
68
70
  </PropertyGroup>
69
71
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
70
72
  <ClCompile>
@@ -102,17 +104,20 @@
102
104
  </ItemDefinitionGroup>
103
105
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
104
106
  <ClCompile>
105
- <AdditionalIncludeDirectories>C:\msys64\usr\local\ruby-2.7.2vc\include\ruby-2.7.0\x64-mswin64_140;C:\msys64\usr\local\ruby-2.7.2vc\include\ruby-2.7.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
107
+ <AdditionalIncludeDirectories>C:\msys64\usr\local\ruby-3.2.1-vc\include\ruby-3.2.0\x64-mswin64_140;C:\msys64\usr\local\ruby-3.2.1-vc\include\ruby-3.2.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
106
108
  <Optimization>Disabled</Optimization>
107
109
  <PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
108
110
  <WarningLevel>Level3</WarningLevel>
109
111
  </ClCompile>
110
112
  <Link>
111
- <AdditionalLibraryDirectories>C:\msys64\usr\local\ruby-2.7.2vc\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
112
- <AdditionalDependencies>x64-vcruntime140-ruby270.lib;%(AdditionalDependencies)</AdditionalDependencies>
113
+ <AdditionalLibraryDirectories>C:\msys64\usr\local\ruby-3.2.1-vc\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
114
+ <AdditionalDependencies>x64-vcruntime140-ruby320.lib;%(AdditionalDependencies)</AdditionalDependencies>
113
115
  <ModuleDefinitionFile>ruby_prof.def</ModuleDefinitionFile>
114
116
  <SubSystem>Console</SubSystem>
115
117
  </Link>
118
+ <ProjectReference>
119
+ <LinkLibraryDependencies>false</LinkLibraryDependencies>
120
+ </ProjectReference>
116
121
  </ItemDefinitionGroup>
117
122
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
118
123
  <ClCompile>
@@ -125,7 +130,6 @@
125
130
  </Link>
126
131
  </ItemDefinitionGroup>
127
132
  <ItemGroup>
128
- <ClInclude Include="..\rp_aggregate_call_tree.h" />
129
133
  <ClInclude Include="..\rp_allocation.h" />
130
134
  <ClInclude Include="..\rp_call_tree.h" />
131
135
  <ClInclude Include="..\rp_call_trees.h" />
@@ -137,7 +141,6 @@
137
141
  <ClInclude Include="..\ruby_prof.h" />
138
142
  </ItemGroup>
139
143
  <ItemGroup>
140
- <ClCompile Include="..\rp_aggregate_call_tree.c" />
141
144
  <ClCompile Include="..\rp_allocation.c" />
142
145
  <ClCompile Include="..\rp_call_tree.c" />
143
146
  <ClCompile Include="..\rp_call_trees.c" />
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
5
5
  <title>ruby-prof call tree</title>
6
- <style type="text/css">
6
+ <style>
7
7
  body {
8
8
  font-size: 70%;
9
9
  padding: 0;
@@ -19,6 +19,7 @@
19
19
  margin-bottom: 0px;
20
20
  padding-left: 0px;
21
21
  list-style-type: none;
22
+ font-weight: normal;
22
23
  }
23
24
 
24
25
  li {
@@ -96,4 +96,18 @@ module RubyProf
96
96
  def self.ensure_not_running!
97
97
  raise(RuntimeError, "RubyProf is already running") if running?
98
98
  end
99
+
100
+ class << self
101
+ extend Gem::Deprecate
102
+ deprecate :measure_mode, "Profile#measure_mode", 2023, 6
103
+ deprecate :measure_mode=, "Profile#measure_mode=", 2023, 6
104
+ deprecate :exclude_threads, "Profile#exclude_threads", 2023, 6
105
+ deprecate :exclude_threads=, "Profile#initialize", 2023, 6
106
+ deprecate :start, "Profile#start", 2023, 6
107
+ deprecate :pause, "Profile#pause", 2023, 6
108
+ deprecate :stop, "Profile#stop", 2023, 6
109
+ deprecate :resume, "Profile#resume", 2023, 6
110
+ deprecate :running?, "Profile#running?", 2023, 6
111
+ deprecate :profile, "Profile.profile", 2023, 6
112
+ end
99
113
  end
@@ -52,7 +52,14 @@ module RubyProf
52
52
  self.total_time - self.self_time - self.wait_time
53
53
  end
54
54
 
55
- # :enddoc:
55
+ def eql?(other)
56
+ self.hash == other.hash
57
+ end
58
+
59
+ def ==(other)
60
+ self.eql?(other)
61
+ end
62
+
56
63
  def <=>(other)
57
64
  if other.nil?
58
65
  -1
@@ -50,7 +50,7 @@ module RubyProf
50
50
  # options - Hash of print options. Note that each printer can
51
51
  # define its own set of options.
52
52
  #
53
- # :min_percent - Number 0 to 100 that specifes the minimum
53
+ # :min_percent - Number 0 to 100 that specifies the minimum
54
54
  # %self (the methods self time divided by the
55
55
  # overall total time) that a method must take
56
56
  # for it to be printed out in the report.
@@ -131,6 +131,7 @@ module RubyProf
131
131
 
132
132
  * MyObject#test - An instance method "test" of the class "MyObject"
133
133
  * <Object:MyObject>#test - The <> characters indicate a method on a singleton class.
134
+
134
135
  EOT
135
136
  end
136
137
  end
@@ -27,7 +27,7 @@ module RubyProf
27
27
 
28
28
  def determine_event_specification_and_value_scale
29
29
  @event_specification = "events: "
30
- case RubyProf.measure_mode
30
+ case @result.measure_mode
31
31
  when RubyProf::PROCESS_TIME
32
32
  @value_scale = RubyProf::CLOCKS_PER_SEC
33
33
  @event_specification << 'process_time'
@@ -68,8 +68,6 @@ module RubyProf
68
68
 
69
69
  def print_threads
70
70
  remove_subsidiary_files_from_previous_profile_runs
71
- # TODO: merge fibers of a given thread here, instead of relying
72
- # on the profiler to merge fibers.
73
71
  @result.threads.each do |thread|
74
72
  print_thread(thread)
75
73
  end
@@ -100,21 +98,17 @@ module RubyProf
100
98
  true
101
99
  end
102
100
 
103
- def base_name
104
- @options[:profile] || "profile"
105
- end
106
-
107
101
  def remove_subsidiary_files_from_previous_profile_runs
108
- pattern = [base_name, "callgrind.out", $$, "*"].join(".")
102
+ pattern = ["callgrind.out", $$, "*"].join(".")
109
103
  files = Dir.glob(File.join(path, pattern))
110
104
  FileUtils.rm_f(files)
111
105
  end
112
106
 
113
107
  def file_name_for_thread(thread)
114
108
  if thread.fiber_id == Fiber.current.object_id
115
- [base_name, "callgrind.out", $$].join(".")
109
+ ["callgrind.out", $$].join(".")
116
110
  else
117
- [base_name, "callgrind.out", $$, thread.fiber_id].join(".")
111
+ ["callgrind.out", $$, thread.fiber_id].join(".")
118
112
  end
119
113
  end
120
114
 
@@ -29,7 +29,7 @@ module RubyProf
29
29
  end
30
30
 
31
31
  # Creates a link to a method. Note that we do not create
32
- # links to methods which are under the min_perecent
32
+ # links to methods which are under the min_percent
33
33
  # specified by the user, since they will not be
34
34
  # printed out.
35
35
  def create_link(thread, overall_time, method)
@@ -6,16 +6,16 @@ module RubyProf
6
6
  # profile, a call stack profile and a graph profile.
7
7
  class MultiPrinter
8
8
  def initialize(result, printers = [:flat, :graph_html])
9
- @flat_printer = FlatPrinter.new(result) if printers.include?(:flat)
9
+ @flat_printer = printers.include?(:flat) ? FlatPrinter.new(result) : nil
10
10
 
11
- @graph_printer = GraphPrinter.new(result) if printers.include?(:graph)
12
- @graph_html_printer = GraphHtmlPrinter.new(result) if printers.include?(:graph_html)
11
+ @graph_printer = printers.include?(:graph) ? GraphPrinter.new(result) : nil
12
+ @graph_html_printer = printers.include?(:graph_html) ? GraphHtmlPrinter.new(result) : nil
13
13
 
14
- @tree_printer = CallTreePrinter.new(result) if printers.include?(:tree)
15
- @call_info_printer = CallInfoPrinter.new(result) if printers.include?(:call_tree)
14
+ @tree_printer = printers.include?(:tree) ? CallTreePrinter.new(result) : nil
15
+ @call_info_printer = printers.include?(:call_tree) ? CallInfoPrinter.new(result) : nil
16
16
 
17
- @stack_printer = CallStackPrinter.new(result) if printers.include?(:stack)
18
- @dot_printer = DotPrinter.new(result) if printers.include?(:dot)
17
+ @stack_printer = printers.include?(:stack) ? CallStackPrinter.new(result) : nil
18
+ @dot_printer = printers.include?(:dot) ? DotPrinter.new(result) : nil
19
19
  end
20
20
 
21
21
  def self.needs_dir?
@@ -28,7 +28,7 @@ module RubyProf
28
28
  def print(options)
29
29
  validate_print_params(options)
30
30
 
31
- @profile = options.delete(:profile) || "profile"
31
+ @file_name = options.delete(:profile) || "profile"
32
32
  @directory = options.delete(:path) || File.expand_path(".")
33
33
 
34
34
  print_to_flat(options) if @flat_printer
@@ -44,36 +44,36 @@ module RubyProf
44
44
 
45
45
  # the name of the flat profile file
46
46
  def flat_report
47
- "#{@directory}/#{@profile}.flat.txt"
47
+ "#{@directory}/#{@file_name}.flat.txt"
48
48
  end
49
49
 
50
50
  # the name of the graph profile file
51
51
  def graph_report
52
- "#{@directory}/#{@profile}.graph.txt"
52
+ "#{@directory}/#{@file_name}.graph.txt"
53
53
  end
54
54
 
55
55
  def graph_html_report
56
- "#{@directory}/#{@profile}.graph.html"
56
+ "#{@directory}/#{@file_name}.graph.html"
57
57
  end
58
58
 
59
59
  # the name of the callinfo profile file
60
60
  def call_info_report
61
- "#{@directory}/#{@profile}.call_tree.txt"
61
+ "#{@directory}/#{@file_name}.call_tree.txt"
62
62
  end
63
63
 
64
64
  # the name of the callgrind profile file
65
65
  def tree_report
66
- "#{@directory}/#{@profile}.callgrind.out.#{$$}"
66
+ "#{@directory}/#{@file_name}.callgrind.out.#{$$}"
67
67
  end
68
68
 
69
69
  # the name of the call stack profile file
70
70
  def stack_report
71
- "#{@directory}/#{@profile}.stack.html"
71
+ "#{@directory}/#{@file_name}.stack.html"
72
72
  end
73
73
 
74
74
  # the name of the call stack profile file
75
75
  def dot_report
76
- "#{@directory}/#{@profile}.dot"
76
+ "#{@directory}/#{@file_name}.dot"
77
77
  end
78
78
 
79
79
  def print_to_flat(options)
@@ -101,12 +101,12 @@ module RubyProf
101
101
  end
102
102
 
103
103
  def print_to_tree(options)
104
- @tree_printer.print(options.merge(:path => @directory, :profile => @profile))
104
+ @tree_printer.print(options.merge(:path => @directory, :profile => @file_name))
105
105
  end
106
106
 
107
107
  def print_to_stack(options)
108
108
  File.open(stack_report, "wb") do |file|
109
- @stack_printer.print(file, options.merge(:graph => "#{@profile}.graph.html"))
109
+ @stack_printer.print(file, options.merge(:graph => "#{@file_name}.graph.html"))
110
110
  end
111
111
  end
112
112
 
@@ -1,37 +1,70 @@
1
- # encoding: utf-8
2
-
3
- require 'ruby-prof/exclude_common_methods'
4
-
5
- module RubyProf
6
- class Profile
7
- # :nodoc:
8
- def measure_mode_string
9
- case self.measure_mode
10
- when WALL_TIME
11
- "wall_time"
12
- when PROCESS_TIME
13
- "process_time"
14
- when ALLOCATIONS
15
- "allocations"
16
- when MEMORY
17
- "memory"
18
- end
19
- end
20
-
21
- # Hides methods that, when represented as a call graph, have
22
- # extremely large in and out degrees and make navigation impossible.
23
- def exclude_common_methods!
24
- ExcludeCommonMethods.apply!(self)
25
- end
26
-
27
- def exclude_methods!(mod, *method_or_methods)
28
- [method_or_methods].flatten.each do |name|
29
- exclude_method!(mod, name)
30
- end
31
- end
32
-
33
- def exclude_singleton_methods!(mod, *method_or_methods)
34
- exclude_methods!(mod.singleton_class, *method_or_methods)
35
- end
36
- end
37
- end
1
+ # encoding: utf-8
2
+
3
+ require 'ruby-prof/exclude_common_methods'
4
+
5
+ module RubyProf
6
+ class Profile
7
+ def measure_mode_string
8
+ case self.measure_mode
9
+ when WALL_TIME
10
+ "wall_time"
11
+ when PROCESS_TIME
12
+ "process_time"
13
+ when ALLOCATIONS
14
+ "allocations"
15
+ when MEMORY
16
+ "memory"
17
+ end
18
+ end
19
+
20
+ # Hides methods that, when represented as a call graph, have
21
+ # extremely large in and out degrees and make navigation impossible.
22
+ def exclude_common_methods!
23
+ ExcludeCommonMethods.apply!(self)
24
+ end
25
+
26
+ def exclude_methods!(mod, *method_names)
27
+ [method_names].flatten.each do |method_name|
28
+ exclude_method!(mod, method_name)
29
+ end
30
+ end
31
+
32
+ def exclude_singleton_methods!(mod, *method_names)
33
+ exclude_methods!(mod.singleton_class, *method_names)
34
+ end
35
+
36
+ # call-seq:
37
+ # merge! -> self
38
+ #
39
+ # Merges RubyProf threads whose root call_trees reference the same target method. This is useful
40
+ # when profiling code that uses a main thread/fiber to distribute work to multiple workers.
41
+ # If there are tens or hundreds of workers, viewing results per worker thread/fiber can be
42
+ # overwhelming. Using +merge!+ will combine the worker times together into one result.
43
+ #
44
+ # Note the reported time will be much greater than the actual wall time. For example, if there
45
+ # are 10 workers that each run for 5 seconds, merged results will show one thread that
46
+ # ran for 50 seconds.
47
+ #
48
+ def merge!
49
+ # First group threads by their root call tree target (method). If the methods are
50
+ # different than there is nothing to merge
51
+ grouped = threads.group_by do |thread|
52
+ thread.call_tree.target
53
+ end
54
+
55
+ # For each target, get the first thread. Then loop over the remaining threads,
56
+ # and merge them into the first one and ten delete them. So we will be left with
57
+ # one thread per target.
58
+ grouped.each do |target, threads|
59
+ thread = threads.shift
60
+ threads.each do |other_thread|
61
+ thread.merge!(other_thread)
62
+ remove_thread(other_thread)
63
+ end
64
+ thread
65
+ end
66
+
67
+ self
68
+ end
69
+ end
70
+ end
@@ -6,7 +6,6 @@ module Rack
6
6
  def initialize(app, options = {})
7
7
  @app = app
8
8
  @options = options
9
- @options[:min_percent] ||= 1
10
9
 
11
10
  @tmpdir = options[:path] || Dir.tmpdir
12
11
  FileUtils.mkdir_p(@tmpdir)
@@ -26,14 +25,19 @@ module Rack
26
25
  if should_profile?(request.path)
27
26
  begin
28
27
  result = nil
29
- data = ::RubyProf::Profile.profile(profiling_options) do
28
+ profile = ::RubyProf::Profile.profile(profiling_options) do
30
29
  result = @app.call(env)
31
30
  end
32
31
 
32
+ if @options[:merge_fibers]
33
+ profile.merge!
34
+ end
35
+
36
+
33
37
  path = request.path.gsub('/', '-')
34
38
  path.slice!(0)
35
39
 
36
- print(data, path)
40
+ print(profile, path)
37
41
  result
38
42
  end
39
43
  else
@@ -54,39 +58,45 @@ module Rack
54
58
  end
55
59
 
56
60
  def profiling_options
57
- options = {}
58
- options[:measure_mode] = ::RubyProf.measure_mode
59
- options[:exclude_threads] =
60
- if @options[:ignore_existing_threads]
61
- Thread.list.select{|t| t != Thread.current}
62
- else
63
- ::RubyProf.exclude_threads
64
- end
65
- if @options[:request_thread_only]
66
- options[:include_threads] = [Thread.current]
61
+ result = {}
62
+ result[:measure_mode] = @options[:measure_mode] || ::RubyProf::WALL_TIME
63
+ result[:track_allocations] = @options[:track_allocations] || false
64
+ result[:exclude_common] = @options[:exclude_common] || false
65
+
66
+ if @options[:ignore_existing_threads]
67
+ result[:exclude_threads] = Thread.list.select {|thread| thread != Thread.current}
67
68
  end
68
- if @options[:merge_fibers]
69
- options[:merge_fibers] = true
69
+
70
+ if @options[:request_thread_only]
71
+ result[:include_threads] = [Thread.current]
70
72
  end
71
- options
73
+
74
+ result
75
+ end
76
+
77
+ def print_options
78
+ result = {}
79
+ result[:min_percent] = @options[:min_percent] || 1
80
+ result[:sort_method] = @options[:sort_method] || :total_time
81
+ result
72
82
  end
73
83
 
74
- def print(data, path)
84
+ def print(profile, path)
75
85
  @printer_klasses.each do |printer_klass, base_name|
76
- printer = printer_klass.new(data)
86
+ printer = printer_klass.new(profile)
77
87
 
78
88
  if base_name.respond_to?(:call)
79
89
  base_name = base_name.call
80
90
  end
81
91
 
82
92
  if printer_klass == ::RubyProf::MultiPrinter
83
- printer.print(@options.merge(:profile => "#{path}-#{base_name}"))
93
+ printer.print(print_options.merge(:profile => "#{path}-#{base_name}"))
84
94
  elsif printer_klass == ::RubyProf::CallTreePrinter
85
- printer.print(@options.merge(:profile => "#{path}-#{base_name}"))
95
+ printer.print(print_options.merge(:profile => "#{path}-#{base_name}"))
86
96
  else
87
97
  file_name = ::File.join(@tmpdir, "#{path}-#{base_name}")
88
98
  ::File.open(file_name, 'wb') do |file|
89
- printer.print(file, @options)
99
+ printer.print(file, print_options)
90
100
  end
91
101
  end
92
102
  end
@@ -1,3 +1,3 @@
1
1
  module RubyProf
2
- VERSION = "1.4.3"
2
+ VERSION = "1.6.3"
3
3
  end
data/lib/ruby-prof.rb CHANGED
@@ -6,7 +6,7 @@ begin
6
6
  version = Gem::Version.new(RUBY_VERSION)
7
7
  require "#{version.segments[0..1].join('.')}/ruby_prof.so"
8
8
  rescue LoadError
9
- require_relative "../ext/ruby_prof/ruby_prof.so"
9
+ require "ruby_prof.so"
10
10
  end
11
11
 
12
12
  require 'ruby-prof/version'
data/ruby-prof.gemspec CHANGED
@@ -36,7 +36,7 @@ EOF
36
36
  spec.files = Dir['CHANGES',
37
37
  'LICENSE',
38
38
  'Rakefile',
39
- 'README.rdoc',
39
+ 'README.md',
40
40
  'ruby-prof.gemspec',
41
41
  'bin/ruby-prof',
42
42
  'bin/ruby-prof-check-trace',
@@ -56,10 +56,9 @@ EOF
56
56
  'test/*.rb']
57
57
 
58
58
  spec.test_files = Dir["test/test_*.rb"]
59
- spec.required_ruby_version = '>= 2.5.0'
59
+ spec.required_ruby_version = '>= 2.7.0'
60
60
  spec.date = Time.now.strftime('%Y-%m-%d')
61
61
  spec.homepage = 'https://github.com/ruby-prof/ruby-prof'
62
62
  spec.add_development_dependency('minitest')
63
63
  spec.add_development_dependency('rake-compiler')
64
- spec.add_development_dependency('rdoc')
65
64
  end
@@ -5,6 +5,7 @@ require File.expand_path('../test_helper', __FILE__)
5
5
 
6
6
  class AbstractPrinterTest < TestCase
7
7
  def setup
8
+ super
8
9
  @result = {}
9
10
  @printer = RubyProf::AbstractPrinter.new(@result)
10
11
  @options = {}