Perf dashboard's should not include results more than 366 days old in JSON
[WebKit-https.git] / Websites / perf.webkit.org / public / api / runs.php
1 <?php
2
3 require('../include/json-header.php');
4
5 function main($path) {
6     if (count($path) != 1)
7         exit_with_error('InvalidRequest');
8
9     $parts = explode('-', $path[0]);
10     if (count($parts) != 2)
11         exit_with_error('InvalidRequest');
12
13     $test_group_id = array_get($_GET, 'testGroup');
14     $should_cache = array_get($_GET, 'cache');
15     $should_echo_results = !array_key_exists('noResult', $_GET);
16
17     $db = new Database;
18     if (!$db->connect())
19         exit_with_error('DatabaseConnectionFailure');
20
21     if ($test_group_id)
22         $generator = new RunsGeneratorForTestGroup($db, $test_group_id);
23     else
24         $generator = new RunsGenerator($db);
25
26     $platform_id = intval($parts[0]);
27     $metric_id = intval($parts[1]);
28     $config_rows = $db->query_and_fetch_all('SELECT *
29         FROM test_configurations WHERE config_metric = $1 AND config_platform = $2', array($metric_id, $platform_id));
30     if (!$config_rows)
31         exit_with_error('ConfigurationNotFound');
32
33     if ($test_group_id)
34         $test_group_id = intval($test_group_id);
35     else if ($should_cache) { // Only v1 UI needs caching.
36         $maxage = config('jsonCacheMaxAge');
37         header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $maxage) . ' GMT');
38         header("Cache-Control: maxage=$maxage");
39     }
40
41     foreach ($config_rows as $config)
42         $generator->fetch_runs($config['config_type'], $config['config_id'], $config['config_runs_last_modified']);
43
44     $content = success_json($generator->results());
45     if (!$should_echo_results) {
46         echo $generator->results()['elapsedTime'];
47         return;
48     }
49
50     if (!$test_group_id)
51         generate_data_file("$platform_id-$metric_id.json", $content);
52     echo $content;
53 }
54
55 class RunsGenerator {
56     function __construct($db) {
57         $this->db = $db;
58         $this->results = array();
59         $this->last_modified = 0;
60         $this->start_time = microtime(true);
61     }
62
63     function results() {
64         return array(
65             'configurations' => &$this->results,
66             'lastModified' => $this->last_modified,
67             'elapsedTime' => (microtime(true) - $this->start_time) * 1000);
68     }
69
70     function fetch_runs($name, $config_id, $last_modified) {
71         $this->last_modified = max($this->last_modified, Database::to_js_time($last_modified));
72
73         $beginning_of_time = intval(time() - 366 * 24 * 3600) * 1000;
74
75         $results = $this->execute_query($config_id);
76
77         $formatted_runs = array();
78         while ($row = $this->db->fetch_next_row($results)) {
79             $build_time = Database::to_js_time($row['build_time']);
80             $max_time = $build_time;
81             $revisions = self::parse_revisions_array($row['revisions'], $max_time);
82             if ($max_time < $beginning_of_time)
83                 continue;
84             array_push($formatted_runs, self::format_run($row, $build_time, $revisions));
85         }
86
87         $this->results[$name] = $formatted_runs;
88     }
89
90     function execute_query($config_id) {
91         return $this->db->query('
92             SELECT test_runs.*, builds.*, array_agg((commit_repository, commit_revision, commit_time)) AS revisions
93                 FROM builds
94                     LEFT OUTER JOIN build_commits ON commit_build = build_id
95                     LEFT OUTER JOIN commits ON build_commit = commit_id, test_runs
96                 WHERE run_build = build_id AND run_config = $1 AND NOT EXISTS (SELECT * FROM build_requests WHERE request_build = build_id)
97                 GROUP BY build_id, run_id', array($config_id));
98     }
99
100     private static function format_run($run, $build_time, $revisions) {
101         return array(
102             'id' => intval($run['run_id']),
103             'mean' => floatval($run['run_mean_cache']),
104             'iterationCount' => intval($run['run_iteration_count_cache']),
105             'sum' => floatval($run['run_sum_cache']),
106             'squareSum' => floatval($run['run_square_sum_cache']),
107             'markedOutlier' => Database::is_true($run['run_marked_outlier']),
108             'revisions' => $revisions,
109             'build' => $run['build_id'],
110             'buildTime' => $build_time,
111             'buildNumber' => intval($run['build_number']),
112             'builder' => $run['build_builder']);
113     }
114
115     private static function parse_revisions_array($postgres_array, &$max_time) {
116         // e.g. {"(WebKit,131456,\"2012-10-16 14:53:00\")","(Chromium,162004,)"}
117         $outer_array = json_decode('[' . trim($postgres_array, '{}') . ']');
118         $revisions = array();
119         foreach ($outer_array as $item) {
120             $name_and_revision = explode(',', trim($item, '()'));
121             if (!$name_and_revision[0])
122                 continue;
123             $time = Database::to_js_time(trim($name_and_revision[2], '"'));
124             $max_time = max($max_time, $time);
125             $revisions[trim($name_and_revision[0], '"')] = array(trim($name_and_revision[1], '"'), $time);
126         }
127         return $revisions;
128     }
129 }
130
131 class RunsGeneratorForTestGroup extends RunsGenerator {
132     function __construct($db, $test_group_id) {
133         parent::__construct($db);
134         $this->test_group_id = $test_group_id;
135     }
136
137     function execute_query($config_id) {
138         return $this->db->query('
139             SELECT test_runs.*, builds.*, array_agg((commit_repository, commit_revision, commit_time)) AS revisions
140                 FROM builds
141                     LEFT OUTER JOIN build_commits ON commit_build = build_id
142                     LEFT OUTER JOIN commits ON build_commit = commit_id,
143                     test_runs, build_requests, analysis_test_groups
144                 WHERE run_build = build_id AND run_config = $1 AND request_build = build_id AND request_group = $2
145                 GROUP BY build_id, run_id', array($config_id, $this->test_group_id));
146     }
147 }
148
149 main(array_key_exists('PATH_INFO', $_SERVER) ? explode('/', trim($_SERVER['PATH_INFO'], '/')) : array());
150
151 ?>