Friday, March 21, 2008

PHP load testing script to run with cron

We've been interested in seeing what the response time is for some pages of ours on a server. So to test this I came up with the following script which uses curl to open the url, save the contents of the page called to file, close it and while it does this, time the start and end then report on the findings in a database. Here's some sample code:


$hostname_cg = "localhost";
$database_cg = "dbname";
$username_cg = "dbuser";
$password_cg = "dbpass";
$cg = mysql_connect($hostname_cg, $username_cg, $password_cg) or trigger_error(mysql_error(),E_USER_ERROR);

if (!function_exists("GetSQLValueString")) {
function GetSQLValueString($theValue, $theType, $theDefinedValue = "", $theNotDefinedValue = "")
{
$theValue = get_magic_quotes_gpc() ? stripslashes($theValue) : $theValue;

$theValue = function_exists("mysql_real_escape_string") ? mysql_real_escape_string($theValue) : mysql_escape_string($theValue);

switch ($theType) {
case "text":
$theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL";
break;
case "long":
case "int":
$theValue = ($theValue != "") ? intval($theValue) : "NULL";
break;
case "double":
$theValue = ($theValue != "") ? "'" . doubleval($theValue) . "'" : "NULL";
break;
case "date":
$theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL";
break;
case "defined":
$theValue = ($theValue != "") ? $theDefinedValue : $theNotDefinedValue;
break;
}
return $theValue;
}
}


function microtime_float()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
function InsertDB($startTime, $endTime, $totalTime, $Page){
global $database_cg, $cg;
$insertSQL = sprintf("INSERT INTO tblpagetest (StartTime, EndTime, TotalTime, Page) VALUES (%s, %s, %s, %s)",
GetSQLValueString($startTime, "text"),
GetSQLValueString($endTime, "text"),
GetSQLValueString($totalTime, "text"),
GetSQLValueString($Page, "text"));

mysql_select_db($database_cg, $cg);
$Result1 = mysql_query($insertSQL, $cg) or die(mysql_error());
}

////////////
// $page - address of page to download and test.
// $savefile - file to save to on local disk
// $pagename - descriptive name for database entry
// $numberoffiles - this will recursively download the amount of files defined and download them to disk.


function getPage($page, $savefile, $pagename, $numberoffiles){

$time_start = microtime_float();

$ch = curl_init($page);
$fp = fopen($savefile, "w");

curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);

curl_exec($ch);
curl_close($ch);
fclose($fp);

if($numberoffiles <> 0){ // If we have defined a number of files, create a sequential sequence of images which will fulfill the requested amount and download them one at a time.
for ($counter = 1; $counter <= $numberoffiles; $counter++)
{
$image = "http://www.mywebsite.com/stresstestimages/image".$counter.".gif";
$chimage = curl_init($image);
$fpimage = fopen("image".$counter.".gif", "w");

curl_setopt($chimage, CURLOPT_FILE, $fpimage);
curl_setopt($chimage, CURLOPT_HEADER, 0);

curl_exec($chimage);
curl_close($chimage);
fclose($fpimage);
//echo $image."copied";
}
}




$time_end = microtime_float();
$total_time = $time_end - $time_start;

InsertDB($time_start, $time_end, $total_time, $pagename);

print $pagename." returned in $total_time seconds
";

}

function getmypages(){

getPage("http://www.mywebsite.com", "website.txt", "website test", 78);

}
getmypages();

?>

Sample Database table schema:

CREATE TABLE `tblpagetest` (
`ID` int(11) NOT NULL auto_increment,
`StartTime` varchar(255) NOT NULL,
`EndTime` varchar(255) NOT NULL,
`TotalTime` varchar(255) NOT NULL,
`Page` varchar(255) NOT NULL,
`DateCreated` timestamp NOT NULL default CURRENT_TIMESTAMP,
PRIMARY KEY (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;


NOTE: Although this script takes into consideration the size of the page with all assets (use this site to find out how many files link off from the page, and the overall page size http://tools.pingdom.com/fpt/) it does not take into consideration multi-concurrent connections as a normal browser would. E.g. if your index page contains 90 items and totals 400k, you should call 90 images that are 4.4k in size to simulate the load on the server.

I'm pretty sure that there are other scripts out there that make this more efficient and if you know of them, please let me know where I can download and test from. Thanks.

No comments: