RubyInline 3.1.0

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.
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/ruby -w
2
+
3
+ # We started out with some code that averaged a ton of numbers in a
4
+ # bunch of arrays. Once we finally lost our patience with the average
5
+ # running time of the code, we decided to profile and optimize it
6
+ # using RubyInline.
7
+
8
+ class Array
9
+
10
+ def average
11
+ result = 0
12
+ self.each { |x| result += x }
13
+ result / self.size.to_f
14
+ end
15
+
16
+ end
17
+
18
+ max_loop = (ARGV.shift || 5).to_i
19
+ max_size = (ARGV.shift || 100_000).to_i
20
+ a = (1..max_size).to_a
21
+
22
+ 1.upto(max_loop) do
23
+ avg = a.average
24
+ $stderr.print "."
25
+ end
26
+ $stderr.puts ""
27
+
28
+ # The first step to profiling is to get a simple run of the code using
29
+ # 'time' and a large dataset. This is because a profile run should
30
+ # only be used for figuring out where your bottlenecks are, but the
31
+ # runtime of a profile run should be considered invalid. This is
32
+ # because set_trace_func, the main mechanism used by profile is a very
33
+ # costly function.
34
+
35
+ # & time ruby ./example1.rb 5 100000
36
+ # .....
37
+ #
38
+ # real 0m4.580s
39
+ # user 0m3.310s
40
+ # sys 0m0.090s
41
+ # (user+sys = 3.400s)
42
+
43
+ # This gives us a tangible goal, to reduce the runtime of 4.58 seconds
44
+ # as much as possible. The next step is to run with a smaller dataset
45
+ # (because profiling is VERY SLOW) while including the profile module.
46
+
47
+ # & ruby -rprofile ./example1.rb 3 10000
48
+ # ...
49
+ # % cumulative self self total
50
+ # time seconds seconds calls ms/call ms/call name
51
+ # 69.78 4.78 4.78 3 1593.33 2273.33 Array#each
52
+ # 29.78 6.82 2.04 30000 0.07 0.07 Fixnum#+
53
+ # 0.15 6.83 0.01 3 3.33 2276.67 Array#average
54
+ # 0.15 6.84 0.01 1 10.00 10.00 Range#each
55
+ # 0.00 6.84 0.00 1 0.00 10.00 Enumerable.to_a
56
+ # -- CUT ALL FOLLOWING LINES WHERE %time == 0.00
57
+
58
+ # This says that Array#each and Fixnum#+ are the only two things we
59
+ # should focus on at all. The rest of the time is statistically
60
+ # insignificant. So, since average itself is a rather uncomplicated
61
+ # method, we decided to convert the entire method rather than just try
62
+ # to speed up the math or the loop separately. See example2.rb for the
63
+ # continuation of this example.
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/ruby -w -I..
2
+
3
+ require 'inline'
4
+
5
+ class Array
6
+
7
+ inline do |builder|
8
+ builder.c_raw "
9
+ static VALUE average(int argc, VALUE *argv, VALUE self) {
10
+ double result;
11
+ long i, len;
12
+ VALUE *arr = RARRAY(self)->ptr;
13
+ len = RARRAY(self)->len;
14
+
15
+ for(i=0; i<len; i++) {
16
+ result += NUM2DBL(arr[i]);
17
+ }
18
+
19
+ return rb_float_new(result/(double)len);
20
+ }
21
+ "
22
+ end
23
+ end
24
+
25
+ max_loop = (ARGV.shift || 5).to_i
26
+ max_size = (ARGV.shift || 100_000).to_i
27
+ a = (1..max_size).to_a
28
+
29
+ 1.upto(max_loop) do
30
+ avg = a.average
31
+ $stderr.print "."
32
+ end
33
+ $stderr.puts ""
34
+
35
+ # ruby -rprofile ./example2.rb 3 10000
36
+ # ...
37
+ # % cumulative self self total
38
+ # time seconds seconds calls ms/call ms/call name
39
+ # 23.53 0.08 0.08 4 20.00 122.50 Kernel.require
40
+ # 14.71 0.13 0.05 123 0.41 0.98 Config.expand
41
+ # 11.76 0.17 0.04 135 0.30 0.59 String#gsub!
42
+ # 11.76 0.21 0.04 1 40.00 40.00 Hash#each
43
+ # 8.82 0.24 0.03 1 30.00 110.00 Hash#each_value
44
+ # 5.88 0.26 0.02 3 6.67 6.67 Mod_Array_average.average
45
+ # 2.94 0.27 0.01 10 1.00 1.00 Kernel.singleton_method_added
46
+ # 2.94 0.28 0.01 1 10.00 30.00 Fixnum#upto
47
+ # 2.94 0.29 0.01 2 5.00 10.00 Module#parse_signature
48
+ # 2.94 0.30 0.01 2 5.00 5.00 File#stat
49
+ # 2.94 0.31 0.01 1 10.00 10.00 Range#each
50
+ # 2.94 0.32 0.01 1 10.00 50.00 Module#inline_c_real
51
+ # 2.94 0.33 0.01 182 0.05 0.05 Hash#[]=
52
+ # 2.94 0.34 0.01 1 10.00 20.00 Module#inline_c_gen
53
+ # 0.00 0.34 0.00 1 0.00 0.00 Module#include
54
+ # -- CUT ALL FOLLOWING LINES WHERE %time == 0.00
55
+
56
+ # The first example's cumulative time for Array#average was 6.83
57
+ # seconds (wallclock) and the second example's average
58
+ # (Mod_Array_average#average) was .26 seconds (a 26x speedup). The
59
+ # rest of the time was spent dealing with RubyInline's compile of the
60
+ # code. Subsequent runs of the code skip most of RubyInline's work
61
+ # because the code has already been compiled and it hasn't changed.
62
+ # Looking at the profile, there was really nothing more that we wanted
63
+ # to speed up. If there was, then we would have done a few more
64
+ # iterations of using RubyInline to extract slower ruby code into
65
+ # faster C code and profiling again.
66
+ #
67
+ # At this point, we were satisfied with the time of the code and
68
+ # decided to stop profiling. All that was left to do was to run with
69
+ # 'time' again and our larger dataset:
70
+
71
+ # & time ruby ./example2.rb 5 100000
72
+ # .....
73
+ #
74
+ # real 0m1.403s
75
+ # user 0m1.120s
76
+ # sys 0m0.070s
77
+ # (user+sys = 1.190s)
78
+
79
+ # We've reduced the running time of the program from 3.40s of CPU time
80
+ # to 1.19s of CPU. This is a speed-up of 2.85. Not too shabby...
81
+
82
+ # You don't want to compare the runtime of the profiled code because
83
+ # the cost of running with set_trace_func is so great that it skews
84
+ # the results heavily. Looking at the ratio between the normal run
85
+ # versus the profiled runs between the pure ruby and the inlined
86
+ # versions shows this skew quite clearly:
87
+
88
+ # norm prof
89
+ # ruby 3.40 6.83 (1:2 roughly)
90
+ # C 1.19 0.26 (5:1 roughly)
91
+
92
+ # This happens simply because our call to Mod_Array_average.average
93
+ # causes 30000-1 less method calls than the pure ruby version. This
94
+ # translates directly into a multiplier per method call when using
95
+ # set_trace_func (which we estimate to be about 200us per call (6.83 /
96
+ # 30000) on my machine.
metadata ADDED
@@ -0,0 +1,52 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.1
3
+ specification_version: 1
4
+ name: RubyInline
5
+ version: !ruby/object:Gem::Version
6
+ version: 3.1.0
7
+ date: 2004-11-19
8
+ summary: Multi-language extension coding within ruby.
9
+ require_paths:
10
+ - "."
11
+ author: Ryan Davis
12
+ email: ryand-ruby@zenspider.com
13
+ homepage: http://www.zenspider.com/ZSS/Products/RubyInline/
14
+ rubyforge_project: rubyinline
15
+ description: "Ruby Inline is my quick attempt to create an analog to Perl's Inline::C. It
16
+ allows you to embed C or C++ external module code in your ruby script directly.
17
+ The code is compiled and run on the fly when needed. The ruby version isn't near
18
+ as feature-full as the perl version, but it is neat!"
19
+ autorequire: inline
20
+ default_executable:
21
+ bindir: bin
22
+ has_rdoc: false
23
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
24
+ requirements:
25
+ -
26
+ - ">"
27
+ - !ruby/object:Gem::Version
28
+ version: 0.0.0
29
+ version:
30
+ platform: ruby
31
+ files:
32
+ - History.txt
33
+ - Makefile
34
+ - Manifest.txt
35
+ - README.txt
36
+ - example.rb
37
+ - example2.rb
38
+ - inline.gemspec
39
+ - inline.rb
40
+ - inline-compat.rb
41
+ - test_inline.rb
42
+ - tutorial/example1.rb
43
+ - tutorial/example2.rb
44
+ test_files:
45
+ - test_inline.rb
46
+ rdoc_options: []
47
+ extra_rdoc_files: []
48
+ executables: []
49
+ extensions: []
50
+ requirements:
51
+ - A POSIX environment and a compiler for your language.
52
+ dependencies: []