Response time problem

About your application’s environment
Ruby version 1.8.6 (x86_64-linux)
RubyGems version 1.0.1
Rails version 2.0.2
Active Record version 2.0.2
Action Pack version 2.0.2
Active Resource version 2.0.2
Action Mailer version 2.0.2
Active Support version 2.0.2
Application root …
Environment development
Database adapter mysql
Database schema version 23

The controller passes @selectedLandmarkList and @availLandmarkList to
the view which populates a couple of selection lists with the same.
The problem occurs when I have about 8900 items in each list.

Rendering template within layouts/admin
Rendering data_entry/add_waypoint
Rendered data_entry/_waypoint_landmark_table (0.35038)
Rendered data_entry/_waypoint_form (0.42428)
Rendered layouts/_admin_menu (0.00458)
Completed in 198.55079 (0 reqs/sec) | Rendering: 0.43816 (0%) | DB:
0.07019 (0%) | 200 OK [http://localhost/data_entry/add_waypoint]

I can eliminate the error by not populating one of the lists in which
case the response is as below.

Rendering template within layouts/admin
Rendering data_entry/add_waypoint
Rendered data_entry/_waypoint_landmark_table (0.12888)
Rendered data_entry/_waypoint_form (0.13201)
Rendered layouts/_admin_menu (0.00488)
Completed in 0.70847 (1 reqs/sec) | Rendering: 0.22962 (32%) | DB:
0.06943 (9%) | 200 OK [http://localhost/data_entry/add_waypoint]

My question is how can things break by just addition of another 8900
items to another list item? Is this a defect? I haven’t noticed
this problem when I was on 1.2.6.

The code snippet in the controller that is different for both cases is
something like this

if params[:selectedLandmark].length > 50
flash[:notice]=“…”
—> params[:selectedLandmark].each { |itr|
@selectedLandmarkList += @availLandmarkList.select{ |v|
(v[1].to_s==itr)? true : false }
}
else …

If I get rid of the iterator which basically doesn’t do much, the
response time is fast as the second list is empty. I don’t understand
why it is slow in the first case.

—> params[:selectedLandmark].each { |itr|
@selectedLandmarkList += @availLandmarkList.select{ |v|
(v[1].to_s==itr)? true : false }
}
else …

If I get rid of the iterator which basically doesn’t do much, the
response time is fast as the second list is empty. I don’t understand
why it is slow in the first case.

Well you may not think you’re doin very much but for each thing
selectedLandmar you’re iterating over availLandmarkList once, so if
these are both 9000 items long then you’re ending up doing something
81 million times. But whatever the reason is, the real answer is to
stop guessing and use a profiler (eg ruby-prof) to find out where the
time is going.

Fred

Thanks for mentioning ruby-prof. I haven’t used a profiler for Ruby
before and I like it. I put the RubyProf.start at the start of the
controller action and RubyProf.stop at the end of the controller
action and the results are as expected.

Thread ID: 46912571459280
Total: 914.720000

%self total self wait child calls name
46.31 759.76 423.65 0.05 336.06 8852 Array#select
(ruby_runtime:0}
16.02 146.53 146.53 0.00 0.00 78251690 Fixnum#to_s
(ruby_runtime:0}
10.41 95.22 95.22 0.00 0.00 78243001 Array#[]
(ruby_runtime:0}
10.37 94.89 94.89 0.00 0.00 78252170 String#==
(ruby_runtime:0}
1.94 30.28 17.73 0.14 12.41 53050
Module::Benchmark#realtime (/usr/lib/ruby/1.8/benchmark.rb:306}
0.92 8.43 8.43 0.00 0.00 1697290 Kernel#sprintf
(ruby_runtime:0}
0.76 20.79 6.94 0.01 13.84 17680 String#each_byte
(ruby_runtime:0}
0.45 4.23 4.14 0.00 0.09 53050 Mysql#query
(ruby_runtime:0}

I have fixed the workflow of the application so that I dont end up
with two lists of 9K each, but if I do end up with two lists of these
sizes that I need to manage in the future, any other tricks I can use
or do I need to change data structures and design only?

Thanks,
Mukund

On Mar 23, 3:02 am, Frederick C. [email protected]

On 27 Mar 2008, at 08:46, Mukund wrote:

Thanks for mentioning ruby-prof. I haven’t used a profiler for Ruby
before and I like it. I put the RubyProf.start at the start of the
controller action and RubyProf.stop at the end of the controller
action and the results are as expected.

Well the basic problems is that if your lists are of length m and n
then what you’ve got there has complexity O(mn) (which shows up as the
80 million calls to those functions).
I’d also query the efficiency of any action that results in Mysql
being queried 50000 times. If you stored @availLandmarkList as a hash
rather than as an array you’d avoid the linear time search for every
element of params[:selectedLandmark].

Fred.