Issues (321)

extras/benchmark.php (1 issue)

1
<?php
2
/**
3
 * Benchmarking suite for the PHPXMLRPC lib.
4
 *
5
 * @author Gaetano Giunta
6
 * @copyright (C) 2005-2025 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
 **/
13
14
use PhpXmlRpc\PhpXmlRpc;
15
use PhpXmlRpc\Value;
16
use PhpXmlRpc\Request;
17
use PhpXmlRpc\Client;
18
use PhpXmlRpc\Response;
19
use PhpXmlRpc\Encoder;
20
21
/// @todo allow autoloading when the library is installed as dependency
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();
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for ob_flush(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

48
    /** @scrutinizer ignore-unhandled */ @ob_flush();

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
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 - HTTP
206
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
215
    $server = explode(':', $args['HTTPSERVER']);
216
    if (count($server) > 1) {
217
        $srv = 'http://' . $server[0] . '://' . $server[1] . $args['HTTPURI'];
218
        $c = new Client($args['HTTPURI'], $server[0], $server[1]);
219
    } else {
220
        $srv = 'http://' . $args['HTTPSERVER'] . $args['HTTPURI'];
221
        $c = new Client($args['HTTPURI'], $args['HTTPSERVER']);
222
    }
223
224
    // do not interfere with http compression
225
    $c->setAcceptedCompression(false);
226
    //$c->setDebug(1);
227
228
    $testName = "Repeated send (small array) to $srv";
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
        $c->setOption(Client::OPT_KEEPALIVE, false);
240
        begin_test($testName, 'http 11 no keepalive');
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 no keepalive', $response);
247
248
        begin_test($testName, 'http 11 w. keep-alive');
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 w. keep-alive', $response);
255
        $c->xmlrpc_curl_handle = null;
256
    }
257
258
    // this is a single http call - keepalive on/off does not bother us
259
    begin_test($testName, 'multicall');
260
    $response = $c->send($reqs);
261
    foreach ($response as $key => & $val) {
262
        $val = $val->value();
263
    }
264
    end_test($testName, 'multicall', $response);
265
266
    if (function_exists('gzinflate')) {
267
        $c->setOption(Client::OPT_ACCEPTED_COMPRESSION, array('gzip'));
268
        $c->setOption(Client::OPT_REQUEST_COMPRESSION, 'gzip');
269
270
        begin_test($testName, 'http 10 w. compression');
271
        $response = array();
272
        for ($i = 0; $i < $num_tests; $i++) {
273
            $resp = $c->send($req);
274
            $response[] = $resp->value();
275
        }
276
        end_test($testName, 'http 10 w. compression', $response);
277
278
        if (function_exists('curl_init')) {
279
            $c->setOption(Client::OPT_KEEPALIVE, false);
280
            begin_test($testName, 'http 11 w. compression and no keepalive');
281
            $response = array();
282
            for ($i = 0; $i < $num_tests; $i++) {
283
                $resp = $c->send($req, 10, 'http11');
284
                $response[] = $resp->value();
285
            }
286
            end_test($testName, 'http 11 w. compression and no keepalive', $response);
287
288
            $c->setOption(Client::OPT_KEEPALIVE, true);
289
            begin_test($testName, 'http 11 w. keep-alive and compression');
290
            $response = array();
291
            for ($i = 0; $i < $num_tests; $i++) {
292
                $resp = $c->send($req, 10, 'http11');
293
                $response[] = $resp->value();
294
            }
295
            end_test($testName, 'http 11 w. keep-alive and compression', $response);
296
            $c->xmlrpc_curl_handle = null;
297
        }
298
299
        begin_test($testName, 'multicall w. compression');
300
        $response = $c->send($reqs);
301
        foreach ($response as $key => & $val) {
302
            $val = $val->value();
303
        }
304
        end_test($testName, 'multicall w. compression', $response);
305
    }
