Author Archives: Laas - Page 2

Ruby Rack servers benchmark

Facing the question which Ruby Rack server perform best behind Nginx front-end and failing to google out any exact comparison, I decided to do a quick test myself.

The servers:

Later I tried to test UWSGI server too as it now boasts built-in RACK module, but dropped it for two reasons: (1) it required tweaking OS to raise kern.ipc.somaxconn above 128 (which none other server needed) and later Nginx’s worker_connections above 1024 too and (2) it still lagged far behind at ~ 130 req/s, so after successful concurrency of 1000 requests, I got tired of waiting for the tests to complete and gave up seeking it’s break point. Still, UWSGI is very interesting project that I will keep my eye on, mostly because of it’s Emperor and Zerg modes and ease of deployment for dynamic mass-hosting Rack apps.

As UWSGI was originally developed for Python, I wasted a bit of time trying to get it working with some simple Python framework for comparison, but probably lack of knowledge on my part was the failure of it.

Testing

The test platform consisted of:

To set up a basic testcase, I wrote a simple Rack app that responds every request with the request IP address. I dediced to output IP because this involves some Ruby code in the app, but should be rather simple still.

ip = lambda do |env|
  [200, {"Content-Type" => "text/plain"}, [env["REMOTE_ADDR"]]]
end
run ip

Tweaking the concurrency number N (see below) with resolution of 100, I found out the break point of each of the servers (when they started giving errors) and recorded the previous throughput (the one that didn’t give any errors).

Results

The results are as follows:

  1. Unicorn – 2451 req/s @ 1500 concurrent request
  2. Thin – 2102 req/s @ 900 concurrent requests
  3. Passenger – 1549 req/s @ 400 concurrent requests

The following are screenshots from JMeter results:

Unicorn @1500 concurrent request

Thin @900 concurrent requests

Passenger @400 concurrent requests

None of these throughputs are bad, but still Unicorn and Thin beat the crap out of Passenger.

Details

The JMeter testcase

  1. ramp up to N requests concurrently
  2. send request to the server
  3. assert that response contains IP address
  4. loop all of this 10 times

Nginx configuration:

    # Passenger
    server {
      listen 8080;
      server_name localhost;
      root /Users/laas/proged/rack_test/public;
      passenger_enabled on;
      rack_env production;
      passenger_min_instances 4;
    }
 
    # Unicorn
    upstream unicorn_server {
      server unix:/Users/laas/proged/rack_test/tmp/unicorn.sock fail_timeout=0;
    }
 
    server {
      listen 8081;
      server_name localhost;
      root /Users/laas/proged/rack_test/public;
 
      location / {
        proxy_pass http://unicorn_server;
      }
    }
 
    # Thin
    upstream thin_server{
      server unix:/Users/laas/proged/rack_test/tmp/thin.0.sock fail_timeout=0;
      server unix:/Users/laas/proged/rack_test/tmp/thin.1.sock fail_timeout=0;
      server unix:/Users/laas/proged/rack_test/tmp/thin.2.sock fail_timeout=0;
      server unix:/Users/laas/proged/rack_test/tmp/thin.3.sock fail_timeout=0;
    }
 
    server {
      listen 8082;
      server_name localhost;
      root /Users/laas/proged/rack_test/public;
 
      location / {
        proxy_pass http://thin_server;
      }
    }

As is only logical, having processes match the number of cores (dual HT = 4 cores) gave best results for both Thin and Unicorn (thouch the variations were small).

Unicorn configuration

Passenger requires no additional configuration and Thin was configured from command line to use 4 servers and Unix sockets, but Unicorn required a separate file (I modified Unicorn example config for my purpose):

worker_processes 4
working_directory "/Users/laas/proged/rack_test/"
listen '/Users/laas/proged/rack_test/tmp/unicorn.sock', :backlog => 512
timeout 120
pid "/Users/laas/proged/rack_test/tmp/pids/unicorn.pid"
 
preload_app true
  if GC.respond_to?(:copy_on_write_friendly=)
  GC.copy_on_write_friendly = true
end

Disclaimer

I admit that this is extremely basic test and with better configuration much can be squeezed out from all of these servers, but this simple test surved my purpose and hopefully is of help to others too.

git terminal graph with branch names

I have searched several times how to produce graph tree in terminal similar to Gitk or other GUI visualizers. Compiling the knowledge in this StackOverflow question together, I came up with the following command:

