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