306
307
    if (function_exists('curl_init')) {
308
309
        /// test multicall vs. many calls vs. keep-alives - HTTPS
310
311
        $server = explode(':', $args['HTTPSSERVER']);
312
        if (count($server) > 1) {
313
            $srv = 'https://' . $server[0] . ':' . $server[1] . $args['HTTPSURI'];
314
            $c = new Client($args['HTTPSURI'], $server[0], $server[1], 'https');
315
        } else {
316
            $srv = 'https://' . $args['HTTPSSERVER'] . $args['HTTPSURI'];
317
            $c = new Client($args['HTTPSURI'], $args['HTTPSSERVER'], 443, 'https');
318
        }
319
        $c->setOption(Client::OPT_VERIFY_PEER, !$args['HTTPSIGNOREPEER']);
320
        $c->setOption(Client::OPT_VERIFY_HOST, $args['HTTPSVERIFYHOST']);
321
        // do not interfere with http compression
322
        $c->setOption(Client::OPT_ACCEPTED_COMPRESSION, false);
323
        //$c->debug = 1;
324
325
        $testName = "Repeated send (small array) to $srv";
326
327
        $c->setOption(Client::OPT_KEEPALIVE, false);
328
        begin_test($testName, 'https no keep-alive');
329
        $response = array();
330
        for ($i = 0; $i < $num_tests; $i++) {
331
            $resp = $c->send($req);
332
            $response[] = $resp->value();
333
        }
334
        end_test($testName, 'https no keep-alive', $response);
335
336
        $c->setOption(Client::OPT_KEEPALIVE, true);
337
        begin_test($testName, 'https w. keep-alive');
338
        $response = array();
339
        for ($i = 0; $i < $num_tests; $i++) {
340
            $resp = $c->send($req, 10);
341
            $response[] = $resp->value();
342
        }
343
        end_test($testName, 'https w. keep-alive', $response);
344
        $c->xmlrpc_curl_handle = null;
345
346
        begin_test($testName, 'https multicall');
347
        $response = $c->send($reqs);
348
        foreach ($response as $key => & $val) {
349
            $val = $val->value();
350
        }
351
        end_test($testName, 'https multicall', $response);
352
353
        if (function_exists('gzinflate')) {
354
            $c->setOption(Client::OPT_ACCEPTED_COMPRESSION, array('gzip'));
355
            $c->setOption(Client::OPT_REQUEST_COMPRESSION, 'gzip');
356
357
            $c->setOption(Client::OPT_KEEPALIVE, false);
358
            begin_test($testName, 'https w. compression and no keepalive');
359
            $response = array();
360
            for ($i = 0; $i < $num_tests; $i++) {
361
                $resp = $c->send($req);
362
                $response[] = $resp->value();
363
            }
364
            end_test($testName, 'https w. compression and no keepalive', $response);
365
366
            $c->setOption(Client::OPT_KEEPALIVE, true);
367
            begin_test($testName, 'https w. keep-alive and compression');
368
            $response = array();
369
            for ($i = 0; $i < $num_tests; $i++) {
370
                $resp = $c->send($req, 10);
371
                $response[] = $resp->value();
372
            }
373
            end_test($testName, 'https w. keep-alive and compression', $response);
374
            $c->xmlrpc_curl_handle = null;
375
376
            begin_test($testName, 'multicall w. https and compression');
377
            $response = $c->send($reqs);
378
            foreach ($response as $key => & $val) {
379
                $val = $val->value();
380
            }
381
            end_test($testName, 'multicall w. https and compression', $response);
382
        }
383
    }
