1<?php
2
3namespace Google\Protobuf\Benchmark;
4ini_set('memory_limit', '4096M');
5
6const NAME = "PhpBenchmark.php";
7
8function _require_all($dir, &$prefix) {
9    // require all php files
10    foreach (glob("$dir/*") as $path) {
11        if (preg_match('/\.php$/', $path) &&
12            substr($path, -strlen(NAME)) != NAME) {
13                require_once(substr($path, strlen($prefix) + 1));
14            } elseif (is_dir($path)) {
15                _require_all($path, $prefix);
16            }
17    }
18}
19// include all file
20foreach (explode(PATH_SEPARATOR, get_include_path()) as $one_include_path) {
21    _require_all($one_include_path, $one_include_path);
22}
23
24use Benchmarks\BenchmarkDataset;
25
26class BenchmarkMethod
27{
28    // $args[0]: dataset
29    // $args[1]: message class
30    static function parse(&$args) {
31        $payloads = $args[0]->getPayload();
32        for ($i = $payloads->count() - 1; $i >= 0; $i--) {
33            (new $args[1]())->mergeFromString($payloads->offsetGet($i));
34        }
35    }
36
37    // $args: array of message
38    static function serialize(&$args) {
39        foreach ($args as &$temp_message) {
40            $temp_message->serializeToString();
41        }
42    }
43}
44
45class Benchmark
46{
47    private $benchmark_name;
48    private $args;
49    private $benchmark_time;
50    private $total_bytes;
51    private $coefficient;
52
53    public function __construct($benchmark_name, $args, $total_bytes,
54        $benchmark_time = 5.0) {
55            $this->args = $args;
56            $this->benchmark_name = $benchmark_name;
57            $this->benchmark_time = $benchmark_time;
58            $this->total_bytes = $total_bytes;
59            $this->coefficient = pow (10, 0) / pow(2, 20);
60    }
61
62    public function runBenchmark() {
63        $t = $this->runBenchmarkWithTimes(1);
64        $times = ceil($this->benchmark_time / $t);
65        return $this->total_bytes * $times /
66        ($times == 1 ? $t : $this->runBenchmarkWithTimes($times)) *
67        $this->coefficient;
68    }
69
70    private function runBenchmarkWithTimes($times) {
71        $st = microtime(true);
72        for ($i = 0; $i < $times; $i++) {
73            call_user_func_array($this->benchmark_name, array(&$this->args));
74        }
75        $en = microtime(true);
76        return $en - $st;
77    }
78}
79
80function getMessageName(&$dataset) {
81    switch ($dataset->getMessageName()) {
82        case "benchmarks.proto3.GoogleMessage1":
83            return "\Benchmarks\Proto3\GoogleMessage1";
84        case "benchmarks.proto2.GoogleMessage1":
85            return "\Benchmarks\Proto2\GoogleMessage1";
86        case "benchmarks.proto2.GoogleMessage2":
87            return "\Benchmarks\Proto2\GoogleMessage2";
88        case "benchmarks.google_message3.GoogleMessage3":
89            return "\Benchmarks\Google_message3\GoogleMessage3";
90        case "benchmarks.google_message4.GoogleMessage4":
91            return "\Benchmarks\Google_message4\GoogleMessage4";
92        default:
93            exit("Message " . $dataset->getMessageName() . " not found !");
94    }
95}
96
97function runBenchmark($file, $behavior_prefix) {
98    $datafile = fopen($file, "r") or die("Unable to open file " . $file);
99    $bytes = fread($datafile, filesize($file));
100    $dataset = new BenchmarkDataset(NULL);
101    $dataset->mergeFromString($bytes);
102    $message_name = getMessageName($dataset);
103    $message_list = array();
104    $total_bytes = 0;
105    $payloads = $dataset->getPayload();
106    for ($i = $payloads->count() - 1; $i >= 0; $i--) {
107        $new_message = new $message_name();
108        $new_message->mergeFromString($payloads->offsetGet($i));
109        array_push($message_list, $new_message);
110        $total_bytes += strlen($payloads->offsetGet($i));
111    }
112
113    $parse_benchmark = new Benchmark(
114        "\Google\Protobuf\Benchmark\BenchmarkMethod::parse",
115        array($dataset, $message_name), $total_bytes);
116    $serialize_benchmark = new Benchmark(
117        "\Google\Protobuf\Benchmark\BenchmarkMethod::serialize",
118        $message_list, $total_bytes);
119
120    return array(
121        "filename" => $file,
122        "benchmarks" => array(
123            $behavior_prefix . "_parse" => $parse_benchmark->runBenchmark(),
124            $behavior_prefix . "_serailize" => $serialize_benchmark->runBenchmark()
125        ),
126        "message_name" => $dataset->getMessageName()
127    );
128}
129
130// main
131$json_output = false;
132$results = array();
133$behavior_prefix = "";
134
135foreach ($argv as $index => $arg) {
136    if ($index == 0) {
137        continue;
138    }
139    if ($arg == "--json") {
140        $json_output = true;
141    } else if (strpos($arg, "--behavior_prefix") == 0) {
142        $behavior_prefix = str_replace("--behavior_prefix=", "", $arg);
143    }
144}
145
146foreach ($argv as $index => $arg) {
147    if ($index == 0) {
148        continue;
149    }
150    if (substr($arg, 0, 2) == "--") {
151        continue;
152    } else {
153        array_push($results, runBenchmark($arg, $behavior_prefix));
154    }
155}
156
157if ($json_output) {
158    print json_encode($results);
159} else {
160    print "PHP protobuf benchmark result:\n\n";
161    foreach ($results as $result) {
162        printf("result for test data file: %s\n", $result["filename"]);
163        foreach ($result["benchmarks"] as $benchmark => $throughput) {
164            printf("   Throughput for benchmark %s: %.2f MB/s\n",
165                $benchmark, $throughput);
166        }
167    }
168}
169
170?>
171