Technical blog of COil: Symfony, PHP, PEAR & webdev

Strangebuzz...?

» Collapse all «

Tag - php

     

Thursday 21 February 2013

Twig C extension benchmark

Hi Symfonians,

Long time since my last post ! But it's mainly because I actually have a lot of work with Symfony2 projects. One of my current task is to optimize the performances of a Symfony2.0.x project. I was curious to test the Twig C extension to check if there was a real improvement before using it in our production environment. Here we go:

I will not describe the installation as it is very easy, just follow the official documentation. When the extension is correctly installed you have a new Twig entry in your phpinfo():


The benchmark


To test the extension, I choose the most complex page of the site (complex at the Twig level):

  • Renders a tree of about 500 checkboxes
  • Recursive include calls are made inside the templates
  • Widget rendering does not use the Symfony2 form helpers


The main template:

(Called 6 times with different data)

The recursive Twig template _group_tree.html.twig:

PS: Note here that we didn't used here a native Symfony2 form, because the rendering (bind + renderering) was taking about 5 seconds...

Test conditions:

  • Symfony 2.0.22, of course the production environment is used for the test.
  • PHP 5.3.2-1ubuntu4.18 with Suhosin-Patch (cli) (built: Sep 12 2012 19:12:47)
  • php app/check.php, no warning or error, APC is enabled with an APC autoloader.


Results without the extension:

  • 1000 iterations
  • Apache was restarted and Symfony2 cache was cleared between each test

The following results are the second run because the 1st run has to rebuild the Symfony cache.

