I received an email a few days ago from a customer:
I’m loving your tool and using it to build a pretty extensive timeline for a project I’m working on. However, it seems to have stopped loading.
After a bit of troubleshooting, I realized that he had added so many events (217) that it took upwards of 30 seconds to load the page, causing Heroku to throw an error.
I decided to spend today seeing what I could do to speed things up a bit.
To do this, I created a timeline on my local machine and used the Rails console to add 50 events to it. I loaded it a few times and checked the server logs, which indicated that it took about 15 seconds to load on average. Eesh.
I set out to time all the major sections of code to see if I could determine what was taking the most time. I did this by creating a two methods on my Timeline class: initialize_ticker and tick:
attr_accessor :start_tick def initialize_ticker self.start_tick = DateTime.now.to_f end def tick(str) diff = (DateTime.now.to_f - start_tick) * 1000 puts 'Tick %sms - %s' % [diff.to_i, str] end
I called initialize_ticker at the top of the show method in the timeline controller and then added tick method calls to the top of every significant section of code. This let me narrow down where the slow code was. When I determined that something was slow, I added a few more tick method calls within the method to narrow it down even further. Once I had the block of code that was causing trouble, I tried to identify ways to improve it.
One of my major finding was that converting a DateTime object to a float (like in the code above) takes a nontrivial amount of processing time on the backend. Since Preceden’s code was doing this thousands of times whenever a timeline was loaded, it added a lot of time to each page view. Where I could, I started returning floats rather than DateTime objects so it wouldn’t have to be converted later on.
I made a lot of other changes too, but they’d be hard to explain without the context of the code.
tl;dr: I was able to get that 15 second page load down to about 700ms, an improvement of about 20x.
You notice it even more on timelines without a lot of events because what would take several seconds, is now almost instantaneous.
Not bad for a few hours of work.