Unisys12's Blog

My adventures, trials & tribulations of learning web development as a hobby! I mean... who does that?


Phalcon PHP Performance Tests

Phillip Jackson - 2014-04-07 02:25:52
Very simple, low level performance results comparing Laravel 4.1 to Phalcon 1.3.1

Not going to get into the whole story about this, but I wrote this(this, being the blog that you are ready right now) really really simple CMS for myself to use as a blog. I started out using Phalcon, I think 1.2.7, and got about half of it wrote. Upon getting it to a preliminary working stage, I performed my first 'git push' and quickly ran into some issues with the host I am currently using. That would be a free tier over on Openshift. Not going to get into that, because it is not an issue with Phalcon, so... But anyway, since I was already pretty vested in building this CMS for myself, I fell back to my second favorite framework which is Laravel. At this point, I am through with most of the backend stuff. I can create posts, edit them, authenticate, ya-da ya-da! No big deal. But, this weekend, I decided that I would catch the Phalcon project up to where the Laravel project is and check the performance between the two.

Now, before I go any further. I am sad to say that my current dev enviroment is WAMP2.4 running PHP5.4.12, Apache2.2.4 and MySQL5.6.12. For performance monitoring, I am using Webgrind/Xdebug. So this weekend, I finally took the plunge into the land of Vagrant. Still "getting my beak wet" with it. I have a system running, but nothing that I am ready to start punching cards on. Once that is set-up like I want and I am comfortable configuring VH's I will go all in. I also have a New Relic account tied to it, maybe I can gather a little better info than what Webgrind can gather.

I will show the code from each framework before each screenshot, so we can see just how simple of a code example this is.

Laravel 4.1

HomeController

Base controller has nothing special, construct() binds the Post model to the controller. Using Eloquent in my Post model, run a query to return all posts and sort by the id column. Assign that query to the posts variable, return the view 'index', with the $posts var as posts.



class HomeController extends BaseController {

    public function __construct(Post $post)
    {
        $this->post = $post;
    }

    public function showIndex()
     {
        $posts = $this->post->all()->sortByDesc('id');

        return View::make('index')->with('posts', $posts);
   }

}

index.blade.php

Extends the master layout blade file, sets a page title, iterates over the $posts object and displays the section of each post. Within this foreach loop, I use an external library to parse the markdown stored in the database. I also use the php method 'substr' to limit the content displayed to 500 characters.



@extends('layouts.master')

@section('title')
Blog
@stop

@section('content')

<main class="posts">
    @foreach ($posts as $post)
    <header class="post_header">
        <h3 class="post_title"><a href= "{{ url('posts') }}/{{ $post->id }}">{{ $post->post_title }}</a></h3>
        <span class="post_details"><small>{{ $post->post_author }} - {{ $post->created_at }}</small></span>
        <h5 class="post_desc">{{ $post->post_desc }}</h5>
    </header>
    <article class="post_content">
         {{ Parsedown::instance()->parse(substr($post->post_content,0, 500)) }}
    </article>
    <section class="post_tags">
        <small> {{ $post->post_tags }} </small>
    </section>
    @endforeach
</main>

@stop

As you can see, this really simple textbook sorta stuff. Much could be said with me calling a class within a View, which I know... Seems really stupid. I really should refactor that and abstract it out to it's own class. I know. So, now for the screen shot from WebGrind.

Laravel_Webgrind

As you can see, running the above code shows that 961 different functions were called and it took 2050 ms. Yes, the page renders fairly slow and when running Google Page_Speed test actually shows this. The site still scores between 95-97 on average, but as come in as low as 87 before some changes were made to gzip and caching through NGINX. So now let's take a look at the code samples that returns the same view, but from Phalcon...

Phalcon 1.3.1

IndexController.php

class IndexController extends ControllerBase
{

    public function indexAction()
    {
        $this->view->posts = Posts::find(array("order" => "created_at DESC"));
    }

}

index.volt.php

{% extends "layouts/main.volt" %}

{% block title %}<title> Unisys12 - Blog Home </title>{% endblock %}

{% block content %}
<main class="posts">
    {% for post in posts %}
    <header class="post_header">
        <h3 class="post_title"><a href="{{ url('post/show/') }}{{ post.post_title}}">{{ post.post_title }}</a></h3>
        <span class="post_details"><small>{{ post.post_author }} - {{ post.created_at }}</small></span>
        <h5 class="post_desc">{{ post.post_desc }}</h5>
    </header>
    <article class="post_content">
        <?php echo ParseDown::instance()->parse(substr($post->post_content,0, 500)); ?>
    </article>
    {% endfor %}
</main>
{% endblock %}

Exactly the same thing as the Laravel controller and view. Nothing different other than how I am loading the Parsedown library. In Laravel, since it was brought in with Composer, it just worked out of the box. In Phalcon, not so much, so I added a entry into 'loader.php' for a classmap to the this single entity. Other than that, all the same.

Now for the screenshot with the results -

Phalcon_WebGrind

When I saw this, my mouth dropped. I mean to the floor. I did not expect that drastic of a difference between the two. I knew there was going to be a significant difference, but... DANG! To summarize, there was 57 functions run in 70ms. 70 freaking milliseconds! OMG!

With this information, I cannot wait to get my VM up and running properly so I can start running these through New Relic and really get some serious data. Wait, why am I not doing that right now. Ok, yeah... gotta go!

LARAVEL, PHALCON, PHP, PERFORMANCE
comments powered by Disqus