[10:39:54] coil@ubuntu:~/Webdev$ ab -n 1000 http://dev.project.com/search
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking dev.project.com (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests

Server Software:        Apache/2.2.14
Server Hostname:        dev.project.com
Server Port:            80

Document Path:          /search
Document Length:        197192 bytes

Concurrency Level:      1
Time taken for tests:   99.232 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      197742000 bytes
HTML transferred:       197192000 bytes
Requests per second:    10.08 [#/sec] (mean)
Time per request:       99.232 [ms] (mean)
Time per request:       99.232 [ms] (mean, across all concurrent requests)
Transfer rate:          1946.03 [Kbytes/sec] received

Connection Times (ms)
	      min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:    95   99   4.4     98     190
Waiting:       92   96   4.2     95     187
Total:         95   99   4.4     98     190

Percentage of the requests served within a certain time (ms)
  50%     98
  66%    101
  75%    102
  80%    102
  90%    103
  95%    104
  98%    108
  99%    110
 100%    190 (longest request)


Results with the extension enabled:


[10:36:34] coil@ubuntu:~/Webdev$ ab -n 1000 http://dev.project.com/search
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking dev.project.com (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests

Server Software:        Apache/2.2.14
Server Hostname:        dev.project.com
Server Port:            80

Document Path:          /search
Document Length:        197192 bytes

Concurrency Level:      1
Time taken for tests:   84.887 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      197742000 bytes
HTML transferred:       197192000 bytes
Requests per second:    11.78 [#/sec] (mean)
Time per request:       84.887 [ms] (mean)
Time per request:       84.887 [ms] (mean, across all concurrent requests)
Transfer rate:          2274.87 [Kbytes/sec] received

Connection Times (ms)
	      min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:    81   85   2.9     84     127
Waiting:       78   82   2.7     81     124
Total:         81   85   2.9     84     127

Percentage of the requests served within a certain time (ms)
  50%     84
  66%     86
  75%     87
  80%     87
  90%     88
  95%     89
  98%     91
  99%     94
 100%    127 (longest request)


(I have run the tests several times to check that the results are reliable)

Conclusion


As you can see, it is quiet interesting as the global gain is about 14,5%. I have tested on several smaller templates but the gain was insignificant and less than 1%. (which seems logical)

So the extension can really be helpful on complex templates with a lot of parameters, the more complex the Twig templates are the more gain you will have. (up to 15%)

See you. COil :)


About the extension:


For other Symfony2 performance tricks check out the following resources:


Monday 6 September 2010

sfTaskLoggerPlugin updated for symfony 1.4

Wow, long time I didn't post, but that don't mean I am no more addicted with symfony. :p All my plugins were updated for symfony1.4. sfTaskLoggerPlugin was the last to be, in fact it was ok in svn but there wasn't the related pear package. Hope you'll give a try because the plugin is quiet unpopular (only 5 subscribers for now) but for sure it is the most useful of all my plugins. It is already used in production for a startup, a big company and for several other projects.

I must mention that there is a very nice review of the plugin on the blog of Tomasz Ducin. (many thanks ! ;) ) where you'll have an interesting feedback on why and how to use the plugin.

I tried to made a clean and quiet exhaustive documentation so you can see if the plugin feeds your needs or not, it's in the README tab.

Here is the change-log since the last PEAR release. (And don't forget the +1 please if you find it somewhat useful ^^):

  • Updated sample and purge tasks
  • Moved "env" and "application" options at the base task level
  • Updated package and README
  • Temporary logs stored into the log application of the project
  • Packages for symfony 1.1, 1.3 and 1.4
  • Plugin has now a YAML to configure if one must save the main output in a file, the database or both
  • Added new field to store the id of the last fully processed record
  • New option that allows to log only if there were thing processed by the task
  • New option to check if the task was already run once in a day
  • New option to check if the task is already running
  • New task to purge failed tasks still flagged as "is_running"
  • Re-factored a bit the code
  • Changed the plugin task namespace to "task-logger" instead of "sf_task_logger"
  • Modified the logSection function
  • Added the logSection method
  • Corrected the log functions
  • Fixed the log messages


See you. COil :)

Sunday 13 September 2009

New 1.2 symfony plugin + tutorial: sfTaskLoggerPlugin

Hi symfonians ! ^^

Again, that's quiet a long i didn't post something on symfony. Well i suppose releasing a new is a good occasion for this. Let me introduce the sfTaskLoggerPlugin plugin:

The sfTaskLoggerPlugin plugin allows you to run tasks and store the results. Results are stored in the database in a specific table and also in a log file. Each task has its own log file, witch is stored in a specific directory depending on its namespace and name. (`/log/tasks/:TASK_NAMESPACE/:TASK_NAME`).

The database record stores the following informations:

  • Options of the task
  • Arguments of the task
  • An error code
  • Start and end time
  • A success flag
  • The log file path
  • Extra comments (for admin)

It's very useful, I've already used on several project i worked on (from 1.0 to 1.2). You to have a clean and "easy to access" historic (through an admin gen module for example) of all run tasks and their results. How to use it ? Well Very easy !!

Note: The plugin is Doctrine and Propel friendly, it you are using Doctrine, the /lib/config/doctrine/schema.yml will be used whereas using Propel the /lib/config/schema.yml will be used.

Installation

  • Install the plugin
       $ symfony plugin:install sfTaskLoggerPlugin


(or download it and unzip in your /plugins directory)

  • Clear you cache
       $ symfony cc


Configuration


The plugin comes with a base task class witch is named sfBaseTaskLoggerTask Therefore your tasks must extend this one. Because there is no autoloading at the task level, one must include the base class manually:

   require_once(dirname(FILE). '/sfBaseTaskLoggerTask.class.php');

Note: Of course you will have to change this path depending on where is located your task. For example if it is located in the `/lib/task` folder of your project, the include directive should look like this:

   require_once(dirname(FILE). '/../../plugins/sfTaskLoggerPlugin/lib/task/sfBaseTaskLoggerTask.class.php');


Usage


1 - Create a new class that extends the plugin base class:


<?php
class sfTaskLoggerSampleTask extends sfBaseTaskLoggerTask
?>


2 - Implement the configure() method as you would do with a standard task:


<?php
/**
 * Main task configuration.
 */
protected function configure()
{
  $this->addArguments(array(
    new sfCommandArgument('arg_1', sfCommandArgument::OPTIONAL, 'Test argument 1', 'arg_1_value'),
    new sfCommandArgument('arg_2', sfCommandArgument::OPTIONAL, 'Test argument 2', 'arg_2_value'),
  ));

  $this->addOptions(array(
    new sfCommandOption('env', null, sfCommandOption::PARAMETER_REQUIRED, 'Environment used', 'prod'),
    new sfCommandOption('application', null, sfCommandOption::PARAMETER_REQUIRED, 'Application used', 'frontend'),
  ));

  $this->namespace = 'sf_task_logger';
  $this->name      = 'sample';

  $this->briefDescription = 'This is a sample task !';

  $this->detailedDescription = <<<EOF
The task [sf_task_logger:sample|INFO] doesn't do that much.
It logs itself in the database and in the file system:

  [./symfony sf_task_logger:sample --env=prod|INFO]
EOF;
}
?>


Now there are 2 specific methods to implement:

3 - checkParameters()


<?php

        /**
         * Advanced check of task parameters.
         */
        protected function checkParameters($arguments = array(), $options = array())
        {
          /* // Stupid example test
          if ($this->args['arg_1'] != 'arg_1_value')
          {
            throw new InvalidArgumentException('The value for argument 1 is not valid ! Check the help of the task.');
          }
          */
    
          return true;
        }
?>


Note: This method can be usefull if you have advanced controls to do on task parameters or arguments. Just return `true` if you don't have to use it.

4 - doProcess()


<?php
        /**
         * Main task process.
         */
        protected function doProcess()
        {
          try
          {
            $this->printAndLog(' - This is a log info !!');
            $this->task->setErrorCode(self::ERROR_CODE_SUCCESS);
            $this->setOk();
          }
          catch (Exception $e)
          {
            $this->task->setErrorCode(self::ERROR_CODE_FAILURE);
            $this->setNOk($e);
          }
        }
?>


Note: This is the main method of your task process. `$this->task` is the database object that will be saved. As you can see the `setOk()` and `setNOk` methods allow to set the flag of the record automatically depending on the success or failure of the task.

If you want more control on the task process you can also re-implement the `execute()` method of the base class witch is responsible for calling all others sub functions:

<?php
    /**
     * Global process of the task.
     *
     * @see sfTask
     */
    protected function execute($arguments = array(), $options = array())
    {
      $this->setParameters($arguments, $options);
    
      $this->checkParameters($arguments, $options);
    
      $this->initDatabaseManager();
    
      $this->initLogger();
    
      $this->logStart();
    
      $this->doProcess();
    
      $this->logEnd();
    }
?>


Notes:

The plugin is bundled with a sample task: `/lib/task/sfTaskLoggerSampleTask.class` witch can be run with the following command:

   ./symfony sf_task_logger:sample


TODO

  • Include Propel and Doctrine admin generator module

Support


Please report bugs or feature request on this post.

Changelog


See you. COil ^^

PS: I have published this tutorial quiet quickly, please help me by reporting typos and errors.
PS2: The official README file is far more readable
PS3: As always, any contribution will be welcome !

Tuesday 9 September 2008

New symfony 1.1 / 1.2 plugin + tutorial : sfDB4toPropelPlugin

1 - sfDB4toPropelPlugin presentation


I've just released a new plugin, it is called sfDB4toPropelPlugin, what is this ? Can it make coffee ? Not yet. ;) Well this one add to symfony a new task: propel:db4-to-propel that allows you to convert a DB4 schema (A DBDesigner 4 schema) into a valid propel schema.yml file. It can handle:

  • I18n tables
  • Foreign keys
  • phpNames of tables
  • Name of propel connection
  • Comments for all fields
  • Name of target schema
  • Lib package name
  • And several other options...


You can read a complete tutorial for this plugin in the full version of this post.
Of course, i'll be glad to have some feedback here, to know what you like / dislike and what could be improved.

See you. COil ;)



Related posts:


PS: Reading the related posts, it seems that i did not use the "last version", so i'll check what can be included in the next version of the plugin.

...

Continue reading...

Friday 2 May 2008

PHP_Debug V2.1.3 released

This is just a small update to correct and close minor bugs that were on the Pear bug tracker. I have also finally added the sources on the php csv server. The last step will be to do the end user documentation in the DocBook format so it can be available in the official pear documentation.

:)

Tuesday 1 January 2008

PHP_Debug 2.1.2 is out !

[En] First of all, happy new yeaaaarrrrr !!!!!!!!! ;)

Just a little update of PHP_Debug, here is the changelog:

  • Added credits to symfony for the idea of the floating div renderer
  • Added a link for a direct input W3C validation
  • Added warning for local W3C validation
  • Corrected html validation in the W3C tab (dooh!)
  • Changed main version number for the pear one
  • Switched package to stable state
  • Fixed typo in the database debug tab
  • [12078] Moved examples to doc role
  • [10919] Created a setStartTime method for the php_debugline class


Enjoy ! See you. COil :)

PS: Be carefull, the main version number is now the pear one. The pear version of this version is 1.0.0 stable whereas the SourceForge version is 2.1.2

PS: You can also check the project homepage

PHP_Debug 2.1.2

Tuesday 25 December 2007

Un éléphant ça bug énormément

[FR] A défaut d'avoir le courage d'écrire des articles intéressants à propos de Symfony ou de mettre à jour mes plugins; voici quelques photos de mon nouvel "ami de bureau", très sociable, pas si encombrant que ça malgré la réputation qu'il traîne. :) Le voilà donc dans diverses poses. Vous pouvez le commander sur le site de Nexen entre autres.

