Adobe Solution Partner

July 27, 2006

CFSwitch Hunt

Filed under: ColdFusion, Performance, SeeFusion — Tags: — Patrick Quinn @ 4:26 pm

We made an interesting discovery in a recent consulting engagement, and we wanted to share what we found with the community. The gist of what we found is that cfswitch, with a string expression, and especially under load, runs dramatically slower than the equivalent cfif-cfelseif-cfelse block. Here’’s what happened…

A customer purchased one of our one day remote consulting engagements. They reported an intermittent performance problem that they were unable to pin down. They were already a SeeFusion customer, so we used SeeFusion to generate stack traces on the running requests. This line showed up quite often in the traces we took:

"jrpp-27" prio=5 tid=0x09572cb0 nid=0x12d4 runnable [5da2f000..5da2fdb8]
  at java.lang.FloatingDecimal.readJavaFormatString(Unknown Source)
  at java.lang.Double.parseDouble(Unknown Source)

Elsewhere in the stack traces we saw evidence of cfswitch usage. So we did some further digging, and sure enough, the customer was using cfswitch tags inside query loops–not an uncommon practice at all. But the switch expressions were all strings. So here’’s the kicker. Under the covers, ColdFusion attempts to convert the switch expression to a floating point number, using Java’’s parseDouble method. If the conversion works, then ColdFusion uses the expression as a number. If the conversion fails, however, then an exception is thrown, and an exception stack is generated, but then ColdFusion handles the exception and uses the expression as a string. The problem is, that exception throwing and stack generation gets very, very expensive under load.

We cooked up some tests to verify, and sure enough, on average the performance difference between cfswitch with string expressions, and the equivalent cfif-cfelseif-cfelse blocks, was a 10-fold difference. Under load, that will multiply dramatically.

We had the customer convert their cfswitch blocks, and they had an immediate improvement in performance and stability. There were other things left to tune, but this was a primary culprit.

We also found evidence that the floating point conversion might be single-threaded, which would make matters even worse. But the evidence for this wasn”t clear, and there also appeared to be some variation across different VM versions, but we had to move on to other things and couldn”t pursue this other point.

Moral of the story–only use numeric expressions for cfswitch! Otherwise, use equivalent cfif-cfelseif-cfelse blocks. And this is especially true if your code will be running under heavy load.

Test files

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • LinkedIn
  • StumbleUpon
  • Technorati
  • TwitThis

10 Comments »

  1. You all submit this to the CF Engineering team? Seems like it might be useful information they could use in tuning Scorpio.

    Comment by Rob Brooks-Bilson — July 27, 2006 @ 12:00 am

  2. This is very interesting indeed! It really goes against what I had thought to be true. But I am a huge proponent of the idea that the proof is in the pudding (mmm, pudding). If tests say strings are slower in swtich, then I believe it. Thanks for doing the tests.

    Comment by Ben Nadel — July 27, 2006 @ 12:00 am

  3. You don’t mention a version number. Was it CFMX7.x? Would you surmise that it would happen in CFMX as well?

    Comment by Al Everett — July 28, 2006 @ 12:00 am

  4. Thank you so much for blogging your findings. I’ve always found cfswitch awkward to use (perhaps because I have to type a few more chars?) but recently I made the effort to switch to cfswitch because the CF docs state that this is more efficient. I quote: “The cfswitch tag provides better performance than a series of cfif/cfelseif tags, and the code is easier to read.”

    Your findings fly in the face of the docs so I hope Adobe will take note, investigate this matter and amend the docs if necessary. Now I can return to using lovely CFIF tags. :-)

    Comment by Gary Fenton — July 28, 2006 @ 12:00 am

  5. wow.

    I’m cringing at my old projects floating around with this not-obvious time bomb in it… all for the sake of code readability…

    you contacted any CF engineers about this? the forthcomming CF8 ‘n’ all…

    Comment by barry.b — July 29, 2006 @ 12:00 am

  6. I just want to be 100% sure before I make a change to a piece of high traffic logging code on House of Fusion. Your saying that this code segment:
    CFSWITCH expression="#arguments.agent#"
    CFCASE value="Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)"
    CFRETURN 20
    /CFCASE
    CFCASE value="Googlebot/2.1 (+http://www.google.com/bot.html)"
    CFRETURN 12
    /CFCASE
    /CFSWITCH

    Will run slower than this one:
    CFIF Not CompareNoCase(arguments.agent, ‘Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)‘)
    CFRETURN 20
    CFELSEIF Not CompareNoCase(arguments.agent, ‘Googlebot/2.1 (+http://www.google.com/bot.html)’)
    CFRETURN 12
    /CFIF

    Is there a break point on the amount of cases/CFELSEIFs that will show a performance gain? Such as 10 CFCases or better show the CFSWITCH to be better than 9 CFELSEIFs when dealing with strings.

    Comment by Michael Dinowitz — August 1, 2006 @ 12:00 am

  7. On the previous comment, is it better to use a number of smaller CFIF statements or one large CFIF/CFELSEIF where possible?

    Comment by Michael Dinowitz — August 1, 2006 @ 12:00 am

  8. Have there been any updates to this? Has Adobe contacted you about this and commented? At my company, we use case statements all the time and it would really suck for this to be true.

    I also have some of the same questions as others. Is there a tipping point at which one becomes more efficient than the other?

    Also, do you have any code you could offer for use in testing?

    Comment by Andy Matthews — January 29, 2007 @ 12:00 am

  9. Hey Andy. Yes, we did talk directly with some of our contacts on the ColdFusion engineering team, and this was a confirmed problem/bug. They acknowledged it to us and elsewhere around the Web.

    It should be noted that this is only a problem with <cfswitch> inside of loops, particularly large loops. We got lots of questions on this from Fusebox 3 customers along the lines of–do we need to rewrite all our fbx_switch files!? The answer is very definitely no. You shouldn’t see any performance problems with a single pass over a switch statement. However, if you’ve got a switch statement with a string expression inside even a small loop–say, 100 iterations–then you’ll almost certainly see a performance boost by changing those to the equivalent if-else block.

    The tipping point would probably vary a bit for different applications. In the case of our customer, the loops were above 1,000 iterations. You’d have to test your system specifically to see what your tipping point is.

    I’ve posted (above) a version of the tests we ran to document the initial performance differences. Later tests were a bit more complicated, but this gives you the gist.

    Comment by Patrick — February 7, 2007 @ 12:00 am

  10. Good news. I got around to trying this in CF8 today and the problem seems to be resolved.

    Comment by Brad Wood — November 21, 2007 @ 12:00 am

RSS feed for comments on this post. TrackBack URL

Leave a comment

 

Server Down?

Maximize Web application uptime by drawing upon Webapper's years of experience tuning and stabilizing many of the world's largest ColdFusion Web applications. Contact us today!