| Mantis - Quercus | |||||
| Viewing Issue Advanced Details | |||||
|  | |||||
| ID: | Category: | Severity: | Reproducibility: | Date Submitted: | Last Update: | 
| 2981 | minor | always | 09-30-08 08:40 | 10-08-08 18:48 | |
|  | |||||
| Reporter: | ferg | Platform: | |||
| Assigned To: | ferg | OS: | |||
| Priority: | normal | OS Version: | |||
| Status: | closed | Product Version: | 3.2.1 | ||
| Product Build: | Resolution: | fixed | |||
| Projection: | none | ||||
| ETA: | none | Fixed in Version: | 3.2.1 | ||
|  | |||||
| Summary: | 0002981: include performance issues | ||||
| Description: | (rep by Steven Grimm) Over the weekend I did a little bit of profiling of Quercus. There are two hotspots where Quercus is spending a lot of time when it goes through our big big list of include files. My test was just running "ab" to serially fetch a dummy .php file that contained nothing but an include_once of our top-level master include file. First, Quercus is checking the modification times on each original PHP file on every run. I don't see a config option to only do that periodically (though I may have missed something obvious) -- it's actually quite expensive, accounting for nearly 1/4 of the wall time of my test. That's possibly not a huge deal in a development environment but in a production environment we'd probably want to only check mod times once a minute or so since on-the-fly edits are extremely rare. Second, it's spending tons of time assembling the include file paths. To support multiple developer sandboxes, our include statements are all dynamic, like: include_once $_SERVER['PHP_ROOT'] . '/lib/display/pages.php'; and we set PHP_ROOT in the Apache virtual host config (on vanilla PHP) or in the Resin config. That ends up generating Java code like: env.includeOnce(_quercus_selfDirectory, v__SERVER.get(qv_PHP_ROOT_0).toStringBuilder(env).append(_qc_libdisplaypagesphp).toString(), false); According to the profiling, a huge amount of time is being spent in the various parts of that chain of string operations, primarily in the append() method which appears to need to do a reallocation of its buffer for each and every one of these includeOnce() calls. This may be related to bug 2971. Maybe this can instead do some compile-time evaluation of the paths, like: if (v__SERVER.get(qv_PHP_ROOT_0).equals("/path/at/compile/time")) { env.includeOnce(_quercus_selfDirectory, "/path/at/compile/time/lib/display/pages.php", false); // and ideally all the other adjacent includes that depend only on $_SERVER['PHP_ROOT'], // though the get().equals() is probably not too expensive to do for each one } else { // do the dynamic include as above, *and* trigger a background recompile of the page } That would basically eliminate the string construction cost of all these includes, of which we have zillions since each module "include_once"s its direct dependencies whether or not those dependencies were already included earlier in another module. (There are currently 18094 include_once statements in our code base, to give you some idea, though not all of them are hit on every request.) But maybe there's another way to make this fast; the above is just the first thing that comes to mind. Once we have a fix for 2971 in hand, and hopefully for the issues above too, we'll do another round of benchmarks/profiling and see where things stand. | ||||
| Steps To Reproduce: | |||||
| Additional Information: | |||||
| Relationships | |||||
| Attached Files: |  bench.php [^] (1,412 bytes) 10-05-08 12:25 | ||||
| Notes | |||||
|  | |||||
| 
 | 
 | ||||
|  | |||||
| 
 | 
 | ||||
|  | |||||
| 
 | 
 | ||||