Test Failed
Push — master ( 2bc697...ec556c )
by Maciej
02:06
created

bin/Commands/Benchmark/AnalyzeCommand.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * Highlighter
5
 *
6
 * Copyright (C) 2016, Some right reserved.
7
 *
8
 * @author Kacper "Kadet" Donat <[email protected]>
9
 *
10
 * Contact with author:
11
 * Xmpp: [email protected]
12
 * E-mail: [email protected]
13
 *
14
 * From Kadet with love.
15
 */
16
17
namespace Kadet\Highlighter\bin\Commands\Benchmark;
18
19
use Symfony\Component\Console\Command\Command;
20
use Symfony\Component\Console\Helper\Table;
21
use Symfony\Component\Console\Helper\TableCell;
22
use Symfony\Component\Console\Helper\TableSeparator;
23
use Symfony\Component\Console\Input\InputArgument;
24
use Symfony\Component\Console\Input\InputInterface;
25
use Symfony\Component\Console\Input\InputOption;
26
use Symfony\Component\Console\Output\OutputInterface;
27
28
class AnalyzeCommand extends Command
29
{
30
    protected function execute(InputInterface $input, OutputInterface $output)
31
    {
32
        /**
33
         * @noinspection PhpComposerExtensionStubsInspection
34
         * Adding ext-json as dev-only dependency still doesn't
35
         * prevent this issue so we have to ignore this inspection
36
         */
37
        $json = json_decode(file_get_contents($input->getArgument('input')[0]), true);
38
39
        $output->writeln(sprintf(
40
            "Date: <info>%s</info> Formatter: <info>%s</info>, Comment: <info>%s</info>",
41
            date('d.m.Y H:i:s', $json['timestamp']),
42
            $json['formatter'],
43
            isset($json['comment']) ? $json['comment'] : 'none'
44
        ));
45
46
        $table = new Table($output);
47
48
        $suffix = $input->getOption('relative') ? 'bytes/s' : 'ms';
49
        $table->addRow(['set', "min [$suffix]", "avg [$suffix]", "max [$suffix]", "std dev [$suffix]"]);
50
51
        $summary = [];
52
        foreach ($json['results'] as $file => $data) {
53
            $this->separator($file, $table);
54
55
            foreach ($data['times'] as $set => $times) {
56
                $result = array_map(function ($time) use ($data, $input) {
57
                    return $input->getOption('relative') ? $data['size'] / $time : $time * 1000;
58
                }, $times);
59
60
                $this->entry($result, $set, $table);
61
62
                $summary[$set][] = array_sum($result) / count($result);
63
            }
64
65
            if (!isset($data['memory'])) {
66
                continue;
67
            }
68
69
            foreach ($data['memory'] as $set => $memory) {
70
                $result = array_map(function ($memory) use ($data, $input) {
71
                    $bytes = $input->getOption('relative') ? $memory / $data['size'] : $memory;
72
                    return $this->formatBytes($bytes, (bool)$input->getOption('relative'));
73
                }, $memory);
74
75
                $this->entry($result, $set, $table);
76
            }
77
        }
78
79
        if (!$input->hasParameterOption('--summary')) {
80
            $table->render();
81
        }
82
83
        $summary = array_filter($summary, function ($key) use ($input) {
84
            return fnmatch($input->getOption('summary') ?: '*', $key);
85
        }, ARRAY_FILTER_USE_KEY);
86
87
        $max = max(array_map('strlen', array_keys($summary)));
88
        foreach ($summary as $name => $set) {
89
            $output->writeln(sprintf(
90
                "<comment>%s</comment> %s %s",
91
                str_pad($name, $max, ' ', STR_PAD_LEFT),
92
                $this->format($input->getOption('relative') ? array_sum($set) / count($set) : array_sum($set)),
93
                $suffix
94
            ));
95
        }
96
    }
97
98
    protected function separator($file, Table $table)
99
    {
100
        $table->addRows([
101
            new TableSeparator(),
102
            [new TableCell($file, ['colspan' => 5])],
103
            new TableSeparator(),
104
        ]);
105
    }
106
107
    protected function entry($result, $set, Table $table)
108
    {
109
        $min = min($result);
110
        $avg = $this->avarage($result);
111
        $max = max($result);
112
        $dev = $this->stddev($result);
113
114
        $table->addRow([
115
            $set,
116
            $this->format($min),
117
            $this->format($avg),
118
            $this->format($max),
119
            sprintf("%s (%d%%)", $this->format($dev), $dev / $avg * 100),
120
        ]);
121
    }
122
123
    private function format($number)
124
    {
125
        return is_numeric($number) ? number_format($number, 2) : $number;
126
    }
127
128
    private function avarage(array $result)
129
    {
130
        return array_sum($result) / count($result);
131
    }
132
133
    private function stddev($result)
134
    {
135
        $mean = array_sum($result) / count($result);
136
137
        return sqrt(array_sum(array_map(function ($result) use ($mean) {
138
            return pow((float) $result - $mean, 2);
139
        }, $result)) / count($result));
140
    }
141
142
    private function formatBytes($bytes, $relative = false)
0 ignored issues
show
The parameter $relative is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
143
    {
144
        $units = array('B', 'KB', 'MB', 'GB', 'TB');
145
146
        $bytes = max($bytes, 0);
147
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
148
        $pow = min($pow, count($units) - 1);
149
150
        $bytes /= (1 << (10 * $pow));
151
152
        return $this->format($bytes);//.$units[$pow].($relative ? '/byte' : '');
153
    }
154
155
    protected function configure()
156
    {
157
        $this
158
            ->setName('benchmark:analyze')
159
            ->setDescription('Tests performance of KeyLighter')
160
            ->addArgument('input', InputArgument::IS_ARRAY | InputArgument::REQUIRED, 'Input JSON file(s)')
161
            ->addOption('relative', 'r', InputOption::VALUE_NONE, 'Show relative times?')
162
            ->addOption('summary', 'u', InputOption::VALUE_OPTIONAL, 'Show summary times?', '*');
163
    }
164
}
165