RubyInline 3.1.0

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