ruby-prof 1.3.1-x64-mingw32 → 1.4.0-x64-mingw32

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 806c0eb4c670c555d8db93891b8463b252c01d4ecc53352007d52faab3dc189a
4
- data.tar.gz: 104d4c36f8b6c983197dd1f24241033f53357d50d6f8c04082e9ca8de28e3dca
3
+ metadata.gz: 412103d1d1140848e4e171d010d603e98753a561ee75e62f217013e46848ac64
4
+ data.tar.gz: 686d22e4138b8fbe4a03f9ba8bfcd1e5523671fb5b4a3f46029676339a2736b8
5
5
  SHA512:
6
- metadata.gz: 6f7f2a47b1d91fe60796abf2a7c3889232753be3ed44d8639199749cc6d620ea688b99145a52522f25f6ad7d997ed16afd17118fc93893a9c50bd9e614c5b74a
7
- data.tar.gz: 554417600fb7e354648f24cabf27ccd122070772bef65900c8e26e62e2fb575f39aa8208ad3bf7ef5e7f0100701ed78c22306e9e61bce770cd9c970d525be979
6
+ metadata.gz: 374122cf537066f530a7df115941ba2d184229e9d88614ee5901430950d8d87b354fae3faddf9ebdf1fc5b7899b553892f9fa5604a559adc7ad336fb0db36b52
7
+ data.tar.gz: '058817625f1294f32d1aaba1dcc5f607d9375ec85177f69461be92a9fda972765f211e2d385514360779d6a034f15b4966de082c22d8017a3889c2a856aadd3b'
data/CHANGES CHANGED
@@ -1,3 +1,15 @@
1
+ 1.4.0 (2020-05-12)
2
+ =====================
3
+ * API change - remove merge_fibers support since it resulted in incorrect results or crashes (Charlie Savage)
4
+ * Fix crash when profiling memory usage (Charlie Savage)
5
+ * When tracing execution correctly print out newobj tracepoint events (Charlie Savage)
6
+ * Remove no longer needed code for building extensions (Charlie Savage)
7
+
8
+ 1.3.2 (2020-04-19)
9
+ =====================
10
+ * Fix rack profiler so it is thread safe (Charlie Savage)
11
+ * Fix loading of prebuilt binaries on mingw64 to use Ruby's major and minor version (Charlie Savage)
12
+
1
13
  1.3.1 (2020-03-11)
2
14
  =====================
3
15
  * Add max_percent and filter_by options to flat printer (Sean McGivern)
data/Rakefile CHANGED
@@ -38,9 +38,9 @@ Rake::ExtensionTask.new do |ext|
38
38
  ext.gem_spec = default_spec
39
39
  ext.name = SO_NAME
40
40
  ext.ext_dir = "ext/#{SO_NAME}"
41
- ext.lib_dir = "lib/#{RUBY_VERSION}"
41
+ ext.lib_dir = "lib/#{Gem::Version.new(RUBY_VERSION).segments[0..1].join('.')}"
42
42
  ext.cross_compile = true
43
- ext.cross_platform = ['x86-mingw32', 'x64-mingw32']
43
+ ext.cross_platform = ['x64-mingw32']
44
44
  end
45
45
 
46
46
  # Rake task to build the default package
@@ -58,7 +58,6 @@ if RUBY_PLATFORM.match(/win32|mingw32/)
58
58
  win_spec = default_spec.clone
59
59
  win_spec.platform = Gem::Platform::CURRENT
60
60
  win_spec.files += Dir.glob('lib/**/*.so')
61
- win_spec.instance_variable_set(:@cache_file, nil) # Hack to work around gem issue
62
61
 
63
62
  # Unset extensions
64
63
  win_spec.extensions = nil
@@ -1,35 +1,5 @@
1
1
  require "mkmf"
2
2
 
3
- if RUBY_ENGINE != "ruby"
4
- STDERR.puts("\n\n***** This gem is MRI-specific. It does not support #{RUBY_ENGINE}. *****\n\n")
5
- exit(1)
6
- end
7
-
8
- if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.4.0')
9
- STDERR.puts("\n\n***** Ruby version #{RUBY_VERSION} is no longer supported. Please upgrade to 2.3 or higher. *****\n\n")
10
- exit(1)
11
- end
12
-
13
- # For the love of bitfields...
14
- $CFLAGS += ' -std=c99'
15
-
16
- # And since we are using C99
17
- CONFIG['warnflags'].gsub!('-Wdeclaration-after-statement', '')
18
-
19
- def add_define(name, value = nil)
20
- if value
21
- $defs.push("-D#{name}=#{value}")
22
- else
23
- $defs.push("-D#{name}")
24
- end
25
- end
26
-
27
- def windows?
28
- RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
29
- end
30
-
31
- add_define("RUBY_PROF_RUBY_VERSION", RUBY_VERSION.split('.')[0..2].inject(0){|v,d| v*100+d.to_i})
32
-
33
3
  # This function was added in Ruby 2.5, so once Ruby 2.4 is no longer supported this can be removed
34
4
  have_func('rb_tracearg_callee_id', ["ruby.h"])
35
5
 
@@ -219,7 +219,7 @@ VALUE prof_call_trees_callers(VALUE self)
219
219
  }
220
220
  }
221
221
 
222
- VALUE result = rb_ary_new_capa(callers->num_entries);
222
+ VALUE result = rb_ary_new_capa((long)callers->num_entries);
223
223
  rb_st_foreach(callers, prof_call_trees_collect_aggregates, result);
224
224
  rb_st_free_table(callers);
225
225
  return result;
@@ -239,7 +239,7 @@ VALUE prof_call_trees_callees(VALUE self)
239
239
  rb_st_foreach((*call_tree)->children, prof_call_trees_collect_callees, (st_data_t)callees);
240
240
  }
241
241
 
242
- VALUE result = rb_ary_new_capa(callees->num_entries);
242
+ VALUE result = rb_ary_new_capa((long)callees->num_entries);
243
243
  rb_st_foreach(callees, prof_call_trees_collect_aggregates, result);
244
244
  rb_st_free_table(callees);
245
245
  return result;
@@ -10,7 +10,7 @@ VALUE total_allocated_objects_key;
10
10
 
11
11
  static double measure_allocations_via_gc_stats(rb_trace_arg_t* trace_arg)
12
12
  {
13
- return rb_gc_stat(total_allocated_objects_key);
13
+ return (double)rb_gc_stat(total_allocated_objects_key);
14
14
  }
15
15
 
16
16
  static double measure_allocations_via_tracing(rb_trace_arg_t* trace_arg)
@@ -24,7 +24,7 @@ static double measure_process_time(rb_trace_arg_t* trace_arg)
24
24
  userTimeInt.LowPart = userTime.dwLowDateTime;
25
25
  userTimeInt.HighPart = userTime.dwHighDateTime;
26
26
 
27
- return sysTimeInt.QuadPart + userTimeInt.QuadPart;
27
+ return (double)(sysTimeInt.QuadPart + userTimeInt.QuadPart);
28
28
  #elif !defined(CLOCK_PROCESS_CPUTIME_ID)
29
29
  struct rusage usage;
