{
    "href": "/post/2005/09/22/benchmarking-call-user-func-array/",
    "relId": "2005/09/22/benchmarking-call-user-func-array",
    "title": "Benchmarking call_user_func_array()",
    "author": "pmjones",
    "markup": "html",
    "tags": [
        {
            "href": "/tag/benchmarks/",
            "relId": "benchmarks",
            "title": "Benchmarks",
            "author": null,
            "created": null,
            "updated": [],
            "markup": "markdown"
        },
        {
            "href": "/tag/php/",
            "relId": "php",
            "title": "PHP",
            "author": null,
            "created": null,
            "updated": [],
            "markup": "markdown"
        }
    ],
    "created": "2005-09-23 01:49:51 UTC",
    "updated": [
        "2005-09-23 01:49:51 UTC"
    ],
    "html": "<p>Andreas Korthaus wrote the <a href=\"http://phpsavant.com\">Savant</a> mailing list recently with some interesting benchmark numbers on Savant3 and the output escaping routines.  He wrote up a quick template script (in PHP of course) and used the Savant eprint() method 300+ times to escape output (which itself uses only htmlspecialchars() by default).  Then he ran the script; the time to run was ...</p>\n<blockquote>\n<p>\nResult: 161 ms</p>\n<p>...</p>\n<p>After that I looked at the cachegrind listings to find out<br>\nwhere some noticable time is lost. Looks like escaping costs a<br>\nlot of time, so I changed my templates not to use output<br>\nescaping:</p>\n<p>Result: 12 ms!!!</p>\n<p>No, I did not forget a digit ;-)</p>\n<p>...</p>\n<p>So it seems the way escaping is implemented, hurts performance<br>\nvery much!\n</p>\n</blockquote>\n<p>That very dramatic difference in running times (14x!) looked mostly due to the fact that he wasn't using htmlspecialchars() on the echoed output.  Then he changed all the \"echo\" to \"echo htmlspecialchars()\" and claimed only a 1.5ms difference.  Followup emails from his continued benchmarking noted the slow-points in Savant were related primarily to call_user_func_array() calling the escaping functions, although the output escaping itself also adds running time.</p>\n<p>All this piqued my interest to see the speed difference between using native functions, user-defined functions, objects, variable-functions, and the call_user_func[_array]() functions.  For an experiment, I wrote a user-defined function ...</p>\n<pre>\n// mimics htmlentities() as a user-defined function\nfunction html($value)\n{\n\treturn htmlentities($value);\n}\n</pre>\n<p>... and a user-defined class:</p>\n<pre>\nclass example {\n\t// mimics htmlentites() as a method\n\tfunction html($value)\n\t{\n\t\treturn htmlentities($value);\n\t}\n}\n</pre>\n<p>Then I wrote a script to make 100,000 calls to each of these:</p>\n<ul>\n<li>htmlentities($value)\n\t</li>\n<li>html($value)</li>\n<li>$func($value) <i>where $func = 'html'</i>\n</li>\n<li>$object-&gt;html($value) <i>where $object = new example()</i>\n</li>\n<li>$object-&gt;$func($value)</li>\n<li>call_user_func($func, $value)</li>\n<li>call_user_func(array($object, $func), $value)</li>\n<li>call_user_func_array($func, array($value))</li>\n<li>call_user_func_array(array($object, $func), array($value))</li>\n</ul>\n<p>One set of representative results from my Mac Mini (PHP 5.1rc1), in seconds:</p>\n<pre>\nname            : diff     : description\nnative          : 0.614219 : htmlentities($value)\nliteral_func    : 0.745537 : html($value)\nvariable_func   : 0.826048 : $func($value)\nliteral_method  : 0.957708 : $object-&gt;html($value)\nvariable_method : 0.840837 : $object-&gt;$func($value)\ncall_func       : 1.006599 : call_user_func($func, $value)\ncall_object     : 1.193323 : call_user_func((array($object, $func), $value)\ncufa_func       : 1.232891 : call_user_func_array($func, array($value))\ncufa_object     : 1.309725 : call_user_func_array((array($object, $func), array($value)\n</pre>\n<p>Here's another one:</p>\n<pre>\nname            : diff     : total\nnative          : 0.772733 : 0.772733\nliteral_func    : 0.737210 : 1.509943\nvariable_func   : 0.807990 : 2.317933\nliteral_method  : 0.820931 : 3.138864\nvariable_method : 0.821516 : 3.960380\ncall_func       : 1.006845 : 4.967225\ncall_object     : 1.210223 : 6.177448\ncufa_func       : 1.114493 : 7.291941\ncufa_object     : 1.307970 : 8.599911\n</pre>\n<p>And another, just for good measure:</p>\n<pre>\nname            : diff     : total\nnative          : 0.613295 : 0.613295\nliteral_func    : 0.733299 : 1.346594\nvariable_func   : 0.815782 : 2.162376\nliteral_method  : 0.965143 : 3.127519\nvariable_method : 0.842771 : 3.970290\ncall_func       : 1.023640 : 4.993930\ncall_object     : 1.221747 : 6.215677\ncufa_func       : 1.104610 : 7.320287\ncufa_object     : 1.449468 : 8.769755\n</pre>\n<p>So native calls to htmlentities() are twice as fast as doing effectively the same thing via call_user_func() with an object method, and using call_user_func_array() is 10-20% slower than using call_user_func().  I hadn't realized the differences in speed of execution would be so distinct; of course, I never really thought about it before, either.  Clearly PHP has to do a lot more work behind the scenes to map the variables to objects and parameters when using call_user_func_array().</p>\n<p>You can download the very simple func_speed.php script <a href=\"http://paul-m-jones.com/public/func_speed.phps\">here</a>.</p>\n<p>Um, you'll need <a href=\"http://solarphp.com\">Solar</a> for it (sorry about that, I used the debug-timer object for the testing).</p>\n"
}
