ColdFusion createObject "Component" and Pathing Performance

I haven't blogged in awhile due to schedule, but had to blog this experience I recently had while attempting to stabilize an application and enhance performance.

I have always taken for granted that createObject was lightning fast... Well, as fast as feasibly possibly under a given JVM.

I think I was dead wrong and this may be an issue for Adobe to address. I am unclear on the internals of course. But I have been up against OOMs on my current project and wanted to test out using soft reference (cached objects) and use duplicate from the cache rather than createObject.

Far stretch I know... but hey it was worth a try. What was revealed was that performance was negligible and createObject was faster in some intervals. Memory behaved the same, no real bonus. So in discussion with a fellow consultant I told him I'd ship a zip to him for test purposes as he had said he'd seen a significant performance enhancement with duplicate (not true by the way).

What happened next totally shocked me. To simplify the test code I snagged my VO.cfc out of it's proper place (several dirs down i.e. sitedir, com, bus, app, model, vo.. you get the idea) and put it in the root of the calling cfm. I then removed all the pathing (dot notation) from my createObject call and executed the cfm to see if it would run ok after the change.

The test was a loop of 10k over this create object call. I was seeing execution times of around 30 seconds. When I ran the updated code it went to 577 milliseconds... I am still befuddled by this. Is there that much overhead with pathing?

I initially thought it was a mapping issue because I had been using mappings, but absolute path from root was just as slow.

Please Adobe tell me this is Sun's jvm and not your code. I know this is negligible with 100 or so creates, but imagine the boost if I did find something here.

For clarification I am running on a Mac (OS X, CF running in JBOSS), but also tested on my old Dell (XP, CF running in JRUN). I didn't see as dramatic a difference on WIntel, but my exec time went from 30 seconds to 4 seconds. I am happy with 10x faster on Windows too...

Any insight here is greatly appreciated. Example Code:

<cfscript>
      currentTime = now();
    rqaArray = arrayNew(1);
    initTime = getTickCount();
         for (index=1; index lte 10000; index = index + 1)
{
    // pathing example replace vo reference with     //this pathing call com.mercer.mercerOnline.model.RQASummaryVO
    rqa = createObject("component","RQASummaryVO");
    rqa.rqaID = index;
            rqa.type = "theType";
            rqa.createDate = currentTime;
            rqa.submitDate = currentTime;
            rqa.client = "currentClient";
            rqa.clientID = "clientID";
            rqa.status = 6;
            rqa.userID = 123456;
            rqa.agencyID = "agencyID";
            rqa.predecessorID = 0;
            rqa.locked = false;
            rqa.deleted = false;
            rqa.title = "The Title "&#index#;
            rqa.policyNumber = "thePolicyNum";
            rqa.agencyName = "agencyName";
            rqa.totalPremium = "totalPremium";
            rqa.hasMessages = false;
            rqa.isAssigned = false;
            rqa.assignedTo = "";
            rqa.proposedEffDate = currentTime;
    rqa.proposedExpDate = currentTime;
    rqa.agentName                     = "agentName";
            ArrayAppend(rqaArray,rqa);
         }

         endTime = getTickCount();

         totalTime = endTime - initTime;
</cfscript>
<cfdump var="#arrayLen(rqaArray)#">
<cfdump var="#rqaArray[10000]#" />
<cfdump var="#totalTime#" />

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
That would truly be remarkable if pathing was causing such performance degradation! Have you profiled the code in each scenario to see if there's varying java execution under the covers in each scenario?
# Posted By Andrew Gscheidle's Standing Meeting | 12/12/08 5:11 PM
Short answer, yes it does have to do with CF server mappings.

The issue it's running up against is that the CF server mappings aren't restricted to &quot;atomic&quot; names.

I had actually made the comment during the Scorpio alpha that I felt that was... less than helpful. (I was actually not that pleasant about it.) But as Sean Corfield and a number of other folks already have mappings where the name of the mapping is something like &quot;/com/mycompany/thing/otherthing&quot;, what I was told was &quot;it works this way, it's not going to change, end of discussion&quot;.

