C/C++ FastCGI

Discussion in 'Install/Configuration' started by fryk, Jun 1, 2005.

  1. fryk

    fryk New Member

    Sure.

    simple-test-script.php
    Code:
    <html><head><title>CGI C Example #3</title></head>
    <body><h1>CGI C Example #3</h1>
    <table border=2>
    
    <?
    
    $db = mysql_pconnect("localhost","root","") or die('konnekt');
    mysql_select_db("ht3") or die('db');
    
    $r = mysql_query("SELECT * FROM pages");
    if ($r)	
    {
    	$nrows = mysql_num_rows($r);
    	$num_fields = mysql_num_fields($r);
    	
    	printf("rows: %i, cols: %i
    
    \n",$nrows,$num_fields);
    	printf("<table border=2>\n");
    
    	while ( $row = mysql_fetch_array($r) )
    	{
    		printf("<tr>");
    		for($j = 0; $j < $num_fields; $j++)
    		{
    			printf("<td>%s</td>", $row[$j] ? $row[$j] : NULL");
    		}
    		printf("</tr>");
    		printf("\n");
    	}
    
    	printf("</table></body></html>\n");
       mysql_free_result($r);
    
    }
    
    mysql_close($db);
    
    ?>
    
    </table></body></html>
    simple-test-script.c
    Code:
    #include	<stdio.h>
    #include	<mysql.h>
    #include "fcgi_config.h"
    #include <stdlib.h>
    #include "fcgi_stdio.h"
    
    int main ()
    {
    	int	err = 0;
    	MYSQL	dbase;
    
    	if (mysql_init(&dbase) == NULL) err = 1;
    	else
    	{		
    		if(mysql_real_connect(&dbase,"localhost","root","","ht3",0,NULL,0) == NULL) err = 1;
    	}
    	if(err)
    	{
    		printf("
    
    Error connecting to database</body></html>\n");
    		exit(0);
    	}
    
    
    	//
    	// B E G I N   R E Q U E S T
    	// 
    
    
        while (FCGI_Accept() >= 0)
        {
    		char		sqlbuff[255];
    		MYSQL_RES	*result;
    		
    		printf("Content-type: text/html\r\n\r\n");
    		printf("<html><head><title>CGI C Example #3</title></head>\n");
    		printf("<body><h1>CGI C Example #3: %i</h1>\n",getpid());
    	
    		sprintf(sqlbuff,"SELECT * FROM pages");
    		if(mysql_real_query(&dbase,sqlbuff,strlen(sqlbuff)))
    		{
    			printf("
    
    SQL error</body></html>\n");
    			exit(1);
    		}
    		
    		result = mysql_store_result(&dbase);
    		if(result)
    		{
    			int			i, j, num_fields, nrows;
    			MYSQL_ROW	row;;
    			
    			nrows = mysql_num_rows(result);
    			num_fields = mysql_num_fields(result);
    			
    			printf("rows: %i, cols: %i
    
    \n",nrows,num_fields);
    			printf("<table border=2>\n");
    
    			while ( row = mysql_fetch_row(result) )
    			{
    				printf("<tr>");
    				for(j = 0; j < num_fields; j++)
    				{
    					printf("<td>%s</td>", row[j] ? row[j] : "NULL");
    				}
    				printf("</tr>");
    				printf("\n");
    			}
    
    			printf("</table></body></html>\n");
    
    			mysql_free_result(result);
    			free(result);
    		}
    		else
    		{
    			printf("No entries</body></html>\n");
    		}
    
        } /* while */
        
        mysql_close(&dbase);
    
        return 0;
    }
    "SELECT * FROM pages" returns 4 rows / 5 short columns each.

    I got ubuntu:
    Code:
    root@fryk:/var/www # uname -a
    Linux fryk 2.6.10-5-386 #1 Tue Apr 5 12:12:40 UTC 2005 i686 GNU/Linux
    
    on p4 2.xghz 512ram

    Apache2 run just from apt-get install + mod_php + mod_fastcgi (-processes 10 - same as lsws).
    Lsws standard with c fastcgi as described in previous posts (php fastcgi is built in - as I get it).

    I typically measured it with
    Code:
    ab -n 20000 -c 50 PATH
  2. mistwang

    mistwang LiteSpeed Staff

    I think your test case is DB bounded.

    Even though, lsws should be slightly faster than Apache, you may want to try tuning the concurrent level of lsws fcgi. In your test, Apache made 50 concurrent queries to MySQL, but lsws fcgi only made 10, according to your configuration posted in previous post. Change the "instances" to match "max connections", try different value between 10-50.

    The C fastCGI could be optimized a little bit:
    To use prepared SQL statement if you are using MySQL 4.1.X
    To combime multiple printf to one, or buffer the result in a buffer with snprintf.
    To cache the result if it does not change very often.

    All in all, the faster you make the FCGI run, the bigger difference you will see between lsws and Apache.
  3. xing

    xing LiteSpeed Staff

    1) Add db_close to line right before exit(1). Just making sure the db connects are freed or are in clean state for the load test.

    2) This test result you would get for this is only realistic in a clean-room environment. Even if you have mysql query cache disabled, subsequent reqsults will be purely from myisam/innodb buffer and or linux buffer ram so after the first few requests, you are dealing with mysql through pure memory non disk i/o calls.

    I would suggest that the scripts are run with a companion program which modifies a record in the page table once every second. This forces mysql cache flush and gives you a more accurate data on how your performance is when injected with index/cache busting write queries.

    In addition, instead of pure select * from pages. You should use a more common compounded query such as select * from pages where pageid = value order by priority asc, etc.

    3) Don't how it applies to C but in javascript, it is magnitudes faster to buffer output like so..

    var buffer = new Array();
    buffer[buffer.length] = "<html>";
    buffer[buffer.length] = "</html>";

    document.write(buffer.join(''));

    A) one big write = faster
    B) Intead of appending growing data to a string, use an dynamic array and
    join the data at the end = faster

    the buffer.join appends all the elements into one string separated by the separator, empty char in this case.

    Not sure how to do this in C but the same concept shoudl apply to most languages.

Share This Page