J'ai mon éléphant PHP
J'ai mon éléphant PHP
J'ai mon éléphant PHP
J'ai mon éléphant PHP



PS: Ah au fait, joyeux Noël à tous ;)

Sunday 20 May 2007

PHP_Debug is pearified !

[En] PHP_Debug is now part of the PEAR repository, it was accepted with a nice +14 vote total. (including 1 conditional). The last update was a new renderer witch was taken from symfony. (who said i was totally obsessed by sf ?) I'am quite proud of it because event it's a little library (40k), what i wanted to do here (since now more than 3 years !), it a "small perfect library", what i mean is:


Let's say it was an exercice for me, but i am happy that is can be useful to some of you. Of course you will not need it if you are already using symfony as it already has a great debugging system. ;) The lib is now near the 10k downloads, i hope i will continue. :) I still have to do the end user documentation on Pear on to upload the code on cvs (still waiting for my cvs account...) If you are willing to help, you are welcome. :)


[Fr] PHP_Debug fait maintenant partie du projet PEAR, "elle" a été acceptée avec un total de votes de +14. (dont 1 vote conditionel). La dernière mise à jour était une nouvelle classe de rendu directement inspirée de symfony. (Qui a dit que j'étais totallement obsédé par sf ???) Je suis assez fier car même si c'est une petite libraire (40k), ce que je voulais faire (maintenant depuis plus de 3 ans !), est "un petit-projet-parfait" (...) , ce que j'entends pas là:


C'etait un bon exercice pour moi, mais je suis content que cette classe soit utile à un certain nombre d'entre vous. Bien sûr vous n'en aurez pas besoin si vous utilisez symfony qui a déjà un système de debuggage intégré. ;) La librairie arrive bientôt à 10.000 téléchargements, j'espère que ça va continuer. Il faut toujours que je mette à jour la documentation utilisateur sur Pear ainsi que de mettre à jour le code sur cvs (toujours en attente de mon compte) Si vous voulez contribuer vous êtes le bienvenue... :)

Thursday 5 April 2007

New version of PHP_Debug V2.1.0 !

[EN] After quiet a long time of inactivity, here is a new release of my debug library for PHP, witch is obviously called PHP_Debug... :) The 1st version was released a long time ago in the late 2003, but every year i do an update. And this year, Symfony gave me an idea for a new renderer for my lib... In fact, i have taken the idea of the "debug floating div" to display the debug informations, well the display is almost the same than the Sf one, except for the logo... And there is still the old table renderer but is should not be used now because the div one is far more pratical to use. Want to see ?? Well, as usual, the demo on my blog. ;) (i think my hoster hate me because of my 147 sub-domains ;) )

One other goal is to propose this package to Pear, you can find my proposal here, the actual package you can download on SourceForge is already a pear package. I've just switched it status to "Proposed" and i'm waiting for feedback. There is also the offical website but i must find the time to update it and also to generate the nice phpdoc.

But what is exactly PHP_Debug ?

The basic purpose of PHP_Debug is to provide assistance in debugging PHP code, by "debug" i don't mean "step by step debug" but program trace, variables display, process time, included files, queries executed, watch variables... These informations are gathered through the script execution and therefore are displayed at the end of the script (in a nice floating div or a html table) so that it can be read and used at any moment. (especially usefull during the development phase of a project or in production with a secure key/ip)



PHP_Debug, features list:

  • General process time SQL/PHP
  • Check performance of parts of code
  • Show sql of executed queries (with highlighting and execution time)
  • Dump of all types of variable in a graphical way
  • Functionnal/trace debug (with line, file, class, function)
  • Show globals vars ($GLOBALS, $_POST, $_GET, $_COOKIE ...)
  • 2 renderers, as a HTML talbe or as a floating div
  • Allow to watch variables (+ watch on type of var)
  • Show php version & loaded extensions
  • Allow to show source code of all parsed file (with TEXT_Highlighter)
  • Static methods to debug/trace out of the debug renderer display
  • Debug infos are classified by type (14 types available)
  • Can replace the PHP error handler to show messages inside the debug renderer



Thanks to Francois (from symfony) who allowed me to take the idea of the floating div, to Stuart Colville for the js class selector code.