Longer answer as to why this happens. When it enters the CreateObject call (or for that matter any cfinclude or cfmodule (with template attribute) call beginning with a forward slash, the server is required to launch through a barrage of possible combinations of virtual and relative paths. So if you've got the component path &quot;com.mycompany.package.with.stuff&quot; the server is going to rifle through this set of potential targets:

mapping /com/mycompany/package/with - stuff.cfc
mapping /com/mycompany/package - with/stuff.cfc
mapping /com/mycompany/package - with.stuff.cfc
mapping /com/mycompany - package/with/stuff.cfc
mapping /com/mycompany - package/with.stuff.cfc
mapping /com/mycompany - package.with/stuff.cfc
mapping /com/mycompany - package.with.stuff.cfc
mapping /com - mycompany/package/with/stuff.cfc
mapping /com - mycompany/package/with.stuff.cfc
mapping /com - mycompany/package.with.stuff.cfc
mapping /com - mycompany/package.with/stuff.cfc
mapping /com - mycompany.package.with.stuff.cfc
mapping /com - mycompany.package.with/stuff.cfc
mapping /com - mycompany.package/with/stuff.cfc

And that's on top of the fact that it does this same set of checks for different file paths across several contexts for each createobject call. So it's doing the above for each mapping, and then it's doing the same set of checks against relative paths and against the webserver root path (which actually is just a default mapping of &quot;/&quot; and is sometimes not correctly mapped). So long story short, the more dots, the longer it takes. The reason why relative components in the same directory execute so much faster is because that's the first check - it looks &quot;aha! it's right there!&quot; and short-circuits and doesn't do any of the subsequent checks.

Of course a lot of this overhead could be reduced instantly by eliminating the value-free feature of having non-atomic mappings. But that's what we've got and apparently that's what we're going to have in the foreseeable future, so I guess we have to just hope that 64-bit architectures will quickly make it a non-issue.
# Posted By ike | 12/12/08 7:10 PM
Ike, thank you for the reply, but I am seeing same exec. times whether using mappings or absolute path.

This is big enough from my point of view to avoid delegates, gateways, and daos in their respective directories and instead creating a class name folder with related cfcs (eg. delegatePerson, gatewayPerson... Person.cfc) and skip pathing.

The real quagmire is that you still will have to &quot;refer&quot; to the &quot;type&quot; with the appropriate path, I noticed that when cfdumping... You would think adobe would resolve this with a simple optional arg for the createObject function that would yield a constant under the covers identifying platform or what have you... Just some ideas.
# Posted By Strikefish | 12/14/08 8:47 PM
Nice find, Jeff. Very much along the lines of the old variables scoping issues as well. Best practice has always been to scope qualify all variables references precisely to eliminate the seek time ColdFusion will spend searching for variables reference matches across all different scopes.

Lucky for me, I've managed to stand by the principle of always keeping my CFCs in a simple one-directory structure with detailed filenames. It's always seemed simpler to me, and now it turns out it's a performance savings too. =)
# Posted By Tyson Vanek | 12/14/08 8:49 PM
@jeff -- well that's really what I was saying ... it doesn't matter whether you're actually using a mapping or not because the server is still going to *try* all those various different paths, merely because there are dots in your path -- hence the performance issue is irrespective of the use or non-use of mapping (but it exists because of the way the mappings work)
# Posted By ike | 12/14/08 9:30 PM
Would turning off typing checking help?
# Posted By Henry Ho | 12/15/08 7:56 PM
@Henry, CF is not a strongly typed language like Java, Actionscript or C#. This is an issue with under the hood code that I and other CF devs do not have access to.

It would have to be addressed by Adobe.
# Posted By Strikefish | 12/15/08 9:23 PM
The item Henry's talking about is in the settings page of the CF Administrator. It's labelled &quot;disable CFC type check&quot; and affects only type checking for CFCs when used for cfargument tags I think. Possibly cfparam although I'm not intimately familiar with it. There's a note on the description of the setting that says &quot;use this in production only&quot;, and I believe is considered best practice in production since all the code has been tested and shown to work, type checking of CFCs is no longer an issue at that point (we hope). ;) I get around that issue by using type=&quot;any&quot; in most of my cfargument tags personally (only for cfcs - I use numeric and string for simple values).
# Posted By ike | 12/15/08 11:25 PM
Oh I forgot to mention, that setting was added in CF8 - I don't remember if you said what CF version you're using, but on CF7 or prior you're right, you won't have that setting.
# Posted By ike | 12/15/08 11:26 PM
My mistake Ike, thanks, yes I am familiar with the disable type checking setting in the Admin.

I selected just to test which revealed no perf. increase.
# Posted By Strikefish | 12/16/08 9:46 AM
Nice find Jeff. I never would have thought something as simple as pathing is what's causing the slow performance. I sure hope Adobe offers an option in CF9 to enable path caching or some other solution. It's a shame we cant get the excellent instantiation speeds you posted simply because of pathing. Just think how much ColdFusion programming / development methodologies would have improved if we didn't have to deal with slow instantiation speeds (when using com.something.X paths). We wouldn't have had to resort to using IBOs instead of arrays of objects! I suppose for now I could just write a build script to move and rename all my CFCs in a project into a single directory, and then do a massive search and replace to update all CFC paths to point to the new file locations. Thanks for sharing your findings!!!
# Posted By Kurt Bonnet | 12/16/08 3:21 PM
Ike has nailed it. cfc path definitely affects the performance. And the order of search is - path relative to the calling template, path relative to the webroot, path relative to the application mapped folders and then path relative to the server mapped folder. More the search needed, more will be the performance hit.
We are looking at all the possible options including caching to reduce the performance cost.

Rupesh
Adobe ColdFusion Team
# Posted By Rupesh Kumar | 12/17/08 3:00 AM
@Rupesh,

I and the CF community thank you. I look forward to receiving an update from you sir.

Good Luck!!!
# Posted By Strikefish | 12/19/08 10:21 AM
I went back to this again today, and with trusted cache turned on, the performance difference for me reduced to a nearly insignificant difference.

this was, of course, using the unscientific &quot;hit refresh a bunch of times&quot; method.
# Posted By marc esher | 12/22/08 8:25 PM
@Marc, thanks, you are correct; this did resolve the issue, but having worked with CF since 98, trusted cache was created for &quot;templates&quot; .cfm pages.

I do not agree with the approach in place for the newer .cfc/components. It should be implemented in a different manner and not a global &quot;end all&quot; because many times in Dev environments trusted cache is turned off.

To be more specific, the algorithm for pathing whether cached .cfc or not should be handled differently it appears.

Thanks for the input!
# Posted By Strikefish | 12/29/08 12:17 PM

Copyright Strikefish, Inc., 2005. All rights reserved.