30
30
  getrusage(RUSAGE_SELF, &usage);
@@ -17,7 +17,7 @@ static double measure_wall_time(rb_trace_arg_t* trace_arg)
17
17
  #if defined(_WIN32)
18
18
  LARGE_INTEGER time;
19
19
  QueryPerformanceCounter(&time);
20
- return time.QuadPart;
20
+ return (double)time.QuadPart;
21
21
  #elif defined(__APPLE__)
22
22
  return mach_absolute_time();// * (uint64_t)mach_timebase.numer / (uint64_t)mach_timebase.denom;
23
23
  #elif defined(__linux__)
@@ -65,25 +65,19 @@ static const char* get_event_name(rb_event_flag_t event)
65
65
  return "fiber-switch";
66
66
  case RUBY_EVENT_RAISE:
67
67
  return "raise";
68
+ case RUBY_INTERNAL_EVENT_NEWOBJ:
69
+ return "newobj";
68
70
  default:
69
71
  return "unknown";
70
72
  }
71
73
  }
72
74
 
73
- VALUE get_fiber(prof_profile_t* profile)
74
- {
75
- if (profile->merge_fibers)
76
- return rb_thread_current();
77
- else
78
- return rb_fiber_current();
79
- }
80
-
81
75
  thread_data_t* check_fiber(prof_profile_t* profile, double measurement)
