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:
The issue it's running up against is that the CF server mappings aren't restricted to "atomic" 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 "/com/mycompany/thing/otherthing", what I was told was "it works this way, it's not going to change, end of discussion".
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 "com.mycompany.package.with.stuff" 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 "/" 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 "aha! it's right there!" 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.
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 "refer" to the "type" 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.
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. =)
It would have to be addressed by Adobe.
I selected just to test which revealed no perf. increase.
We are looking at all the possible options including caching to reduce the performance cost.
Rupesh
Adobe ColdFusion Team
I and the CF community thank you. I look forward to receiving an update from you sir.
Good Luck!!!
this was, of course, using the unscientific "hit refresh a bunch of times" method.
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 "end all" 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!