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

Sign up to get free protection for your applications and to get access to all the features.
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