opsb-RubyInline 3.8.6

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,152 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: opsb-RubyInline
3
+ version: !ruby/object:Gem::Version
4
+ hash: 43
5
+ prerelease: false
6
+ segments:
7
+ - 3
8
+ - 8
9
+ - 6
10
+ version: 3.8.6
11
+ platform: ruby
12
+ authors:
13
+ - Ryan Davis
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-11-30 00:00:00 +00:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: ZenTest
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 29
30
+ segments:
31
+ - 4
32
+ - 3
33
+ version: "4.3"
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: rubyforge
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 7
45
+ segments:
46
+ - 2
47
+ - 0
48
+ - 4
49
+ version: 2.0.4
50
+ type: :development
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: minitest
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ hash: 15
61
+ segments:
62
+ - 2
63
+ - 0
64
+ - 0
65
+ version: 2.0.0
66
+ type: :development
67
+ version_requirements: *id003
68
+ - !ruby/object:Gem::Dependency
69
+ name: hoe
70
+ prerelease: false
71
+ requirement: &id004 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ hash: 19
77
+ segments:
78
+ - 2
79
+ - 6
80
+ - 2
81
+ version: 2.6.2
82
+ type: :development
83
+ version_requirements: *id004
84
+ description: |-
85
+ Inline allows you to write foreign code within your ruby code. It
86
+ automatically determines if the code in question has changed and
87
+ builds it only when necessary. The extensions are then automatically
88
+ loaded into the class/module that defines it.
89
+
90
+ You can even write extra builders that will allow you to write inlined
91
+ code in any language. Use Inline::C as a template and look at
92
+ Module#inline for the required API.
93
+ email:
94
+ - ryand-ruby@zenspider.com
95
+ executables: []
96
+
97
+ extensions: []
98
+
99
+ extra_rdoc_files:
100
+ - History.txt
101
+ - Manifest.txt
102
+ - README.txt
103
+ files:
104
+ - History.txt
105
+ - Manifest.txt
106
+ - README.txt
107
+ - Rakefile
108
+ - demo/fastmath.rb
109
+ - demo/hello.rb
110
+ - example.rb
111
+ - example2.rb
112
+ - lib/inline.rb
113
+ - test/test_inline.rb
114
+ - tutorial/example1.rb
115
+ - tutorial/example2.rb
116
+ has_rdoc: true
117
+ homepage: http://rubyforge.org/projects/rubyinline/
118
+ licenses: []
119
+
120
+ post_install_message:
121
+ rdoc_options:
122
+ - --main
123
+ - README.txt
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ none: false
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ hash: 3
132
+ segments:
133
+ - 0
134
+ version: "0"
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ none: false
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ hash: 3
141
+ segments:
142
+ - 0
143
+ version: "0"
144
+ requirements:
145
+ - A POSIX environment and a compiler for your language.
146
+ rubyforge_project: rubyinline
147
+ rubygems_version: 1.3.7
148
+ signing_key:
149
+ specification_version: 3
150
+ summary: Inline allows you to write foreign code within your ruby code
151
+ test_files:
152
+ - test/test_inline.rb