cd5d004fd3149091e57fcaf7f25be173e34057c1
[plcapi.git] / extras / benchmark.php
1 <?php
2 /**
3  * Benchmarking suite for the PHP-XMLRPC lib.
4  *
5  * @author Gaetano Giunta
6  * @copyright (c) 2005-2020 G. Giunta
7  * @license code licensed under the BSD License: see file license.txt
8  *
9  * @todo add a check for response ok in call testing
10  * @todo add support for --help option to give users the list of supported parameters
11  * @todo make number of test iterations flexible
12  * @todo add https tests
13  **/
14
15 use PhpXmlRpc\PhpXmlRpc;
16 use PhpXmlRpc\Value;
17 use PhpXmlRpc\Request;
18 use PhpXmlRpc\Client;
19 use PhpXmlRpc\Response;
20 use PhpXmlRpc\Encoder;
21
22 include_once __DIR__ . '/../vendor/autoload.php';
23
24 include __DIR__ . '/../tests/parse_args.php';
25 $args = argParser::getArgs();
26
27 function begin_test($test_name, $test_case)
28 {
29     global $test_results;
30     if (!isset($test_results[$test_name])) {
31         $test_results[$test_name] = array();
32     }
33     $test_results[$test_name][$test_case] = array();
34     $test_results[$test_name][$test_case]['time'] = microtime(true);
35 }
36
37 function end_test($test_name, $test_case, $test_result)
38 {
39     global $test_results;
40     $end = microtime(true);
41     if (!isset($test_results[$test_name][$test_case])) {
42         trigger_error('ending test that was not started');
43     }
44     $test_results[$test_name][$test_case]['time'] = $end - $test_results[$test_name][$test_case]['time'];
45     $test_results[$test_name][$test_case]['result'] = $test_result;
46     echo '.';
47     flush();
48     @ob_flush();
49 }
50
51 // Set up PHP structures to be used in many tests
52
53 $data1 = array(1, 1.0, 'hello world', true, '20051021T23:43:00', -1, 11.0, '~!@#$%^&*()_+|', false, '20051021T23:43:00');
54 $data2 = array('zero' => $data1, 'one' => $data1, 'two' => $data1, 'three' => $data1, 'four' => $data1, 'five' => $data1, 'six' => $data1, 'seven' => $data1, 'eight' => $data1, 'nine' => $data1);
55 $data = array($data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2, $data2);
56 $keys = array('zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine');
57
58 // Begin execution
59
60 $test_results = array();
61 $is_web = isset($_SERVER['REQUEST_METHOD']);
62 $xd = extension_loaded('xdebug') && ini_get('xdebug.profiler_enable');
63 if ($xd) {
64     $num_tests = 1;
65 } else {
66     $num_tests = 10;
67 }
68
69 $title = 'XML-RPC Benchmark Tests';
70
71 if ($is_web) {
72     echo "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\">\n<head>\n<title>$title</title>\n</head>\n<body>\n<h1>$title</h1>\n<pre>\n";
73 } else {
74     echo "$title\n\n";
75 }
76
77 if ($is_web) {
78     echo "<h3>Using lib version: " . PhpXmlRpc::$xmlrpcVersion . " on PHP version: " . phpversion() . "</h3>\n";
79     if ($xd) {
80         echo "<h4>XDEBUG profiling enabled: skipping remote tests. Trace file is: " . htmlspecialchars(xdebug_get_profiler_filename()) . "</h4>\n";
81     }
82     flush();
83     ob_flush();
84 } else {
85     echo "Using lib version: " . PhpXmlRpc::$xmlrpcVersion . " on PHP version: " . phpversion() . "\n";
86     if ($xd) {
87         echo "XDEBUG profiling enabled: skipping remote tests\nTrace file is: " . xdebug_get_profiler_filename() . "\n";
88     }
89 }
90
91 // test 'manual style' data encoding vs. 'automatic style' encoding
92 begin_test('Data encoding (large array)', 'manual encoding');
93 for ($i = 0; $i < $num_tests; $i++) {
94     $vals = array();
95     for ($j = 0; $j < 10; $j++) {
96         $valarray = array();
97         foreach ($data[$j] as $key => $val) {
98             $values = array();
99             $values[] = new Value($val[0], 'int');
100             $values[] = new Value($val[1], 'double');
101             $values[] = new Value($val[2], 'string');
102             $values[] = new Value($val[3], 'boolean');
103             $values[] = new Value($val[4], 'dateTime.iso8601');
104             $values[] = new Value($val[5], 'int');
105             $values[] = new Value($val[6], 'double');
106             $values[] = new Value($val[7], 'string');
107             $values[] = new Value($val[8], 'boolean');
108             $values[] = new Value($val[9], 'dateTime.iso8601');
109             $valarray[$key] = new Value($values, 'array');
110         }
111         $vals[] = new Value($valarray, 'struct');
112     }
113     $value = new Value($vals, 'array');
114     $out = $value->serialize();
115 }
116 end_test('Data encoding (large array)', 'manual encoding', $out);
117
118 begin_test('Data encoding (large array)', 'automatic encoding');
119 $encoder = new Encoder();
120 for ($i = 0; $i < $num_tests; $i++) {
121     $value = $encoder->encode($data, array('auto_dates'));
122     $out = $value->serialize();
123 }
124 end_test('Data encoding (large array)', 'automatic encoding', $out);
125
126 if (function_exists('xmlrpc_set_type')) {
127     begin_test('Data encoding (large array)', 'xmlrpc-epi encoding');
128     for ($i = 0; $i < $num_tests; $i++) {
129         for ($j = 0; $j < 10; $j++) {
130             foreach ($keys as $k) {
131                 xmlrpc_set_type($data[$j][$k][4], 'datetime');
132                 xmlrpc_set_type($data[$j][$k][8], 'datetime');
133             }
134         }
135         $out = xmlrpc_encode($data);
136     }
137     end_test('Data encoding (large array)', 'xmlrpc-epi encoding', $out);
138 }
139
140 // test 'old style' data decoding vs. 'automatic style' decoding
141 $dummy = new Request('');
142 $out = new Response($value);
143 $in = '<?xml version="1.0" ?>' . "\n" . $out->serialize();
144
145 begin_test('Data decoding (large array)', 'manual decoding');
146 for ($i = 0; $i < $num_tests; $i++) {
147     $response = $dummy->ParseResponse($in, true);
148     $value = $response->value();
149     $result = array();
150     foreach($value as $val1) {
151         $out = array();
152         foreach($val1 as $name => $val) {
153             $out[$name] = array();
154             foreach($val as $data) {
155                 $out[$name][] = $data->scalarval();
156             }
157         }
158         $result[] = $out;
159     }
160 }
161 end_test('Data decoding (large array)', 'manual decoding', $result);
162
163 begin_test('Data decoding (large array)', 'manual decoding deprecated');
164 for ($i = 0; $i < $num_tests; $i++) {
165     $response = $dummy->ParseResponse($in, true);
166     $value = $response->value();
167     $result = array();
168     $l = $value->arraysize();
169     for ($k = 0; $k < $l; $k++) {
170         $val1 = $value->arraymem($k);
171         $out = array();
172         foreach($val1 as $name => $val) {
173             $out[$name] = array();
174             $m = $val->arraysize();
175             for ($j = 0; $j < $m; $j++) {
176                 $data = $val->arraymem($j);
177                 $out[$name][] = $data->scalarval();
178             }
179         } // while
180         $result[] = $out;
181     }
182 }
183 end_test('Data decoding (large array)', 'manual decoding deprecated', $result);
184
185 begin_test('Data decoding (large array)', 'automatic decoding');
186 for ($i = 0; $i < $num_tests; $i++) {
187     $response = $dummy->ParseResponse($in, true, 'phpvals');
188     $value = $response->value();
189 }
190 end_test('Data decoding (large array)', 'automatic decoding', $value);
191
192 if (function_exists('xmlrpc_decode')) {
193     begin_test('Data decoding (large array)', 'xmlrpc-epi decoding');
194     for ($i = 0; $i < $num_tests; $i++) {
195         $response = $dummy->ParseResponse($in, true, 'xml');
196         $value = xmlrpc_decode($response->value());
197     }
198     end_test('Data decoding (large array)', 'xmlrpc-epi decoding', $value);
199 }
200
201 if (!$xd) {
202
203     $num_tests = 25;
204
205     /// test multicall vs. many calls vs. keep-alives
206     $encoder = new Encoder();
207     $value = $encoder->encode($data1, array('auto_dates'));
208     $req = new Request('interopEchoTests.echoValue', array($value));
209     $reqs = array();
210     for ($i = 0; $i < $num_tests; $i++) {
211         $reqs[] = $req;
212     }
213     $server = explode(':', $args['HTTPSERVER']);
214     if (count($server) > 1) {
215         $srv = $server[1] . '://' . $server[0] . $args['HTTPURI'];
216         $c = new Client($args['HTTPURI'], $server[0], $server[1]);
217     } else {
218         $srv = $args['HTTPSERVER'] . $args['HTTPURI'];
219         $c = new Client($args['HTTPURI'], $args['HTTPSERVER']);
220     }
221     // do not interfere with http compression
222     $c->accepted_compression = array();
223     //$c->debug=true;
224
225     $testName = "Repeated send (small array) to $srv";
226
227     if (function_exists('gzinflate')) {
228         $c->accepted_compression = null;
229     }
230     begin_test($testName, 'http 10');
231     $response = array();
232     for ($i = 0; $i < $num_tests; $i++) {
233         $resp = $c->send($req);
234         $response[] = $resp->value();
235     }
236     end_test($testName, 'http 10', $response);
237
238     if (function_exists('curl_init')) {
239         begin_test($testName, 'http 11 w. keep-alive');
240         $response = array();
241         for ($i = 0; $i < $num_tests; $i++) {
242             $resp = $c->send($req, 10, 'http11');
243             $response[] = $resp->value();
244         }
245         end_test($testName, 'http 11 w. keep-alive', $response);
246
247         $c->keepalive = false;
248         begin_test($testName, 'http 11');
249         $response = array();
250         for ($i = 0; $i < $num_tests; $i++) {
251             $resp = $c->send($req, 10, 'http11');
252             $response[] = $resp->value();
253         }
254         end_test($testName, 'http 11', $response);
255     }
256
257     begin_test($testName, 'multicall');
258     $response = $c->send($reqs);
259     foreach ($response as $key => & $val) {
260         $val = $val->value();
261     }
262     end_test($testName, 'multicall', $response);
263
264     if (function_exists('gzinflate')) {
265         $c->accepted_compression = array('gzip');
266         $c->request_compression = 'gzip';
267
268         begin_test($testName, 'http 10 w. compression');
269         $response = array();
270         for ($i = 0; $i < $num_tests; $i++) {
271             $resp = $c->send($req);
272             $response[] = $resp->value();
273         }
274         end_test($testName, 'http 10 w. compression', $response);
275
276         if (function_exists('curl_init')) {
277             begin_test($testName, 'http 11 w. keep-alive and compression');
278             $response = array();
279             for ($i = 0; $i < $num_tests; $i++) {
280                 $resp = $c->send($req, 10, 'http11');
281                 $response[] = $resp->value();
282             }
283             end_test($testName, 'http 11 w. keep-alive and compression', $response);
284
285             $c->keepalive = false;
286             begin_test($testName, 'http 11 w. compression');
287             $response = array();
288             for ($i = 0; $i < $num_tests; $i++) {
289                 $resp = $c->send($req, 10, 'http11');
290                 $response[] = $resp->value();
291             }
292             end_test($testName, 'http 11 w. compression', $response);
293         }
294
295         begin_test($testName, 'multicall w. compression');
296         $response = $c->send($reqs);
297         foreach ($response as $key => & $val) {
298             $val = $val->value();
299         }
300         end_test($testName, 'multicall w. compression', $response);
301     }
302 } // end of 'if no xdebug profiling'
303
304
305 echo "\n";
306 foreach ($test_results as $test => $results) {
307     echo "\nTEST: $test\n";
308     foreach ($results as $case => $data) {
309         echo "  $case: {$data['time']} secs - Output data CRC: " . crc32(serialize($data['result'])) . "\n";
310     }
311 }
312
313 if ($is_web) {
314     echo "\n</pre>\n</body>\n</html>\n";
315 }