1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
|
== Performance Testing Built into Rails ==
As of June 20, 2008 edge rails has had a new type of Unit test geared towards profiling. Of course like most great things, getting it working takes bit of work. The test relies on statistics gathered from the Garbage Collection that isn't readily available from standard compiled ruby. There is a patch located at http://rubyforge.org/tracker/download.php/1814/7062/17676/3291/ruby186gc.patch[http://rubyforge.org/tracker/download.php/1814/7062/17676/3291/ruby186gc.patch]
Also the test requires a new version of Ruby-Prof version of 0.6.1. It is not readily available at the moment and can most easily be found as a tarball on github. It's repository is located at git://github.com/jeremy/ruby-prof.git.
What follows is a description of how to set up an alternative ruby install to use these features
=== Compiling the Interpreter ===
[source, shell]
----------------------------------------------------------------------------
[User ~]$ mkdir rubygc
[User ~]$ wget ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6-p111.tar.gz
[User ~]$ tar -xzvf ruby-1.8.6-p111.tar.gz
[User ~]$ cd ruby-1.8.6-p111
[User ruby-1.8.6-p111]$ curl http://rubyforge.org/tracker/download.php/1814/7062/17676/3291/ruby186gc.patch | patch -p0
#I like putting my alternative ruby builds in an opt directory, set the prefix to where ever you feel is most comfortable.
[User ruby-1.8.6-p111]$ ./configure --prefix=/opt/rubygc
[User ruby-1.8.6-p111]$ sudo make && make install
----------------------------------------------------------------------------
Add the following lines in your \~/.profile or \~/.bash\_login for convenience.
----------------------------------------------------------------------------
alias gcruby='/opt/rubygc/rubygc/bin/ruby'
alias gcrake='/opt/rubygc/rubygc/bin/rake'
alias gcgem='/opt/rubygc/rubygc/bin/gem'
alias gcirb=/opt/rubygc/rubygc/bin/irb'
alias gcrails='/opt/rubygc/rubygc/bin/rails'
----------------------------------------------------------------------------
=== Installing RubyGems ===
Next we need to install rubygems and rails so that we can use the interpreter properly.
[source, shell]
----------------------------------------------------------------------------
[User ~]$ wget http://rubyforge.org/frs/download.php/38646/rubygems-1.2.0.tgz
[User ~]$ tar -xzvf rubygems-1.2.0.tgz
[User ~]$ cd rubygems-1.2.0
[User rubygems-1.2.0]$ gcruby setup.rb
[User rubygems-1.2.0]$ cd ~
[User ~]$ gcgem install rake
[User ~]$ gcgem install mysql
[User ~]$ gcgem install rails
----------------------------------------------------------------------------
If installing mysql gem fails ( like it did for me ), you will have to manually install it :
[source, shell]
----------------------------------------------------------------------------
[User ~]$ cd /Users/lifo/rubygc/lib/ruby/gems/1.8/gems/mysql-2.7/
[User mysql-2.7]$ gcruby extconf.rb --with-mysql-config
[User mysql-2.7]$ make && make install
----------------------------------------------------------------------------
=== Installing Jeremy Kemper's ruby-prof ===
We are in the home stretch. All we need now is ruby-proff 0.6.1
[source, shell]
----------------------------------------------------------------------------
[User ~]$ git clone git://github.com/jeremy/ruby-prof.git
[User ~]$ cd ruby-prof/
[User ruby-prof (master)]$ gcrake gem
[User ruby-prof (master)]$ gcgem install pkg/ruby-prof-0.6.1.gem
----------------------------------------------------------------------------
Finished, go get yourself a power drink!
=== Ok so I lied, a few more things we need to do ===
You have everything we need to start profiling through rails Unit Testing. Unfortunately we are still missing a few files. I'm going to do the next step on a fresh Rails app, but it will work just as well on developmental 2.1 rails application.
==== The Rails App ====
First I need to generate a rail app
[source, shell]
----------------------------------------------------------------------------
[User ~]$ gcrails profiling_tester -d mysql
[User ~]$ cd profiling_tester
[User profiling_tester]$ script/generate scaffold item name:string
[User profiling_tester]$ gcrake db:create:all
[User profiling_tester]$ gcrake db:migrate
[User profiling_tester (master)]$ rm public/index.html
----------------------------------------------------------------------------
Now I'm going to init it as a git repository and add edge rails as a submodule to it.
[source, shell]
----------------------------------------------------------------------------
[User profiling_tester]$ git init
[User profiling_tester (master)]$ git submodule add git://github.com/rails/rails.git vendor/rails
----------------------------------------------------------------------------
Finally we want to change config.cache_classes to true in our environment.rb
----------------------------------------------------------------------------
config.cache_classes = true
----------------------------------------------------------------------------
If we don't cache classes, then the time Rails spends reloading and compiling our models and controllers will confound our results. Obviously we will try to make our test setup as similar as possible to our production environment.
=== Generating and Fixing the tests ===
Ok next we need to generate the test script.
[source, shell]
----------------------------------------------------------------------------
[User profiling_tester (master)]$ script/generate performance_test homepage
----------------------------------------------------------------------------
This will generate _test/performance/homepage_test.rb_ for you. However, as I have generated the project using Rails 2.1 gem, we'll need to manually generate one more file before we can go ahead.
We need to put the following inside _test/performance/test_helper.rb
[source, ruby]
----------------------------------------------------------------------------
require 'test_helper'
require 'performance_test_help'
----------------------------------------------------------------------------
Though this depends where you run your tests from and your system config. I myself run my tests from the Application root directory
so instead of
[source, ruby]
----------------------------------------------------------------------------
require 'test_helper'
#I have
require 'test/test_helper'
----------------------------------------------------------------------------
Also I needed to change homepage_test.rb to reflect this also
[source, ruby]
----------------------------------------------------------------------------
require 'test/performance/test_helper.rb'
----------------------------------------------------------------------------
=== Testing ===
Rails has two types of performance testing :
* profile - For finding out what's slow in something
* benchmark - For determining how fast is something
In other words, you first _benchmark_ your application to find out if something is not fast. And then _profile_ it to find out what exactly is slowing it down.
Now, if we look at the generated performance test ( one we generated using _script/generate performance_test_ ), it'll look something like :
[source, ruby]
----------------------------------------------------------------------------
.require 'performance/test_helper'
class HomepageTest < ActionController::PerformanceTest
# Replace this with your real tests.
def test_homepage
get '/'
end
end
----------------------------------------------------------------------------
The format looks very similar to that of an integration test. And guess what, that's what it is. But that doesn't stop you from testing your Model methods. You could very well write something like :
[source, ruby]
----------------------------------------------------------------------------
require 'performance/test_helper'
class UserModelTest < ActionController::PerformanceTest
# Replace this with your real tests.
def test_slow_find
User.this_takes_shlong_to_run
end
end
----------------------------------------------------------------------------
Which is very useful way to profile individual processes.
|