Category Archives: ExtJS

How something you can’t see affects your app’s performance

It started with a simple bug report: PartKeepr, which uses ExtJS for its frontend magic, eats 30% CPU performance on a user’s system.

I blindly asked the user about his system specs, because I believed it was yet another ultra-low-performance system and suspected that it was one of those things (again). I’ve had several personal complaints about slow performance (that usual “PHP is slow and JS is even slower” yadda-yadda). One of those complaints turned out that the user tried to run PartKeepr on Firefox (which had an awfully slow JS implementation at that time) which, in turn, ran on his 500 MHz AMD Geode Platform. After suggesting to try out Google Chrome, he was amazed how fast a JS application actually can be on a slow system.

 

After asking the user for his system specs, I felt that I should verify the issue on my system to tell the user something like “look, it runs without any CPU problems here, please investigate and try another browser”. But to my surprise, even on my Intel Core i7-950 Workstation, the Chromium task manager revealed that the tab would take 30% CPU time – there’s clearly something wrong.

 

I am using ExtJS as a developer for almost 4 years now, but as I do projects in my spare time, I don’t dig inside JS debugging on a daily basis, but I knew that Chromium has quite some powerful tools built-in. I opened up the “Timeline” tab in the developer tools, hit the “record” button and recorded data for 2 seconds. To my surprise, there were 2 timers, which were fired and seem to go on like forever – in my example, hovering over the timer reveals quite some useful information. I’m not confident what these values mean in detail, but one thing is for sure: A fired timer  which lasts for the overall span of the recorded events isn’t what I intended when I wrote PartKeepr.

The big question remains: How to debug this? The timer event information was no help at all, because it referred to the timer mechanisms inside ExtJS, which most likely aren’t the cause. So I decided to do something very simple and quick: Go through the Ext.application “launch” method and see when things start to go wrong.
I quickly identified that the problem was my status bar and the time display immediately came into my mind. The time is refreshed every 240 ms, simply because making that one second causes it to sometimes skip a second, due to the overhead of the refresh method itself. To understand what’s going wrong, we need to have a look at the implementation:

As you can see, rendering of the component causes the trouble to start: Every time the onUpdate method is called, it defers itself. This probably adds quite lots of data to the stack, as I also noticed that the memory usage in that tab would grow.

As a first start, I rewrote the timer using the Ext.TaskManager:

For testing purposes, I’ve picked 100 ms as interval, and to my surprise, the CPU load was still pretty high – around 18% and the memory usage still raised by a few hundred KB each second. So what’s going on here?

I quickly figured out that it had either this.setText(), Ext.Date.format() or Ext.getDateFormat() – because when I commented the line out, memory usage was nearly constant and the CPU was nearly idle. As expected, Ext.Date.format() or Ext.getDateFormat() weren’t the culprit – setText was.

Ext.toolbar.TextItem.setText doesn’t only update it’s child element, but also triggers a call to updateLayout(), which needs to go through the complete layout tree. The question is: How to get around this?

The answer is pretty simple: Update the element manually and skip layout calculation when a new text is set. And this also has drawbacks. One issue is that updateLayout() is required if the text length changes. This will happen when updating the time, but also will happen when switching locales, which results in unpredictable length changes of the widget. My decision was straightforward here: Update the layout of the widget every 10 seconds, and only then update a new date format.

The full code for this modification can be found at github.

I was pretty proud that I found this issue in a reasonable amount if time – but it’s computing after all, which means that Murphy’s law sometimes grasps in. After I commented everything else back in, the CPU usage was still around 6% idle.

I started commenting several things in and out, and I found another little gem: The fading system notice button!

This cute little button informs the user that the system has a new, unread notice for him to read. To get the user’s attention, the button’s icon fades in and out. However – it fades in and out all the time, and even if the button is hidden!

Due to the lessons learned from the time display, it was also very easy to fix that: Add the task as done previously and only fade the button when it’s really needed. Additionally, one fade cycle only happens every 10 seconds, so that the user doesn’t get distracted too much. It still eats 7% CPU on my machine when fading, but it’s a fair trade, since system notices are rare and there’s a 9 second pause with almost no CPU usage.

The code for this bit is also at github.

Finally, there’s only one timer process visible in the developer tools – which is the time update. Also, the effectively used time went from 30% down to 0.000007449% (yes – during 6.9 seconds of recording, the status bar update took only 0.512ms, not seconds), so this is a brilliant optimization result.