Still haven't been able to identify the source of the slowness with Apache's ab tool. I've seen the numbers you're seeing Kev. When using httperf with production & APC the benchmark numbers are indicative of how they actually feel when using an application from the browser. I haven't installed this benchmark suite on the slice, may try that soon, so I don't have a frame of reference but I am suspecting somewhere between Zend/Cake and Kohana/CI.
For a 'hello world' benchmark the motivation is that you're supposed to get a sense of the critical path of a framework. "How long does it take for a request to an app with one route to a pass-thru controller and a view that prints hello world?" Rasmus first popularized this benchmark a couple years back. The numbers were most interesting then because frameworks hadn't yet been built specifically to kill 'hello world'.
A Digression on How Doo Wins the 'Hello World' Benchmark
====================================
I don't believe this benchmark is irrelevant, but do understand what this benchmark is measuring
and how a framework like Doo achieves 8x performance over Zend. I'm going to pick on one aspect of Doo's implementation real quick because it demonstrates why optimizing for (and winning) a 'hello world' benchmark can be naive and dangerous.
Let's focus on routing. Three quick references:
* Hello World app routes.php:
http://github.com/joshdavey/framark/blob/a6c9033fc2273abab4195729c2d8be7d3910e298/projects/doo-1.0/app/protected/config/routes.conf.php
* Routing Documentation:
http://doophp.com/doc/guide/basic/routes * Router Implementation:
http://github.com/joshdavey/framark/blob/a6c9033fc2273abab4195729c2d8be7d3910e298/projects/doo-1.0/dooframework/uri/DooUriRouter.php
Routes in Doo are a multidimensional PHP array of arrays. The first dimension is 'http method', the second is 'uri', i.e. $route['*']['/'] means all methods for URI /. Similarly $route['get']['/person/:id'] means GETs to URI /person/$id where ID is variable. When programming in Doo you are authoring these routes in one PHP file in one big array.
Now, looking at lines 231 through 320 of the DooUriRouter we can see how a route is chosen. If there is a static match on the URI, meaning no ':dynamic/:parts', a match is immediately found and returned in lines 231 through 240. This is the path the hello world benchmark takes, simple, fast, immediate. In a real application, where there are paths with dynamic parts, every single route in the app (even static ones) is iterated through, exploded, and compared. If more than one match in the exploded array size is found (i.e., if you used a convention like: '/person/:id', '/car/:id', these would both be initial hits for a request on '/foo/bar') then all matches are iterated through again and regex/string comparisons occur on their parts. This leads to a runtime of O(# routes) + O(# matching routes with/same/part/count).
What's the big deal? As your Doo app grows in complexity your performance degrades linear to the number of routes you have (and 2x linear if your routes are mostly of/similar/depth). For a trivial app with 5 routes this means the routing code is at least 5x-10x slower than routing in hello world. For a non-trivial app with 50 routes Doo's routing code becomes 50-100x slower.
Compare this to Recess where routes are specified in annotations on controllers. In production routes wind up cached in a serialized tree. Recess takes a performance hit by having to retrieve routes from cache (hopefully APC/memcache/memory) and deserialize. From there Recess does a recursive descent matching each part of the route. So the runtime complexity is based on the depth of the request url, i.e. this/route/request will be resolved in 3 steps (or less, if there isn't a match). Notice the ammount of PHP run to decide a route does not depend on the number of routes, but rather the depth of a URL.
So in a Hello World benchmark Recess' routing will always be slower than Doo's with the additional overhead of uncaching/unserializing. However, as the # of routes in your application's grows Recess' routing performance will remain roughly the same while Doo's degrades by 1-2x with every additional route.
Wow, that was a bigger digression than I was hoping for. Point being: techniques to be the fastest framework with 'hello world' don't imply techniques for being a fastest framework in the 'real world' :)
Back to Kev's Email
============
I will make another push to look into the horrible AB performance with this next iteration of Recess for 5.3. Hello world perf is looking competitive (not on Doo's scale) with httperf and there are some things in the critical path (like loading a PDO object for your databases) that should be lazy and could improve it even further. If anyone else loves perf and would like to help profile/optimize shoot me an email.
At the end of the day, though, it should be clear that the #1 'benchmark' Recess is focused on is the programmability model and internal architecture. So far we've done a great job on them both without sacrificing performance. In fact, we're incredibly well with performance given the annotations/meta-programming model we've pushed forward.
I wouldn't lose sleep at night because we aren't winning the 'Hello World' benchmark race. I *would* lose sleep at night if our framework required central configuration in large PHP arrays or if the performance of Recess applications degraded significantly as they became more complex. What I am losing sleep over right now is ensuring we've got the best foundation possible for PHP 5.3 and beyond. The promise of PHP 5.3, with features like namespaces, late static binding, and closures, is that Recess 5.3 will be way faster as namespaces replace the Library
and have a better programmability model.
That's all, for now. Hope everyone has had a great weekend!
-Kris