82
76
  {
83
77
  thread_data_t* result = NULL;
84
78
 
85
- /* Get the current thread and fiber information. */
86
- VALUE fiber = get_fiber(profile);
79
+ // Get the current fiber
80
+ VALUE fiber = rb_fiber_current();
87
81
 
88
82
  /* We need to switch the profiling context if we either had none before,
89
83
  we don't merge fibers and the fiber ids differ, or the thread ids differ. */
@@ -172,7 +166,7 @@ prof_method_t* check_method(VALUE profile, rb_trace_arg_t* trace_arg, rb_event_f
172
166
  static void prof_trace(prof_profile_t* profile, rb_trace_arg_t* trace_arg, double measurement)
173
167
  {
174
168
  static VALUE last_fiber = Qnil;
175
- VALUE fiber = get_fiber(profile);
169
+ VALUE fiber = rb_fiber_current();
176
170
 
177
171
  rb_event_flag_t event = rb_tracearg_event_flag(trace_arg);
178
172
  const char* event_name = get_event_name(event);
@@ -487,7 +481,6 @@ static VALUE prof_allocate(VALUE klass)
487
481
  profile->include_threads_tbl = NULL;
488
482
  profile->running = Qfalse;
489
483
  profile->allow_exceptions = false;
490
- profile->merge_fibers = false;
491
484
  profile->exclude_methods_tbl = method_table_create();
492
485
  profile->running = Qfalse;
493
486
  profile->tracepoints = rb_ary_new();
@@ -529,9 +522,6 @@ prof_stop_threads(prof_profile_t* profile)
529
522
  If not specified, defaults to RubyProf::WALL_TIME.
530
523
  allow_exceptions: Whether to raise exceptions encountered during profiling,
531
524
  or to suppress all exceptions during profiling
532
- merge_fibers: Whether profiling data for a given thread's fibers should all be
533
- subsumed under a single entry. Basically only useful to produce
534
- callgrind profiles.
535
525
  track_allocations: Whether to track object allocations while profiling. True or false.
536
526
  exclude_common: Exclude common methods from the profile. True or false.
537
527
  exclude_threads: Threads to exclude from the profiling results.
@@ -546,7 +536,6 @@ static VALUE prof_initialize(int argc, VALUE* argv, VALUE self)
546
536
  VALUE include_threads = Qnil;
547
537
  VALUE exclude_common = Qnil;
548
538
  VALUE allow_exceptions = Qfalse;
549
- VALUE merge_fibers = Qfalse;
550
539
  VALUE track_allocations = Qfalse;
551
540
 
552
541
  int i;
@@ -566,7 +555,6 @@ static VALUE prof_initialize(int argc, VALUE* argv, VALUE self)
566
555
  mode = rb_hash_aref(mode_or_options, ID2SYM(rb_intern("measure_mode")));
567
556
  track_allocations = rb_hash_aref(mode_or_options, ID2SYM(rb_intern("track_allocations")));
568
557
  allow_exceptions = rb_hash_aref(mode_or_options, ID2SYM(rb_intern("allow_exceptions")));
569
- merge_fibers = rb_hash_aref(mode_or_options, ID2SYM(rb_intern("merge_fibers")));
570
558
  exclude_common = rb_hash_aref(mode_or_options, ID2SYM(rb_intern("exclude_common")));
571
559
  exclude_threads = rb_hash_aref(mode_or_options, ID2SYM(rb_intern("exclude_threads")));
572
560
  include_threads = rb_hash_aref(mode_or_options, ID2SYM(rb_intern("include_threads")));
@@ -587,7 +575,6 @@ static VALUE prof_initialize(int argc, VALUE* argv, VALUE self)
587
575
  }
588
576
  profile->measurer = prof_get_measurer(NUM2INT(mode), track_allocations == Qtrue);
589
577
  profile->allow_exceptions = (allow_exceptions == Qtrue);
590
- profile->merge_fibers = (merge_fibers == Qtrue);
591
578
 
592
579
  if (exclude_threads != Qnil)
593
580
  {
@@ -679,7 +666,7 @@ static VALUE prof_start(VALUE self)
679
666
 
680
667
  profile->running = Qtrue;
681
668
  profile->paused = Qfalse;
682
- profile->last_thread_data = threads_table_insert(profile, get_fiber(profile));
669
+ profile->last_thread_data = threads_table_insert(profile, rb_fiber_current());
683
670
 
684
671
  /* open trace file if environment wants it */
685
672
  trace_file_name = getenv("RUBY_PROF_TRACE");
@@ -769,11 +756,7 @@ static VALUE prof_stop(VALUE self)
769
756
  {
770
757
  if (trace_file != stderr && trace_file != stdout)
771
758
  {
772
- #ifdef _MSC_VER
773
- _fcloseall();
774
- #else
775
759
  fclose(trace_file);
776
- #endif
777
760
  }
778
761
  trace_file = NULL;
779
762
  }
@@ -26,7 +26,6 @@ typedef struct prof_profile_t
26
26
  thread_data_t* last_thread_data;
27
27
  double measurement_at_pause_resume;
28
28
  bool allow_exceptions;
29
- bool merge_fibers;
30
29
  } prof_profile_t;
31
30
 
32
31
  void rp_init_profile(void);
@@ -129,7 +129,7 @@ prof_frame_t* prof_frame_push(prof_stack_t* stack, prof_call_tree_t* call_tree,
129
129
  prof_frame_t* prof_frame_unshift(prof_stack_t* stack, prof_call_tree_t* parent_call_tree, prof_call_tree_t* call_tree, double measurement)
130
130
  {
131
131
  if (prof_stack_last(stack))
132
- rb_raise(rb_eRuntimeError, "Stach unshift can only be called with an empty stack");
132
+ rb_raise(rb_eRuntimeError, "Stack unshift can only be called with an empty stack");
133
133
 
134
134
  parent_call_tree->measurement->total_time = call_tree->measurement->total_time;
135
135
  parent_call_tree->measurement->self_time = 0;
@@ -187,7 +187,7 @@ prof_frame_t* prof_frame_pop(prof_stack_t* stack, double measurement)
187
187
 
188
188
  prof_method_t* prof_find_method(prof_stack_t* stack, VALUE source_file, int source_line)
189
189
  {
190
- prof_frame_t* frame = stack->ptr;
190
+ prof_frame_t* frame = prof_stack_last(stack);
191
191
  while (frame >= stack->start)
192
192
  {
193
193
  if (!frame->call_tree)
@@ -7,16 +7,24 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ruby_prof", "ruby_prof.vcxp
7
7
  EndProject
8
8
  Global
9
9
  GlobalSection(SolutionConfigurationPlatforms) = preSolution
10
+ Debug|ARM = Debug|ARM
11
+ Debug|ARM64 = Debug|ARM64
10
12
  Debug|x64 = Debug|x64
11
13
  Debug|x86 = Debug|x86
14
+ Release|ARM = Release|ARM
15
+ Release|ARM64 = Release|ARM64
12
16
  Release|x64 = Release|x64
13
17
  Release|x86 = Release|x86
14
18
  EndGlobalSection
15
19
  GlobalSection(ProjectConfigurationPlatforms) = postSolution
20
+ {6B4978F4-3B5F-4D38-81A8-069EC28CC069}.Debug|ARM.ActiveCfg = Debug|Win32
21
+ {6B4978F4-3B5F-4D38-81A8-069EC28CC069}.Debug|ARM64.ActiveCfg = Debug|Win32
16
22
  {6B4978F4-3B5F-4D38-81A8-069EC28CC069}.Debug|x64.ActiveCfg = Debug|x64
17
23
  {6B4978F4-3B5F-4D38-81A8-069EC28CC069}.Debug|x64.Build.0 = Debug|x64
18
24
  {6B4978F4-3B5F-4D38-81A8-069EC28CC069}.Debug|x86.ActiveCfg = Debug|Win32
19
25
  {6B4978F4-3B5F-4D38-81A8-069EC28CC069}.Debug|x86.Build.0 = Debug|Win32
26
+ {6B4978F4-3B5F-4D38-81A8-069EC28CC069}.Release|ARM.ActiveCfg = Release|Win32
27
+ {6B4978F4-3B5F-4D38-81A8-069EC28CC069}.Release|ARM64.ActiveCfg = Release|Win32
20
28
  {6B4978F4-3B5F-4D38-81A8-069EC28CC069}.Release|x64.ActiveCfg = Release|x64
21
29
  {6B4978F4-3B5F-4D38-81A8-069EC28CC069}.Release|x64.Build.0 = Release|x64
22
30
  {6B4978F4-3B5F-4D38-81A8-069EC28CC069}.Release|x86.ActiveCfg = Release|Win32
@@ -64,7 +64,7 @@
64
64
  </PropertyGroup>
65
65
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
66
66
  <TargetExt>.so</TargetExt>
67
- <OutDir>..\..\..\lib</OutDir>
67
+ <OutDir>..\..\..\lib\</OutDir>
68
68
  </PropertyGroup>
69
69
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
70
70
  <ClCompile>
@@ -102,17 +102,28 @@
102
102
  </ItemDefinitionGroup>
103
103
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
104
104
  <ClCompile>
105
- <AdditionalIncludeDirectories>C:\msys64\usr\local\ruby-2.7.0vc\include\ruby-2.7.0\x64-mswin64_140;C:\msys64\usr\local\ruby-2.7.0vc\include\ruby-2.7.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
105
+ <AdditionalIncludeDirectories>C:\msys64\usr\local\ruby-2.7.1vc\include\ruby-2.7.0\x64-mswin64_140;C:\msys64\usr\local\ruby-2.7.1vc\include\ruby-2.7.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
106
106
  <Optimization>Disabled</Optimization>
107
107
  <PreprocessorDefinitions>HAVE_RB_TRACEARG_CALLEE_ID;%(PreprocessorDefinitions)</PreprocessorDefinitions>
108
+ <WarningLevel>Level3</WarningLevel>
108
109
  </ClCompile>
109
110
  <Link>
110
- <AdditionalLibraryDirectories>C:\msys64\usr\local\ruby-2.7.0vc\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
111
+ <AdditionalLibraryDirectories>C:\msys64\usr\local\ruby-2.7.1vc\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
111
112
  <AdditionalDependencies>x64-vcruntime140-ruby270.lib;%(AdditionalDependencies)</AdditionalDependencies>
112
113
  <ModuleDefinitionFile>ruby_prof.def</ModuleDefinitionFile>
113
114
  <SubSystem>Console</SubSystem>
114
115
  </Link>
115
116
  </ItemDefinitionGroup>
117
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
118
+ <ClCompile>
119
+ <AdditionalIncludeDirectories>C:\msys64\usr\local\ruby-2.7.1vc\include\ruby-2.7.0\x64-mswin64_140;C:\msys64\usr\local\ruby-2.7.1vc\include\ruby-2.7.0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
120
+ </ClCompile>
121
+ <Link>
122
+ <AdditionalLibraryDirectories>C:\msys64\usr\local\ruby-2.7.1vc\lib</AdditionalLibraryDirectories>
123
+ <AdditionalDependencies>x64-vcruntime140-ruby270.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
124
+ <ModuleDefinitionFile>ruby_prof.def</ModuleDefinitionFile>
125
+ </Link>
126
+ </ItemDefinitionGroup>
116
127
  <ItemGroup>
117
128
  <ClInclude Include="..\rp_aggregate_call_tree.h" />
118
129
  <ClInclude Include="..\rp_allocation.h" />
@@ -0,0 +1,132 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3
+ <ItemGroup Label="ProjectConfigurations">
4
+ <ProjectConfiguration Include="Debug|ARM">
5
+ <Configuration>Debug</Configuration>
6
+ <Platform>ARM</Platform>
7
+ </ProjectConfiguration>
8
+ <ProjectConfiguration Include="Release|ARM">
9
+ <Configuration>Release</Configuration>
10
+ <Platform>ARM</Platform>
11
+ </ProjectConfiguration>
12
+ <ProjectConfiguration Include="Debug|ARM64">
13
+ <Configuration>Debug</Configuration>
14
+ <Platform>ARM64</Platform>
15
+ </ProjectConfiguration>
16
+ <ProjectConfiguration Include="Release|ARM64">
17
+ <Configuration>Release</Configuration>
18
+ <Platform>ARM64</Platform>
19
+ </ProjectConfiguration>
20
+ <ProjectConfiguration Include="Debug|x86">
21
+ <Configuration>Debug</Configuration>
22
+ <Platform>x86</Platform>
23
+ </ProjectConfiguration>
24
+ <ProjectConfiguration Include="Release|x86">
25
+ <Configuration>Release</Configuration>
26
+ <Platform>x86</Platform>
27
+ </ProjectConfiguration>
28
+ <ProjectConfiguration Include="Debug|x64">
29
+ <Configuration>Debug</Configuration>
30
+ <Platform>x64</Platform>
31
+ </ProjectConfiguration>
32
+ <ProjectConfiguration Include="Release|x64">
33
+ <Configuration>Release</Configuration>
34
+ <Platform>x64</Platform>
35
+ </ProjectConfiguration>
36
+ </ItemGroup>
37
+ <PropertyGroup Label="Globals">
38
+ <ProjectGuid>{fd79d690-c808-464c-a46b-01188609976e}</ProjectGuid>
39
+ <Keyword>Linux</Keyword>
40
+ <RootNamespace>Project1</RootNamespace>
41
+ <MinimumVisualStudioVersion>15.0</MinimumVisualStudioVersion>
42
+ <ApplicationType>Linux</ApplicationType>
43
+ <ApplicationTypeRevision>1.0</ApplicationTypeRevision>
44
+ <TargetLinuxPlatform>Generic</TargetLinuxPlatform>
45
+ <LinuxProjectType>{2238F9CD-F817-4ECC-BD14-2524D2669B35}</LinuxProjectType>
46
+ </PropertyGroup>
47
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
48
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
49
+ <UseDebugLibraries>true</UseDebugLibraries>
50
+ </PropertyGroup>
51
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
52
+ <UseDebugLibraries>false</UseDebugLibraries>
53
+ </PropertyGroup>
54
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'" Label="Configuration">
55
+ <UseDebugLibraries>true</UseDebugLibraries>
56
+ </PropertyGroup>
57
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'" Label="Configuration">
58
+ <UseDebugLibraries>false</UseDebugLibraries>
59
+ </PropertyGroup>
60
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
61
+ <UseDebugLibraries>true</UseDebugLibraries>
62
+ <PlatformToolset>WSL_1_0</PlatformToolset>
63
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
64
+ </PropertyGroup>
65
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
66
+ <UseDebugLibraries>false</UseDebugLibraries>
67
+ <PlatformToolset>WSL_1_0</PlatformToolset>
68
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
69
+ </PropertyGroup>
70
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
71
+ <UseDebugLibraries>false</UseDebugLibraries>
72
+ </PropertyGroup>
73
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
74
+ <UseDebugLibraries>true</UseDebugLibraries>
75
+ </PropertyGroup>
76
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
77
+ <ImportGroup Label="ExtensionSettings" />
78
+ <ImportGroup Label="Shared" />
79
+ <ImportGroup Label="PropertySheets" />
80
+ <PropertyGroup Label="UserMacros" />
81
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
82
+ <TargetName>ruby_prof</TargetName>
83
+ <OutDir>../usr/local/lib64/gems/ruby/ruby-prof-1.3.2/</OutDir>
84
+ </PropertyGroup>
85
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
86
+ <TargetName>ruby_prof</TargetName>
87
+ </PropertyGroup>
88
+ <ItemGroup>
89
+ <ClInclude Include="..\rp_aggregate_call_tree.h" />
90
+ <ClInclude Include="..\rp_allocation.h" />
91
+ <ClInclude Include="..\rp_call_tree.h" />
92
+ <ClInclude Include="..\rp_call_trees.h" />
93
+ <ClInclude Include="..\rp_measurement.h" />
94
+ <ClInclude Include="..\rp_method.h" />
95
+ <ClInclude Include="..\rp_profile.h" />
96
+ <ClInclude Include="..\rp_stack.h" />
97
+ <ClInclude Include="..\rp_thread.h" />
98
+ <ClInclude Include="..\ruby_prof.h" />
99
+ </ItemGroup>
100
+ <ItemGroup>
101
+ <ClCompile Include="..\rp_aggregate_call_tree.c" />
102
+ <ClCompile Include="..\rp_allocation.c" />
103
+ <ClCompile Include="..\rp_call_tree.c" />
104
+ <ClCompile Include="..\rp_call_trees.c" />
105
+ <ClCompile Include="..\rp_measurement.c" />
106
+ <ClCompile Include="..\rp_measure_allocations.c" />
107
+ <ClCompile Include="..\rp_measure_memory.c" />
108
+ <ClCompile Include="..\rp_measure_process_time.c" />
109
+ <ClCompile Include="..\rp_measure_wall_time.c" />
110
+ <ClCompile Include="..\rp_method.c" />
111
+ <ClCompile Include="..\rp_profile.c" />
112
+ <ClCompile Include="..\rp_stack.c" />
113
+ <ClCompile Include="..\rp_thread.c" />
114
+ <ClCompile Include="..\ruby_prof.c" />
115
+ </ItemGroup>
116
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
117
+ <Link>
118
+ <LibraryDependencies>ruby</LibraryDependencies>
119
+ </Link>
120
+ <ClCompile>
121
+ <PreprocessorDefinitions>
122
+ </PreprocessorDefinitions>
123
+ </ClCompile>
124
+ </ItemDefinitionGroup>
125
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
126
+ <Link>
127
+ <LibraryDependencies>ruby</LibraryDependencies>
128
+ </Link>
129
+ </ItemDefinitionGroup>
130
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
131
+ <ImportGroup Label="ExtensionTargets" />
132
+ </Project>
@@ -1,9 +1,10 @@
1
1
  # encoding: utf-8
2
+ require 'rubygems/version'
2
3
 
3
4
  # Load the C-based binding.
4
5
  begin
5
- RUBY_VERSION =~ /(\d+\.\d+\.\d+)/
6
- require "#{$1}/ruby_prof.so"
6
+ version = Gem::Version.new(RUBY_VERSION)
7
+ require "#{version.segments[0..1].join('.')}/ruby_prof.so"
7
8
  rescue LoadError
8
9
  require "ruby_prof.so"
9
10
  end
@@ -5,43 +5,37 @@ module Rack
5
5
  class RubyProf
6
6
  def initialize(app, options = {})
7
7
  @app = app
8
+ @options = options
9
+ @options[:min_percent] ||= 1
8
10
 
9
- options[:min_percent] ||= 1
11
+ @tmpdir = options[:path] || Dir.tmpdir
12
+ FileUtils.mkdir_p(@tmpdir)
10
13
 
11
- options[:path] ||= Dir.tmpdir
12
- FileUtils.mkdir_p(options[:path])
14
+ @printer_klasses = @options[:printers] || {::RubyProf::FlatPrinter => 'flat.txt',
15
+ ::RubyProf::GraphPrinter => 'graph.txt',
16
+ ::RubyProf::GraphHtmlPrinter => 'graph.html',
17
+ ::RubyProf::CallStackPrinter => 'call_stack.html'}
13
18
 
14
19
  @skip_paths = options[:skip_paths] || [%r{^/assets}, %r{\.(css|js|png|jpeg|jpg|gif)$}]
15
20
  @only_paths = options[:only_paths]
16
-
17
- @max_requests = options[:max_requests]
18
-
19
- @options = options
20
21
  end
21
22
 
22
23
  def call(env)
23
24
  request = Rack::Request.new(env)
24
25
 
25
26
  if should_profile?(request.path)
26
- profiler.resume
27
27
  begin
28
- result = @app.call(env)
29
- ensure
30
- profiler.pause
31
- end
28
+ result = nil
29
+ data = ::RubyProf::Profile.profile(profiling_options) do
30
+ result = @app.call(env)
31
+ end
32
32
 
33
- if profiler.max_requests_reached?
34
- prefix = if aggregate_requests?
35
- nil
36
- else
37
- request.path.gsub('/', '-')[1..-1]
38
- end
33
+ path = request.path.gsub('/', '-')
34
+ path.slice!(0)
39
35
 
40
- profiler.print!(prefix)
41
- delete_profiler!
36
+ print(data, path)
37
+ result
42
38
  end
43
-
44
- result
45
39
  else
46
40
  @app.call(env)
47
41
  end
@@ -49,126 +43,53 @@ module Rack
49
43
 
50
44
  private
51
45
 
52
- class RackProfiler
53
- def initialize(options)
54
- @options = options
55
-
56
- @profile = ::RubyProf::Profile.new(profiling_options)
57
- @profile.start
58
- @profile.pause
59
-
60
- @printer_klasses = options[:printers] || default_printers
61
-
62
- @tmpdir = options[:path]
63
-
64
- @max_requests = options[:max_requests] || 1
65
- @requests_count = 0
46
+ def should_profile?(path)
47
+ return false if paths_match?(path, @skip_paths)
66
48
 
67
- @printed = false
68
- # if running across multiple requests, we want to make sure that the
69
- # ongoing profile is not lost if the process shuts down before the
70
- # max request count is reached
71
- ObjectSpace.define_finalizer(self, proc { print! })
72
- end
49
+ @only_paths ? paths_match?(path, @only_paths) : true
50
+ end
73
51
 
74
- def resume
75
- @profile.resume
76
- end
52
+ def paths_match?(path, paths)
53
+ paths.any? { |skip_path| skip_path =~ path }
54
+ end
77
55
 
78
- def pause
79
- @profile.pause
80
- @requests_count += 1
56
+ 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]
81
67
  end
82
-
83
- def max_requests_reached?
84
- @requests_count >= @max_requests
68
+ if @options[:merge_fibers]
69
+ options[:merge_fibers] = true
85
70
  end
71
+ options
72
+ end
86
73
 
87
- def print!(prefix = nil)
88
- return false if @printed || @requests_count == 0
89
-
90
- data = @profile.stop
91
-
92
- prefix ||= "multi-requests-#{@requests_count}"
93
-
94
- @printer_klasses.each do |printer_klass, base_name|
95
- printer = printer_klass.new(data)
96
-
97
- if base_name.respond_to?(:call)
98
- base_name = base_name.call
99
- end
74
+ def print(data, path)
75
+ @printer_klasses.each do |printer_klass, base_name|
76
+ printer = printer_klass.new(data)
100
77
 
101
- if printer_klass == ::RubyProf::MultiPrinter \
102
- || printer_klass == ::RubyProf::CallTreePrinter
103
- printer.print(@options.merge(:profile => "#{prefix}-#{base_name}"))
104
- else
105
- file_name = ::File.join(@tmpdir, "#{prefix}-#{base_name}")
106
- ::File.open(file_name, 'wb') do |file|
107
- printer.print(file, @options)
108
- end
109
- end
78
+ if base_name.respond_to?(:call)
79
+ base_name = base_name.call
110
80
  end
111
81
 
112
- @printed = true
113
- end
114
-
115
- private
116
-
117
- def profiling_options
118
- options = {}
119
- options[:measure_mode] = ::RubyProf.measure_mode
120
- options[:exclude_threads] =
121
- if @options[:ignore_existing_threads]
122
- Thread.list.select{|t| t != Thread.current}
123
- else
124
- ::RubyProf.exclude_threads
82
+ if printer_klass == ::RubyProf::MultiPrinter
83
+ printer.print(@options.merge(:profile => "#{path}-#{base_name}"))
84
+ elsif printer_klass == ::RubyProf::CallTreePrinter
85
+ printer.print(@options.merge(:profile => "#{path}-#{base_name}"))
86
+ else
87
+ file_name = ::File.join(@tmpdir, "#{path}-#{base_name}")
88
+ ::File.open(file_name, 'wb') do |file|
89
+ printer.print(file, @options)
125
90
  end
126
- if @options[:request_thread_only]
127
- options[:include_threads] = [Thread.current]
128
91
  end
129
- if @options[:merge_fibers]
130
- options[:merge_fibers] = true
131
- end
132
- options
133
- end
134
-
135
- def default_printers
136
- {::RubyProf::FlatPrinter => 'flat.txt',
137
- ::RubyProf::GraphPrinter => 'graph.txt',
138
- ::RubyProf::GraphHtmlPrinter => 'graph.html',
139
- ::RubyProf::CallStackPrinter => 'call_stack.html'}
140
92
  end
141
93
  end
142
-
143
- def profiler
144
- if aggregate_requests?
145
- @@_shared_profiler ||= RackProfiler.new(@options)
146
- else
147
- @_profiler ||= RackProfiler.new(@options)
148
- end
149
- end
150
-
151
- def delete_profiler!
152
- if aggregate_requests?
153
- @@_shared_profiler.print! if @@_shared_profiler
154
- @@_shared_profiler = nil
155
- else
156
- @_profiler = nil
157
- end
158
- end
159
-
160
- def aggregate_requests?
161
- !@max_requests.nil?
162
- end
163
-
164
- def should_profile?(path)
165
- return false if paths_match?(path, @skip_paths)
166
-
167
- @only_paths ? paths_match?(path, @only_paths) : true
168
- end
169
-
170
- def paths_match?(path, paths)
171
- paths.any? { |skip_path| skip_path =~ path }
172
- end
173
94
  end
174
95
  end
@@ -1,3 +1,3 @@
1
1
  module RubyProf
2
- VERSION = "1.3.1"
2
+ VERSION = "1.4.0"
3
3
  end
@@ -0,0 +1,9 @@
1
+ # tcp_client.rb
2
+ require 'socket'
3
+ client = TCPSocket.new('localhost', 9090)
4
+
5
+ client.puts("HI")
6
+ line = client.gets
7
+ puts line
8
+
9
+ client.close
@@ -8,254 +8,122 @@ require 'set'
8
8
 
9
9
  # -- Tests ----
10
10
  class FiberTest < TestCase
11
+
11
12
  def enumerator_with_fibers
12
- @fiber_ids << Fiber.current.object_id
13
13
  enum = Enumerator.new do |yielder|
14
14
  [1,2].each do |x|
15
- @fiber_ids << Fiber.current.object_id
16
- sleep 0.1
17
15
  yielder.yield x
18
16
  end
19
17
  end
20
- while true
21
- begin
22
- enum.next
23
- rescue StopIteration
24
- break
25
- end
26
- end
27
- sleep 0.1
18
+
19
+ enum.next
20
+ enum.next
21
+ end
22
+
23
+ def fiber_yield_resume
24
+ fiber = Fiber.new do
25
+ Fiber.yield 1
26
+ Fiber.yield 2
27
+ end
28
+
29
+ fiber.resume
30
+ fiber.resume
28
31
  end
29
32
 
30
33
  def setup
31
34
  # Need to use wall time for this test due to the sleep calls
32
35
  RubyProf::measure_mode = RubyProf::WALL_TIME
33
- @fiber_ids = Set.new
34
- @root_fiber = Fiber.current.object_id
35
- @thread_id = Thread.current.object_id
36
36
  end
37
37
 
38
38
  def test_fibers
39
39
  result = RubyProf.profile { enumerator_with_fibers }
40
40
 
41
- profiled_fiber_ids = result.threads.map(&:fiber_id)
42
- assert_equal(2, result.threads.length)
43
- assert_equal([@thread_id], result.threads.map(&:id).uniq)
44
- assert_equal(@fiber_ids, Set.new(profiled_fiber_ids))
41
+ assert_equal(2, result.threads.size)
45
42
 
46
- assert profiled_fiber_ids.include?(@root_fiber)
47
- assert(root_fiber_profile = result.threads.detect{|t| t.fiber_id == @root_fiber})
48
- assert(enum_fiber_profile = result.threads.detect{|t| t.fiber_id != @root_fiber})
49
- assert_in_delta(0.33, root_fiber_profile.total_time, 0.05)
50
- assert_in_delta(0.33, enum_fiber_profile.total_time, 0.05)
51
-
52
- methods = result.threads[0].methods.sort.reverse
53
- assert_equal(12, methods.count)
43
+ thread1 = result.threads[0]
44
+ methods = thread1.methods.sort.reverse
45
+ assert_equal(5, methods.count)
54
46
 
55
47
  method = methods[0]
56
48
  assert_equal('FiberTest#test_fibers', method.full_name)
57
49
  assert_equal(1, method.called)
58
- assert_in_delta(0.33, method.total_time, 0.05)
59
- assert_in_delta(0, method.self_time, 0.05)
60
- assert_in_delta(0, method.wait_time, 0.05)
61
- assert_in_delta(0.33, method.children_time, 0.05)
62
50
 
63
51
  method = methods[1]
64
52
  assert_equal('FiberTest#enumerator_with_fibers', method.full_name)
65
53
  assert_equal(1, method.called)
66
- assert_in_delta(0.33, method.total_time, 0.05)
67
- assert_in_delta(0, method.self_time, 0.05)
68
- assert_in_delta(0, method.wait_time, 0.05)
69
- assert_in_delta(0.33, method.children_time, 0.05)
70
54
 
71
55
  method = methods[2]
72
56
  assert_equal('Enumerator#next', method.full_name)
73
- assert_equal(3, method.called)
74
- assert_in_delta(0.22, method.total_time, 0.05)
75
- assert_in_delta(0, method.self_time, 0.05)
76
- assert_in_delta(0.22, method.wait_time, 0.05)
77
- assert_in_delta(0, method.children_time, 0.05)
57
+ assert_equal(2, method.called)
78
58
 
79
59
  method = methods[3]
80
- assert_equal('Kernel#sleep', method.full_name)
81
- assert_equal(1, method.called)
82
- assert_in_delta(0.11, method.total_time, 0.05)
83
- assert_in_delta(0.11, method.self_time, 0.05)
84
- assert_in_delta(0, method.wait_time, 0.05)
85
- assert_in_delta(0, method.children_time, 0.05)
86
-
87
- # Since these methods have such short times their order is a bit indeterminate
88
- method = methods.detect {|a_method| a_method.full_name == 'Class#new'}
89
60
  assert_equal('Class#new', method.full_name)
90
61
  assert_equal(1, method.called)
91
- assert_in_delta(0, method.total_time, 0.05)
92
- assert_in_delta(0, method.self_time, 0.05)
93
- assert_in_delta(0, method.wait_time, 0.05)
94
- assert_in_delta(0, method.children_time, 0.05)
95
-
96
- if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.5.0')
97
- method = methods.detect {|a_method| a_method.full_name == 'Set#<<'}
98
- assert_equal('Set#<<', method.full_name)
99
- assert_equal(1, method.called)
100
- assert_in_delta(0, method.total_time, 0.05)
101
- assert_in_delta(0, method.self_time, 0.05)
102
- assert_in_delta(0, method.wait_time, 0.05)
103
- assert_in_delta(0, method.children_time, 0.05)
104
- end
105
62
 
106
- method = methods.detect {|a_method| a_method.full_name == 'Module#==='}
107
- assert_equal('Module#===', method.full_name)
63
+ method = methods[4]
64
+ assert_equal('Enumerator#initialize', method.full_name)
108
65
  assert_equal(1, method.called)
109
- assert_in_delta(0, method.total_time, 0.05)
110
- assert_in_delta(0, method.self_time, 0.05)
111
- assert_in_delta(0, method.wait_time, 0.05)
112
- assert_in_delta(0, method.children_time, 0.05)
113
66
 
114
- method = methods.detect {|a_method| a_method.full_name == 'Kernel#object_id'}
115
- assert_equal('Kernel#object_id', method.full_name)
116
- assert_equal(1, method.called)
117
- assert_in_delta(0, method.total_time, 0.05)
118
- assert_in_delta(0, method.self_time, 0.05)
119
- assert_in_delta(0, method.wait_time, 0.05)
120
- assert_in_delta(0, method.children_time, 0.05)
67
+ thread2 = result.threads[1]
68
+ methods = thread2.methods.sort.reverse
69
+ assert_equal(4, methods.count)
121
70
 
122
- method = methods.detect {|a_method| a_method.full_name == '<Class::Fiber>#current'}
123
- assert_equal('<Class::Fiber>#current', method.full_name)
71
+ method = methods[0]
72
+ assert_equal('Enumerator#each', method.full_name)
124
73
  assert_equal(1, method.called)
125
- assert_in_delta(0, method.total_time, 0.05)
126
- assert_in_delta(0, method.self_time, 0.05)
127
- assert_in_delta(0, method.wait_time, 0.05)
128
- assert_in_delta(0, method.children_time, 0.05)
129
74
 
130
- method = methods.detect {|a_method| a_method.full_name == 'Exception#exception'}
131
- assert_equal('Exception#exception', method.full_name)
75
+ method = methods[1]
76
+ assert_equal('Enumerator::Generator#each', method.full_name)
132
77
  assert_equal(1, method.called)
133
- assert_in_delta(0, method.total_time, 0.05)
134
- assert_in_delta(0, method.self_time, 0.05)
135
- assert_in_delta(0, method.wait_time, 0.05)
136
- assert_in_delta(0, method.children_time, 0.05)
137
78
 
138
- method = methods.detect {|a_method| a_method.full_name == 'Exception#backtrace'}
139
- assert_equal('Exception#backtrace', method.full_name)
79
+ method = methods[2]
80
+ assert_equal('Array#each', method.full_name)
140
81
  assert_equal(1, method.called)
141
- assert_in_delta(0, method.total_time, 0.05)
142
- assert_in_delta(0, method.self_time, 0.05)
143
- assert_in_delta(0, method.wait_time, 0.05)
144
- assert_in_delta(0, method.children_time, 0.05)
145
82
 
146
- method = methods.detect {|a_method| a_method.full_name == 'Enumerator#initialize'}
147
- assert_equal('Enumerator#initialize', method.full_name)
148
- assert_equal(1, method.called)
149
- assert_in_delta(0, method.total_time, 0.05)
150
- assert_in_delta(0, method.self_time, 0.05)
151
- assert_in_delta(0, method.wait_time, 0.05)
152
- assert_in_delta(0, method.children_time, 0.05)
83
+ method = methods[3]
84
+ assert_equal('Enumerator::Yielder#yield', method.full_name)
85
+ assert_equal(2, method.called)
86
+ end
153
87
 
154
- methods = result.threads[1].methods.sort.reverse
88
+ def test_fiber_resume
89
+ result = RubyProf.profile { fiber_yield_resume }
155
90
 
156
- if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.6.0')
157
- assert_equal(10, methods.count)
158
- else
159
- assert_equal(11, methods.count)
160
- end
91
+ assert_equal(2, result.threads.size)
92
+
93
+ thread1 = result.threads[0]
94
+ methods = thread1.methods.sort.reverse
95
+ assert_equal(5, methods.count)
161
96
 
162
97
  method = methods[0]
163
- assert_equal('RubyProf::Profile#_inserted_parent_', method.full_name)
98
+ assert_equal('FiberTest#test_fiber_resume', method.full_name)
164
99
  assert_equal(1, method.called)
165
- assert_in_delta(0.33, method.total_time, 0.05)
166
- assert_in_delta(0, method.self_time, 0.05)
167
- assert_in_delta(0.11, method.wait_time, 0.05)
168
- assert_in_delta(0.22, method.children_time, 0.05)
169
100
 
170
101
  method = methods[1]
171
- assert_equal('Enumerator#each', method.full_name)
102
+ assert_equal('FiberTest#fiber_yield_resume', method.full_name)
172
103
  assert_equal(1, method.called)
173
- assert_in_delta(0.22, method.total_time, 0.05)
174
- assert_in_delta(0, method.self_time, 0.05)
175
- assert_in_delta(0, method.wait_time, 0.05)
176
- assert_in_delta(0.22, method.children_time, 0.05)
177
104
 
178
105
  method = methods[2]
179
- assert_equal('Enumerator::Generator#each', method.full_name)
180
- assert_equal(1, method.called)
181
- assert_in_delta(0.22, method.total_time, 0.05)
182
- assert_in_delta(0, method.self_time, 0.05)
183
- assert_in_delta(0, method.wait_time, 0.05)
184
- assert_in_delta(0.22, method.children_time, 0.05)
106
+ assert_equal('Fiber#resume', method.full_name)
107
+ assert_equal(2, method.called)
185
108
 
186
109
  method = methods[3]
187
- assert_equal('Array#each', method.full_name)
110
+ assert_equal('Class#new', method.full_name)
188
111
  assert_equal(1, method.called)
189
- assert_in_delta(0.22, method.total_time, 0.05)
190
- assert_in_delta(0, method.self_time, 0.05)
191
- assert_in_delta(0, method.wait_time, 0.05)
192
- assert_in_delta(0.22, method.children_time, 0.05)
193
112
 
194
113
  method = methods[4]
195
- assert_equal('Kernel#sleep', method.full_name)
196
- assert_equal(2, method.called)
197
- assert_in_delta(0.22, method.total_time, 0.05)
198
- assert_in_delta(0.22, method.self_time, 0.05)
199
- assert_in_delta(0, method.wait_time, 0.05)
200
- assert_in_delta(0, method.children_time, 0.05)
201
-
202
- # Since these methods have such short times their order is a bit indeterminate
203
- method = methods.detect {|a_method| a_method.full_name == 'Exception#initialize'}
204
- assert_equal('Exception#initialize', method.full_name)
114
+ assert_equal('Fiber#initialize', method.full_name)
205
115
  assert_equal(1, method.called)
206
- assert_in_delta(0, method.total_time, 0.05)
207
- assert_in_delta(0, method.self_time, 0.05)
208
- assert_in_delta(0, method.wait_time, 0.05)
209
- assert_in_delta(0, method.children_time, 0.05)
210
-
211
- if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.5.0')
212
- method = methods.detect {|a_method| a_method.full_name == 'Set#<<'}
213
- assert_equal('Set#<<', method.full_name)
214
- assert_equal(2, method.called)
215
- assert_in_delta(0, method.total_time, 0.05)
216
- assert_in_delta(0, method.self_time, 0.05)
217
- assert_in_delta(0, method.wait_time, 0.05)
218
- assert_in_delta(0, method.children_time, 0.05)
219
- end
220
116
 
221
- method = methods.detect {|a_method| a_method.full_name == 'Kernel#object_id'}
222
- assert_equal('Kernel#object_id', method.full_name)
223
- assert_equal(2, method.called)
224
- assert_in_delta(0, method.total_time, 0.05)
225
- assert_in_delta(0, method.self_time, 0.05)
226
- assert_in_delta(0, method.wait_time, 0.05)
227
- assert_in_delta(0, method.children_time, 0.05)
117
+ thread1 = result.threads[1]
118
+ methods = thread1.methods.sort.reverse
119
+ assert_equal(2, methods.count)
228
120
 
229
- method = methods.detect {|a_method| a_method.full_name == 'Enumerator::Yielder#yield'}
230
- assert_equal('Enumerator::Yielder#yield', method.full_name)
231
- assert_equal(2, method.called)
232
- assert_in_delta(0, method.total_time, 0.05)
233
- assert_in_delta(0, method.self_time, 0.05)
234
- assert_in_delta(0, method.wait_time, 0.05)
235
- assert_in_delta(0, method.children_time, 0.05)
121
+ method = methods[0]
122
+ assert_equal('FiberTest#fiber_yield_resume', method.full_name)
123
+ assert_equal(1, method.called)
236
124
 
237
- method = methods.detect {|a_method| a_method.full_name == '<Class::Fiber>#current'}
238
- assert_equal('<Class::Fiber>#current', method.full_name)
125
+ method = methods[1]
126
+ assert_equal('<Class::Fiber>#yield', method.full_name)
239
127
  assert_equal(2, method.called)
240
- assert_in_delta(0, method.total_time, 0.05)
241
- assert_in_delta(0, method.self_time, 0.05)
242
- assert_in_delta(0, method.wait_time, 0.05)
243
- assert_in_delta(0, method.children_time, 0.05)
244
- end
245
-
246
- def test_merged_fibers
247
- result = RubyProf.profile(merge_fibers: true) { enumerator_with_fibers }
248
-
249
- assert_equal(1, result.threads.length)
250
-
251
- thread = result.threads.first
252
- assert_equal(thread.id, thread.fiber_id)
253
- assert_in_delta(0.3, thread.total_time, 0.05)
254
-
255
- assert(method_next = thread.methods.detect{|m| m.full_name == "Enumerator#next"})
256
- assert(method_each = thread.methods.detect{|m| m.full_name == "Enumerator#each"})
257
-
258
- assert_in_delta(0.2, method_next.total_time, 0.05)
259
- assert_in_delta(0.2, method_each.total_time, 0.05)
260
128
  end
261
129
  end
@@ -24,16 +24,6 @@ module Rack
24
24
  end
25
25
  end
26
26
 
27
- module Rack
28
- class RubyProf
29
- attr_reader :_profiler
30
-
31
- def public_delete_profiler!
32
- delete_profiler!
33
- end
34
- end
35
- end
36
-
37
27
  class RackTest < TestCase
38
28
  def test_create_print_path
39
29
  path = Dir.mktmpdir
@@ -100,58 +90,4 @@ class RackTest < TestCase
100
90
  file_path = ::File.join(path, 'path-to-resource.json-dynamic.txt')
101
91
  assert(File.exist?(file_path))
102
92
  end
103
-
104
- def test_works_for_multiple_requests
105
- path = Dir.mktmpdir
106
-
107
- adapter = Rack::RubyProf.new(FakeRackApp.new, :path => path, :max_requests => 2)
108
-
109
- # make a 1st request, and check that this didn't create any files
110
- adapter.call(:fake_env)
111
- assert(Dir["#{path}/*"].empty?)
112
-
113
- # now a second request should create all the expected files
114
- adapter.call(:fake_env)
115
- %w(flat.txt graph.txt graph.html call_stack.html).each do |base_name|
116
- file_path = ::File.join(path, "multi-requests-2-#{base_name}")
117
- assert(File.exist?(file_path))
118
- end
119
-
120
- # let's clean up
121
- FileUtils.rm_rf(Dir["#{path}/*"])
122
-
123
- # and do the same again for the next 2 requests
124
- adapter.call(:fake_env)
125
- assert(Dir["#{path}/*"].empty?)
126
-
127
- adapter.call(:fake_env)
128
- %w(flat.txt graph.txt graph.html call_stack.html).each do |base_name|
129
- file_path = ::File.join(path, "multi-requests-2-#{base_name}")
130
- assert(File.exist?(file_path))
131
- end
132
- end
133
-
134
- def test_tries_to_print_results_if_shut_down_before_max_requests_reached
135
- path = Dir.mktmpdir
136
-
137
- adapter = Rack::RubyProf.new(FakeRackApp.new, :path => path, :max_requests => 100)
138
-
139
- # make a 1st request, and check that this didn't create any files
140
- adapter.call(:fake_env)
141
- assert(Dir["#{path}/*"].empty?)
142
-
143
- adapter.public_delete_profiler!
144
-
145
- %w(flat.txt graph.txt graph.html call_stack.html).each do |base_name|
146
- file_path = ::File.join(path, "multi-requests-1-#{base_name}")
147
- assert(File.exist?(file_path))
148
- end
149
- end
150
-
151
- def test_it_uses_separate_profilers_if_not_aggregating_multiple_requests
152
- adapter1 = Rack::RubyProf.new(FakeRackApp.new)
153
- adapter2 = Rack::RubyProf.new(FakeRackApp.new)
154
-
155
- assert(adapter1.object_id != adapter2.object_id)
156
- end
157
93
  end
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'socket'
4
+ require 'fiber'
5
+
6
+ # The full implementation is given here, in order to show all the parts. A simpler implementation is given below.
7
+ class Reactor
8
+ def initialize
9
+ @readable = {}
10
+ @writable = {}
11
+ end
12
+
13
+ def run
14
+ while @readable.any? or @writable.any?
15
+ readable, writable = IO.select(@readable.keys, @writable.keys, [])
16
+
17
+ readable.each do |io|
18
+ @readable[io].resume
19
+ end
20
+
21
+ writable.each do |io|
22
+ @writable[io].resume
23
+ end
24
+ end
25
+ end
26
+
27
+ def wait_readable(io)
28
+ @readable[io] = Fiber.current
29
+ Fiber.yield
30
+ @readable.delete(io)
31
+
32
+ return yield if block_given?
33
+ end
34
+
35
+ def wait_writable(io)
36
+ @writable[io] = Fiber.current
37
+ Fiber.yield
38
+ @writable.delete(io)
39
+
40
+ return yield if block_given?
41
+ end
42
+ end
43
+
44
+ server = TCPServer.new('localhost', 9090)
45
+ reactor = Reactor.new
46
+
47
+ Fiber.new do
48
+ loop do
49
+ client = reactor.wait_readable(server) do
50
+ server.accept
51
+ end
52
+
53
+ Fiber.new do
54
+ while buffer = reactor.wait_readable(client) {client.gets}
55
+ reactor.wait_writable(client)
56
+ client.puts(buffer)
57
+ end
58
+
59
+ client.close
60
+ end.resume
61
+ end
62
+ end.resume
63
+
64
+ reactor.run
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-prof
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 1.4.0
5
5
  platform: x64-mingw32
6
6
  authors:
7
7
  - Shugo Maeda, Charlie Savage, Roger Pack, Stefan Kaes
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-12 00:00:00.000000000 Z
11
+ date: 2020-05-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -99,8 +99,7 @@ files:
99
99
  - ext/ruby_prof/ruby_prof.h
100
100
  - ext/ruby_prof/vc/ruby_prof.sln
101
101
  - ext/ruby_prof/vc/ruby_prof.vcxproj
102
- - lib/2.6.5/ruby_prof.so
103
- - lib/2.7.0/ruby_prof.so
102
+ - ext/ruby_prof/vc/ruby_prof_linux.vcxproj
104
103
  - lib/ruby-prof.rb
105
104
  - lib/ruby-prof/assets/call_stack_printer.html.erb
106
105
  - lib/ruby-prof/assets/call_stack_printer.png
@@ -132,6 +131,7 @@ files:
132
131
  - test/basic_test.rb
133
132
  - test/call_tree_visitor_test.rb
134
133
  - test/call_trees_test.rb
134
+ - test/client.rb
135
135
  - test/duplicate_names_test.rb
136
136
  - test/dynamic_method_test.rb
137
137
  - test/enumerable_test.rb
@@ -164,6 +164,7 @@ files:
164
164
  - test/printing_recursive_graph_test.rb
165
165
  - test/rack_test.rb
166
166
  - test/recursive_test.rb
167
+ - test/server.rb
167
168
  - test/singleton_test.rb
168
169
  - test/stack_printer_test.rb
169
170
  - test/start_stop_test.rb
@@ -178,7 +179,7 @@ metadata:
178
179
  bug_tracker_uri: https://github.com/ruby-prof/ruby-prof/issues
179
180
  changelog_uri: https://github.com/ruby-prof/ruby-prof/blob/master/CHANGES
180
181
  documentation_uri: https://ruby-prof.github.io/
181
- source_code_uri: https://github.com/ruby-prof/ruby-prof/tree/v1.3.1
182
+ source_code_uri: https://github.com/ruby-prof/ruby-prof/tree/v1.4.0
182
183
  post_install_message:
183
184
  rdoc_options: []
184
185
  require_paths:
@@ -194,7 +195,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
194
195
  - !ruby/object:Gem::Version
195
196
  version: '0'
196
197
  requirements: []
197
- rubygems_version: 3.0.6
198
+ rubygems_version: 3.1.2
198
199
  signing_key:
199
200
  specification_version: 4
200
201
  summary: Fast Ruby profiler
Binary file
Binary file