ManifestGenerator shouldn't need more than 1GB of memory or run for 30 seconds
[WebKit-https.git] / Websites / perf.webkit.org / public / include / manifest-generator.php
1 <?php
2
3 class ManifestGenerator {
4     private $db;
5     private $manifest;
6
7     // FIXME: Compute this value from config.json
8     const MANIFEST_PATH = '../data/manifest.json';
9
10     function __construct($db) {
11         $this->db = $db;
12         $this->elapsed_time = NULL;
13     }
14
15     function generate() {
16         $start_time = microtime(true);
17
18         $platform_table = $this->db->fetch_table('platforms');
19         $repositories_table = $this->db->fetch_table('repositories');
20
21         $repositories_with_commit = $this->db->query_and_fetch_all(
22             'SELECT DISTINCT(commit_repository) FROM commits WHERE commit_reported IS TRUE');
23         if (!$repositories_with_commit)
24             $repositories_with_commit = array();
25
26         foreach ($repositories_with_commit as &$row)
27             $row = $row['commit_repository'];
28
29         $tests = (object)$this->tests();
30         $metrics = (object)$this->metrics();
31         $platforms = (object)$this->platforms($platform_table, false);
32         $repositories = (object)$this->repositories($repositories_table, $repositories_with_commit);
33
34         $this->manifest = array(
35             'siteTitle' => config('siteTitle', 'Performance Dashboard'),
36             'tests' => &$tests,
37             'metrics' => &$metrics,
38             'all' => &$platforms,
39             'dashboard' => (object)array(), // Only used by v1 UI.
40             'repositories' => &$repositories,
41             'builders' => (object)$this->builders(),
42             'bugTrackers' => (object)$this->bug_trackers($repositories_table),
43             'triggerables'=> (object)$this->triggerables(),
44             'dashboards' => (object)config('dashboards'),
45             'summaryPages' => config('summaryPages'),
46             'fileUploadSizeLimit' => config('uploadFileLimitInMB', 0) * 1024 * 1024,
47             'testAgeToleranceInHours' => config('testAgeToleranceInHours'),
48         );
49
50         $this->elapsed_time = (microtime(true) - $start_time) * 1000;
51
52         return TRUE;
53     }
54
55     function manifest() { return $this->manifest; }
56
57     function store() {
58         return generate_json_data_with_elapsed_time_if_needed('manifest.json', $this->manifest, $this->elapsed_time);
59     }
60
61     private function tests() {
62         $tests = array();
63         $tests_table = $this->db->fetch_table('tests');
64         if (!$tests_table)
65             return $tests;
66         foreach ($tests_table as &$test_row) {
67             $tests[$test_row['test_id']] = array(
68                 'name' => $test_row['test_name'],
69                 'url' => $test_row['test_url'],
70                 'parentId' => $test_row['test_parent'] ? intval($test_row['test_parent']) : NULL,
71             );
72         }
73         return $tests;
74     }
75
76     private function metrics() {
77         $metrics = array();
78         $metrics_table = $this->db->query_and_fetch_all('SELECT * FROM test_metrics LEFT JOIN aggregators ON metric_aggregator = aggregator_id');
79         if (!$metrics_table)
80             return $metrics;
81         foreach ($metrics_table as &$row) {
82             $metrics[$row['metric_id']] = array(
83                 'name' => $row['metric_name'],
84                 'test' => intval($row['metric_test']),
85                 'aggregator' => $row['aggregator_name']);
86         }
87         return $metrics;
88     }
89
90     private function platforms(&$platform_table, $is_dashboard) {
91         $config_query = $this->db->query('SELECT config_platform, config_metric,
92             extract(epoch from config_runs_last_modified at time zone \'utc\') * 1000 AS last_modified
93             FROM test_configurations');
94
95         $platform_metrics = array();
96
97         if ($config_query) {
98             $current_platform_entry = null;
99             $last_modified_map = array();
100             while (1) {
101                 $config_row = $this->db->fetch_next_row($config_query);
102                 if (!$config_row)
103                     break;
104
105                 $platform_id = $config_row['config_platform'];
106                 $metric_id = $config_row['config_metric'];
107                 $last_modified = intval($config_row['last_modified']);
108
109                 $key = $platform_id . '-' . $metric_id;
110                 if (array_key_exists($key, $last_modified_map)) {
111                     $last_modified_map[$key] = max($last_modified_map[$key], $last_modified);
112                     continue;
113                 }
114                 $last_modified_map[$key] = $last_modified;
115
116                 $current_platform_entry = &array_ensure_item_has_array($platform_metrics, $platform_id);
117                 array_ensure_item_has_array($current_platform_entry, 'metrics');
118                 array_push($current_platform_entry['metrics'], intval($metric_id));
119             }
120         }
121         $configurations = array();
122
123         $platforms = array();
124         if ($platform_table) {
125             foreach ($platform_table as &$platform_row) {
126                 if (Database::is_true($platform_row['platform_hidden']))
127                     continue;
128                 $id = $platform_row['platform_id'];
129                 if (array_key_exists($id, $platform_metrics)) {
130                     $metrics = &$platform_metrics[$id]['metrics'];
131                     $last_modified = array();
132                     foreach ($metrics as $metric_id)
133                         array_push($last_modified, $last_modified_map[$id . '-' . $metric_id]);
134                     $platforms[$id] = array(
135                         'name' => &$platform_row['platform_name'],
136                         'metrics' => &$metrics,
137                         'lastModified' => &$last_modified
138                     );
139                 }
140             }
141         }
142         return $platforms;
143     }
144
145     private function repositories($repositories_table, $repositories_with_commit) {
146         $repositories = array();
147         if (!$repositories_table)
148             return $repositories;
149         foreach ($repositories_table as &$row) {
150             $repositories[$row['repository_id']] = array(
151                 'name' => $row['repository_name'],
152                 'url' => $row['repository_url'],
153                 'blameUrl' => $row['repository_blame_url'],
154                 'owner'=> $row['repository_owner'],
155                 'hasReportedCommits' => in_array($row['repository_id'], $repositories_with_commit));
156         }
157
158         return $repositories;
159     }
160
161     private function builders() {
162         $builders_table = $this->db->fetch_table('builders');
163         if (!$builders_table)
164             return array();
165         $builders = array();
166         foreach ($builders_table as &$row)
167             $builders[$row['builder_id']] = array('name' => $row['builder_name'], 'buildUrl' => $row['builder_build_url']);
168
169         return $builders;
170     }
171
172     private function bug_trackers($repositories_table) {
173         $tracker_id_to_repositories = array();
174         $tracker_repositories_table = $this->db->fetch_table('tracker_repositories');
175         if ($tracker_repositories_table) {
176             foreach ($tracker_repositories_table as $row) {
177                 array_push(array_ensure_item_has_array($tracker_id_to_repositories, $row['tracrepo_tracker']),
178                     $row['tracrepo_repository']);
179             }
180         }
181
182         $bug_trackers = array();
183         $bug_trackers_table = $this->db->fetch_table('bug_trackers');
184         if ($bug_trackers_table) {
185             foreach ($bug_trackers_table as &$row) {
186                 $bug_trackers[$row['tracker_id']] = array(
187                     'name' => $row['tracker_name'],
188                     'bugUrl' => $row['tracker_bug_url'],
189                     'newBugUrl' => $row['tracker_new_bug_url'],
190                     'repositories' => array_get($tracker_id_to_repositories, $row['tracker_id']));
191             }
192         }
193
194         return $bug_trackers;
195     }
196
197     private function triggerables()
198     {
199         return ManifestGenerator::fetch_triggerables($this->db, array());
200     }
201
202     static function fetch_triggerables($db, $query)
203     {
204         $triggerables = $db->select_rows('build_triggerables', 'triggerable', $query);
205         if (!$triggerables)
206             return array();
207
208         $id_to_triggerable = array();
209         $triggerable_id_to_repository_set = array();
210         foreach ($triggerables as &$row) {
211             $id = $row['triggerable_id'];
212             $id_to_triggerable[$id] = array(
213                 'name' => $row['triggerable_name'],
214                 'isDisabled' => Database::is_true($row['triggerable_disabled']),
215                 'acceptedRepositories' => array(),
216                 'repositoryGroups' => array(),
217                 'configurations' => array());
218             $triggerable_id_to_repository_set[$id] = array();
219         }
220
221         $repository_groups = $db->fetch_table('triggerable_repository_groups', 'repositorygroup_name');
222         $group_repositories = $db->fetch_table('triggerable_repositories');
223         if ($repository_groups && $group_repositories) {
224             $repository_set_by_group = array();
225             foreach ($group_repositories as &$repository_row) {
226                 $group_id = $repository_row['trigrepo_group'];
227                 array_ensure_item_has_array($repository_set_by_group, $group_id);
228                 array_push($repository_set_by_group[$group_id], array(
229                     'repository' => intval($repository_row['trigrepo_repository']),
230                     'acceptsPatch' => Database::is_true($repository_row['trigrepo_accepts_patch'])));
231             }
232             foreach ($repository_groups as &$group_row) {
233                 $triggerable_id = $group_row['repositorygroup_triggerable'];
234                 if (!array_key_exists($triggerable_id, $id_to_triggerable))
235                     continue;
236                 $triggerable = &$id_to_triggerable[$triggerable_id];
237                 $group_id = $group_row['repositorygroup_id'];
238                 $repository_list = array_get($repository_set_by_group, $group_id, array());
239                 array_push($triggerable['repositoryGroups'], array(
240                     'id' => intval($group_row['repositorygroup_id']),
241                     'name' => $group_row['repositorygroup_name'],
242                     'description' => $group_row['repositorygroup_description'],
243                     'hidden' => Database::is_true($group_row['repositorygroup_hidden']),
244                     'acceptsCustomRoots' => Database::is_true($group_row['repositorygroup_accepts_roots']),
245                     'repositories' => $repository_list));
246                 // V2 UI compatibility.
247                 foreach ($repository_list as &$repository_data) {
248                     $repository_id = $repository_data['repository'];
249                     $set = &$triggerable_id_to_repository_set[$triggerable_id];
250                     if (array_key_exists($repository_id, $set))
251                         continue;
252                     $set[$repository_id] = true;
253                     array_push($triggerable['acceptedRepositories'], $repository_id);
254                 }
255
256             }
257         }
258
259         $configuration_map = $db->fetch_table('triggerable_configurations');
260         if ($configuration_map) {
261             foreach ($configuration_map as &$row) {
262                 $triggerable_id = $row['trigconfig_triggerable'];
263                 if (!array_key_exists($triggerable_id, $id_to_triggerable))
264                     continue;
265                 $triggerable = &$id_to_triggerable[$triggerable_id];
266                 array_push($triggerable['configurations'], array(intval($row['trigconfig_test']), intval($row['trigconfig_platform'])));
267             }
268         }
269
270         return $id_to_triggerable;
271     }
272 }
273
274 ?>