sync
[Pman.Admin] / Tools / LoadTest.php
1 <?php
2
3
4 require_once 'Pman/Core/Cli.php';
5 class Pman_Admin_Tools_LoadTest extends Pman_Core_Cli
6 {
7     
8     static $cli_desc = "Load testing for a domain";
9     
10     static $cli_opts = array(
11         
12         'per_second' => array(
13             'desc' => 'Request per second (default 1)',
14             'default' => '2',
15             'short' => 'P',
16             'max' => 1
17            
18         ),
19         
20         'timeout' => array(
21             'desc' => 'Timeout in seconds',
22              'default' => '5',
23             'short' => 'T' ,
24             'max' => 1
25         ),
26         'total' => array(
27             'desc' => 'Total tests (20)',
28              'default' => '20',
29             'short' => 't' ,
30             'max' => 1
31         ),
32         
33     );
34     // try and do some load testing..
35     var $total = 20; // total number of tests to run.
36     var $timeout = 5; // for each request.
37     var $per_second = 2; // how many per second.
38     var $host = 'www-new.regulationasia.com';
39     var $url = 'https://sg2-web.regulationasia.com/';
40     
41     var $cmd = ""; // filled in by initCmd
42     
43     var $started = 0;
44     var $done = array();
45     var $pool = array();
46     function get($r,$opts=array())    
47     {
48
49        // print_R($opts);exit;
50         foreach($opts as $k=>$v) {
51             $this->{$k} = $v;
52         }
53         $this->initCmd();
54
55         echo "Run:
56         
57 Request Per Second: {$this->per_second}
58 No. Requests : {$this->total}
59 Timeout: {$this->timeout}
60 URL: {$this->url}
61 Host: {$this->host}
62 CMD: {$this->cmd}
63
64 ";  
65         
66         
67         while (true) {
68              
69             
70             $ps = $this->poolsize();
71              
72             if ($this->started >= $this->total) {
73                 if ($ps == 0) {
74                     break;
75                 }
76                 usleep((1.0/$this->per_second) * 1000000);
77                 continue;
78             }
79             // run it..
80             $this->run();
81             $this->started++;
82             //echo "Sleep: " . ((1.0/$this->per_second) * 1000000) . "\n";
83             usleep((1.0/$this->per_second) * 1000000);
84             
85         }
86         $this->displayResults();
87         //print_R($this->done);
88         exit;
89     }
90     var $log = array();
91     var $keynames = array();
92     function initCmd()
93     {
94         require_once 'System.php';
95         $curl = System::which('curl');
96         $this->cmd = implode(" ", array(
97                 $curl,
98                 "--max-time " , $this->timeout , 
99                 "-s -o /dev/null -k ",
100                 "-H \"Host: {$this->host}\"",
101                 "\"{$this->url}\"",
102                 "-w \"%{http_code},%{size_download},%{time_connect},%{time_starttransfer},%{time_total}\n\""
103         ));
104         
105         $sn =  $_SERVER["SCRIPT_NAME"];
106         
107         $this->cwd = $sn[0] == '/' ? dirname($sn) : dirname(realpath(getcwd() . '/'. $sn));
108         
109         $this->keynames =array(
110             'success',
111             'size',
112             'connect',
113             'building',
114             'sent'
115         );
116         foreach($this->keynames as $k=>$v) {
117             $this->log[$v] = array();
118         }
119         
120         
121     }
122     
123     function run()
124     {
125        
126          
127          
128         $tn =  $this->tempName('stdout', true);
129         $descriptorspec = array(
130             0 => array("pipe", 'r'),  // stdin is a pipe that the child will read from
131             1 => array("file", $tn, 'w'),  // stdout is a pipe that the child will write to
132             2 => array("pipe", "w") // stderr is a file to write to
133         );
134         
135          
136         //$cmd = 'exec ' . $php . ' ' . $app . ' ' . $cmdOpts; //. ' &';
137         
138        
139         $pipe = array();
140          
141         //echo date("H:i:s"). ":Start: {$this->started} : {$this->cmd}\n";
142         
143         $p = proc_open($this->cmd, $descriptorspec, $pipes,  $this->cwd  );
144         $info =  proc_get_status($p);
145         
146          
147         $this->pool[] = array(
148                 'proc' => $p,
149                 'pid' => $info['pid'],
150                 'out' => $tn,
151                 'id' => $this->started,
152                 //'cmd' => $cmd,
153                 'pipes' => $pipes,
154                 'started' => time()
155         );
156     }   
157        
158     
159     
160     function poolsize()
161     {
162         $pool = array();
163         clearstatcache();
164          
165         foreach($this->pool as $p) {
166              
167          
168             $info =  proc_get_status($p['proc']);
169             
170             // update if necessday.
171             if ($info['pid'] && $p['pid'] != $info['pid']) {
172                 $p['pid'] = $info['pid'];
173             }
174             
175             
176             if ($info['running']) {
177             
178                 $pool[] = $p;
179                 continue;
180             }
181             // closed...
182             
183             
184             fclose($p['pipes'][0]);
185             fclose($p['pipes'][2]);
186             proc_close($p['proc']);
187             $res = trim(file_get_contents($p['out']));
188             
189             $p['data'] = explode(",", $res);
190             $this->done[] = $p;
191             foreach($p['data'] as $i=>$v) {
192                 $this->log[$this->keynames[$i]][]  = $v;
193             }
194             $suc = $p['data'][0] == 200 ? 'Done' : 'Fail';
195             
196             echo date("H:i:s"). ":{$suc}: ". (1+$p['id']). "/{$this->total}: ";
197             $this->displayResults();
198             
199             
200             @unlink($p['out']);
201             
202         }
203         $this->pool = $pool;
204         return count($pool);
205         
206     }
207     
208     function displayResults()
209     {
210         $log = $this->log;
211         // we could slice log values to get recent.. // to show current trend.
212         
213         
214         $done = count($this->done);
215         echo
216             "Success Rate: ". number_format(100*(count(array_filter($log['success'], function($s) { return $s == 200; })) / $done), 0) . '%'.
217             "   Largest: " . number_format(max($log['size']),0) .'b'.  // these ignore failures.
218             "   Smallest: " . number_format(min($log['size']),0) .'b'.
219             "   Av.Connect: ".  number_format(array_sum($log['connect'])/$done, 2) .'s'.
220             "   Average Before Output Time: ", number_format(array_sum($log['building'])/$done, 2) .'s'.
221             "   Average Load Time: " .number_format(array_sum($log['sent'])/$done, 2) .'s' .
222             "   Load: {$this->per_second} req/s" .
223             "\n";
224             
225             
226             
227              
228         
229         
230         
231     }
232
233 }