git log --graph --full-history --all --color --date=short --pretty=format:\"%x1b[31m%h%x09%x1b[0m%x20%ad%x1b[32m%d%x1b[0m %s %x1b[30m(%an)%x1b[0m\"

UPDATE: I added annotation to the end of line in dark-grey (not shown in the image) so that you can blame people quicker.

This produces graph shown on the image.

GIT graph in terminal

GIT graph in terminal with branch names

If you noticed, I have aliased all of this for a much shorter command git tree, which can be done with the following git config line:

git config --global alias.tree 'log --graph --full-history --all --color --date=short --pretty=format:\"%x1b[31m%h%x09%x1b[0m%x20%ad%x1b[32m%d%x1b[0m %s %x1b[30m(%an)%x1b[0m\"'

Notice the two sets of quatation marks.

Brolog is now CommitBlog

Today I woke up with a new name for my blog. It is now known as CommitBlog.

Simple as that.

The why

When starting something new, there is always the problem with the name. The worst part is that, most of the time, you need to come up with a name just in the middle of creation and when you least know, whether the beast will walk, swim or fly. And the name sticks. And sometimes the name stinks too. After some initial moments, I never really liked the name Brolog (being not-so-clever wordplay on Prolog and Blog). Given that I have never actually seen Prolog in action and know nothing of the language it seemed a bit false. So today I woke up and had a new name, that relates more to what I do daily – commit to GIT. Or write to commitlog if you will.

So. There you have it. CommitBlog.

Inkscape CSV merge

I just uploaded inkscape_merge gem v0.1.0.

This is a script to merge SVG files with CSV data-files using Inkscape, to produce one outputfile (e.g. PDF) per data-row.

Script inspired by and based on Aurélio A. Heckert excellent InkscapeGenerator (wiki.colivre.net/Aurium/InkscapeGenerator)

Heckert’s original script unfortunately broke for me several times and I took the opportunity to rewrite it and make it more extendable for future.

 

USAGE

Install the gem

gem install inkscape_merge

Create files

Create CSV data file with first row as a header. The values from this row are used as keys in the SVG file substitution.

Create SVG file that contains some variables in the form:

%VAR_name%

Where `name` is the name of a column in the CSV file created previously. These variables can be anywhere inside the SVG, from plain text nodes to color values. This script just brute-forcedly `gsubs` these values as text w/o any thought.

Run the script

The script requires at least three arguments:

  • the input SVG file
  • the input CSV file
  • and the output file `pattern`

Note: output pattern undergoes the same substitutions as the SVG file, so to create easily unique file names. Additionally the output pattern can contain `%d` which is replaced with current row number.

Example:

inkscape_merge -f postcard.svg -d names.csv -o postcards/card_%d.pdf

This produces files like:

  • postcards/
    • card_1.pdf
    • card_2.pdf

MacFuse and Mac OS X Lion

UPDATE: Now that OSXFUSE is released, use this as the recommended (drop-in) replacement for MacFuse.

Rest is only for historical information.

Now that I have upgraded to Mac OS X Lion, I found that MacFusion does not work. Before diving into a workaround as back in Snow Leopard days I remembered that then it was because of MacFuse and even that time there turned out to be a build floating around the web that would have worked. As is the case now.

This forum listed one of them that got it working for me - macfuse-core-10.5-2.1.9.dmg.

Though, pardsbane here tells of another project – OSXFUSE – one the way that will support Lion out of the box (when the box is released).

PHP site root

How to get the root of your site, regardless of the folder depth of your script while taking into account any Aliases your webserver might have?

Say, for example, that you have in your apache conf the following lines:

  DocumentRoot /var/www/htdocs
  Alias /phpsite /var/www/mysite

That means that your PHP site resides in /var/www/mysite, while rest of your web resides in /var/www/htdocs. How will your PHP scripts know that /phpsite portion, without hardcoding this into scripts, when they do not know how many levels deep in directory structure they themselves are in your site (e.g /phpsite/posts/update.php).

First, if you already don’t have, create a script (call it what ever you like, e.g. config.php) somewhere in your site folder. Preferred is at the top level, but subfolders work too (more on this later).

Secondly, put the following inside that file:

$wwwroot = "http://" . $_SERVER['SERVER_NAME'] .
      str_replace(
        str_replace(
          dirname(__FILE__),
          "",
          $_SERVER['SCRIPT_FILENAME']),
        "",
        $_SERVER['SCRIPT_NAME']);

If you placed your config.php in some subfolder, then you have to multiply the dirname() calls for every subfolder level. E.g if your config.php is in conf/config.php, i.e second level, you need 2 dirname() calls and your 4th line should look like:

dirname(dirname(__FILE__))

Third, include this file in every script, even in subfolders and prepend to links:

require_once "../config.php";
echo "<a href="$wwwroot/some/script.php">Some script</a>";

Voila!

Under the hood

What this script does is actually rather simple string algebra. The contents of those special variable is as follows:

$_SERVER['SERVER_NAME']
    # => example.com
__FILE__
    # => /var/www/mysite/config.php - the name of the script where this is written
$_SERVER['SCRIPT_FILENAME']
    # => /var/www/mysite/dir/script.php - the full path to script that included config.php
$_SERVER['SCRIPT_NAME']
    # => /phpsite/dir/script.php - the URL path of the script that included config.php

You might already start to grasp what we’re about to do. Leaving aside the obvious hostname part, what the str_replace part does is the following:

  1. calculate filesystem path to the base of the site: dirname(__FILE__): /var/www/mysite/config.php => /var/www/mysite
  2. substract this path from the SCRIPT_FILENAME => /var/www/mysite/dir/script.php => /dir/script.php
  3. substract the result from the URL SCRIPT_NAME => /phpsite/dir/script.php => /phpsite

This method works even if you change the Alias or remove it altogether.

Generic vim counters

I needed a way in vim config to use counters and what better way, but to write a function to simultaneously handle all variables and optinally increase or decrease them:

" define and manage counters
" NB! all counters are namespaced globally (g:)
function! Counter(name,...)
" check if this variable already exists or should we initialise it
  if !exists("g:" . a:name)
    exec 'let g:'  . a:name .' = 0'
  endif
" if second parameter is given, increase/decrease value
  if a:0 > 0
    exec 'let g:'. a:name .' = g:' . a:name . ' + ' . a:1
  endif
  exec 'return g:' . a:name
endfunction

Usage of the function is as follows:

" Get the current value
echo Counter('mycount')
 
" Increase value by 1(and return the new value)
echo Counter('mycount', 1)
 
" Decrease value by 2
echo Counter('mycount', -2)

BetterTouchTool and Safari


Few days ago I switched to BetterTouchTool from MagicPrefs because (1) MP somehow blocked clicks when MagicMouse was disconnected and I always had to quit the MP. And (2) BTT lets me configure the trackpad too.

BetterTouchTool lets you define tons of gestures for your Macbooks Trackpad, your MagicMouse and your MagicTrackpad. In addition to that it brings lots of new stuff to MacOS like Windows 7 like window snapping, window switchers etc……

Extensive explanation is at the BTT developer’s blog.

I wanted to add a gesture (four-finger click) to bring up a new Safari window. BTT had Predefined actions to Open Application/File/Script… or Open URL. First of these unfortunately did not open new window, but instead activated one of the pre-existent windows (which I could do just by clicking the Safari Dock icon). The latter did bring up a new window, but I missed the chance to use Top Sites.

AppleScript to the rescue

So I typed four lines in AppleScript and now have an action to pop up new Safari window:

tell application "Safari"
	activate
	make new document
end tell

I saved this as an Application to the /Applications folder just for faster startup and pointed BTT Open Application action to that file. Viola!

Download the Safari New Window action.

MTS to MP4 converter

Following my previous post about iMovie and MTS I always had random trouble with my converter failing/hanging with some  MTS files. And when repeated for the same file – no problems. This way I couldn’t just set the converter to work with tens of files and go for a coffee – I always had to look for hangs and stop the process only to restart it again.

And after I had problems with QuickTime refusing to open the new .mov files and iMovie having no sound, I thought it to be prime time to revisit the script.
Read more »

Mac OS X 10.6.5 upgrade freed 2 GB

When Snow Leopard first game out, it was promised to cut back on the OS footprint (in Gigs).

Now, upgrading to 10.6.5, I somehow had insight to take screenshot of disk usage right before upgrading and comparing to the after shot:

Before:

Mac OS X 10.6.4

After:

Mac OS X 10.6.5

As you can see – it freed over 2 GB of disk space. Now this is what I call a good upgrade. Not only adding features and fixing bugs, but at the same time cutting back in bloat.

Note: my Time Machine reported 7.03 GB worth of changed data that needs to be backed up. So get some, loose some. But as my backup drive has lots of space while MacBook has little, I consider myself a winner.