4

I've heard that if you do not specify output="false" on a ColdFusion function that unnecessary buffering would occur which could hinder performance. So I wanted to run a test to see if I could prove this. My test is below. I saw no difference at all between output="true" or output="false".

So my question is: if I have functions used within large loops should I not have to worry about this setting? Or am I not testing this correctly?

My test was to call the same function 1,000,000 times. I ran it 3 times with output="false" and 3 times with output="true". All 6 tests finished at exactly 20-21 seconds.

enter image description here

The Test Code:

<cffunction name="good" output="false" returntype="Numeric" access="private">
    <cfargument name="numIn" type="numeric" required="true">
    <cfset var x = 0>
    <cfset x = arguments.numIn + 1>
    <cfreturn x>
</cffunction>

<cffunction name="bad" output="true" returntype="Numeric" access="private">
    <cfargument name="numIn" type="numeric" required="true">
    <cfset var x = 0>
    <cfset x = arguments.numIn + 1>
    <cfreturn x>
</cffunction>

<cfset loopNum = 1000000>

<cfset x = 0>
<cfoutput>
    x = #x#<br>
    Running bad function #loopNum# times...<br>
</cfoutput>
<cfset tBegin = GetTickCount()>
<cfloop from="1" to="#loopNum#" index="i">
    <cfset x = bad(i)>
</cfloop>
<cfset tEnd = GetTickCount()>
<cfset scriptTime = (tEnd - tBegin)>
<cfoutput>
    x = #x#<br>
    Time to complete: #scriptTime#<br>
</cfoutput>

<!---
<cfset x = 0>
<cfoutput>
    x = #x#<br>
    Running good function #loopNum# times...<br>
</cfoutput>
<cfset tBegin = GetTickCount()>
<cfloop from="1" to="#loopNum#" index="i">
    <cfset x = good(i)>
</cfloop>
<cfset tEnd = GetTickCount()>
<cfset scriptTime = (tEnd - tBegin)>
<cfoutput>
    x = #x#<br>
    Time to complete: #scriptTime#<br>
</cfoutput>
--->
gfrobenius
  • 3,987
  • 8
  • 34
  • 66
  • If you have a way of doing it, you might want to look at RAM useage. – Dan Bracuk Mar 18 '14 at 18:15
  • I don't know about buffering, but it WILL add white space and possibly carriage returns if you're using returntype="string". So if you expect to return "Hello", you sometimes get " Hello" or " \nHello" (where \n represents a carriage return. – Adrian J. Moreno Mar 18 '14 at 19:40
  • 1
    To clarify, when [I wrote](http://stackoverflow.com/questions/22465244/most-efficient-way-to-zip-files-using-coldfusion-or-java?lq=1#comment34174204_22465244) "unnecessarily buffer" I was referring specifically to adding whitespace to the output buffer. It is trivial to prove that this occurs, and - particularly without whitespace compression and/or gzipped requests - it is certainly an issue. – Peter Boughton Mar 18 '14 at 23:18
  • 1
    The 9..26 whitespace per function iteration in your example is going to accumulate to less than 10MB of memory which isn't really a significant amount in the graphs you show (there looks to be more random variation than that), but obviously when you have longer, nested functions and multiple loops and so on it can add up and become a significant factor (even without considering the HTTP side). And of course not outputting whitespace is always going to be faster than adding it then removing it (even if that difference is slight). – Peter Boughton Mar 18 '14 at 23:19

1 Answers1

3

I agree that it is best practice to always include output="false" in your functions unless you have a very specific and very good reason not to (it's okay in some of the Application.cfc methods like onRequest() for example). But I've never heard anyone say that the reason for this had anything to do with performance, either processor utilization or memory consumption. The primary reason I maintain it is so that you don't have sudden unexpected errors at runtime (caused by that same unnecessary buffering).

Here's an easy example:

<cffunction name="getFlag" output="true">
    <cfreturn true />
</cffunction>

<cfif getFlag()><p>Hello World!</p></cfif>

<cfxml variable="doc"><cfoutput><root flag="#getFlag()#" /></cfoutput></cfxml>

<cfif doc.root.xmlAttributes.flag><p>Hello world!</p></cfif>

You might write something like this, thinking everything should be fine, since the first <cfif> test works fine and you can dump out the xml document and it looks okay from the output of a <cfdump>. And then later you would get the error message this example creates:

cannot convert the value " true" to a boolean 

Because the white-space from the function bled into the XML attribute and while CF will allow you to treat the string "true" as a boolean, it won't convert the string " true". And then like many of us have before, you might spend a long time banging your head, trying to figure out why there's extra white-space in your XML document when there is no extra space in the return value from your function. It happened to me once when custom functions were introduced in CF5. ;)

Samuel Dealey
  • 263
  • 1
  • 7