384
385
    if (function_exists('curl_init') && defined('CURL_HTTP_VERSION_2_0')) {
386
387
        /// test multicall vs. many calls vs. keep-alives - HTTP/2
388
389
        $server = explode(':', $args['HTTPSSERVER']);
390
        if (count($server) > 1) {
391
            $srv = 'https://' . $server[0] . ':' . $server[1] . $args['HTTPSURI'];
392
            $c = new Client($args['HTTPSURI'], $server[0], $server[1], 'https');
393
        } else {
394
            $srv = 'https://' . $args['HTTPSSERVER'] . $args['HTTPSURI'];
395
            $c = new Client($args['HTTPSURI'], $args['HTTPSSERVER'], 443, 'h2');
396
        }
397
        $c->setOption(Client::OPT_VERIFY_PEER, !$args['HTTPSIGNOREPEER']);
398
        $c->setOption(Client::OPT_VERIFY_HOST, $args['HTTPSVERIFYHOST']);
399
        // do not interfere with http compression
400
        $c->setOption(Client::OPT_ACCEPTED_COMPRESSION, false);
401
        //$c->setDebug(1);
402
403
        $testName = "Repeated send (small array) to $srv - HTTP/2";
404
405
        $c->setOption(Client::OPT_KEEPALIVE, false);
406
        begin_test($testName, 'http2 no keep-alive');
407
        $response = array();
408
        for ($i = 0; $i < $num_tests; $i++) {
409
            $resp = $c->send($req);
410
            $response[] = $resp->value();
411
        }
412
        end_test($testName, 'http2 no keep-alive', $response);
413
414
        $c->setOption(Client::OPT_KEEPALIVE, true);
415
        begin_test($testName, 'http2 w. keep-alive');
416
        $response = array();
417
        for ($i = 0; $i < $num_tests; $i++) {
418
            $resp = $c->send($req, 10);
419
            $response[] = $resp->value();
420
        }
421
        end_test($testName, 'http2 w. keep-alive', $response);
422
        $c->xmlrpc_curl_handle = null;
423
424
        begin_test($testName, 'http2 multicall');
425
        $response = $c->send($reqs);
426
        foreach ($response as $key => & $val) {
427
            $val = $val->value();
428
        }
429
        end_test($testName, 'http2 multicall', $response);
430
431
        if (function_exists('gzinflate')) {
432
            $c->setOption(Client::OPT_ACCEPTED_COMPRESSION, array('gzip'));
433
            $c->setOption(Client::OPT_REQUEST_COMPRESSION, 'gzip');
434
435
            $c->setOption(Client::OPT_KEEPALIVE, false);
436
            begin_test($testName, 'http2 w. compression and no keepalive');
437
            $response = array();
438
            for ($i = 0; $i < $num_tests; $i++) {
439
                $resp = $c->send($req);
440
                $response[] = $resp->value();
441
            }
442
            end_test($testName, 'http2 w. compression and no keepalive', $response);
443
444
            $c->setOption(Client::OPT_KEEPALIVE, true);
445
            begin_test($testName, 'http2 w. keep-alive and compression');
446
            $response = array();
447
            for ($i = 0; $i < $num_tests; $i++) {
448
                $resp = $c->send($req, 10);
449
                $response[] = $resp->value();
450
            }
451
            end_test($testName, 'http2 w. keep-alive and compression', $response);
452
            $c->xmlrpc_curl_handle = null;
453
454
            begin_test($testName, 'multicall w. http2 and compression');
455
            $response = $c->send($reqs);
456
            foreach ($response as $key => & $val) {
457
                $val = $val->value();
458
            }
459
            end_test($testName, 'multicall w. http2 and compression', $response);
460
        }
461
    }
462
} // end of 'if no xdebug profiling'
463
464
465
echo "\n";
466
foreach ($test_results as $test => $results) {
467
    echo "\nTEST: $test\n";
468
    foreach ($results as $case => $data) {
469
        echo "  $case: {$data['time']} secs - Output data CRC: " . crc32(serialize($data['result'])) . "\n";
470
    }
471
}
472
473
if ($is_web) {
474
    echo "\n</pre>\n</body>\n</html>\n";
475
}
476