Introduce the concept of analysis task to perf dashboard
[WebKit-https.git] / Websites / perf.webkit.org / public / v2 / manifest.js
1 App.NameLabelModel = DS.Model.extend({
2     name: DS.attr('string'),
3     label: function ()
4     {
5         return this.get('name');
6     }.property('name'),
7 });
8
9 App.Test = App.NameLabelModel.extend({
10     url: DS.attr('string'),
11     parent: DS.belongsTo('test', {inverse: 'childTests'}),
12     childTests: DS.hasMany('test', {inverse: 'parent'}),
13     metrics: DS.hasMany('metrics'),
14 });
15
16 App.Metric = App.NameLabelModel.extend({
17     test: DS.belongsTo('test'),
18     aggregator: DS.attr('string'),
19     label: function ()
20     {
21         return this.get('name') + ' : ' + this.get('aggregator');
22     }.property('name', 'aggregator'),
23     path: function ()
24     {
25         var path = [];
26         var parent = this.get('test');
27         while (parent) {
28             path.push(parent.get('name'));
29             parent = parent.get('parent');
30         }
31         return path.reverse();
32     }.property('name', 'test'),
33     fullName: function ()
34     {
35         return this.get('path').join(' \u2208 ') /* ∈ */
36             + ' : ' + this.get('label');
37     }.property('path', 'label'),
38 });
39
40 App.Builder = App.NameLabelModel.extend({
41     buildUrl: DS.attr('string'),
42     urlFromBuildNumber: function (buildNumber)
43     {
44         var template = this.get('buildUrl');
45         return template ? template.replace(/\$buildNumber/g, buildNumber) : null;
46     }
47 });
48
49 App.BugTracker = App.NameLabelModel.extend({
50     bugUrl: DS.attr('string'),
51     newBugUrl: DS.attr('string'),
52     repositories: DS.hasMany('repository'),
53 });
54
55 App.Platform = App.NameLabelModel.extend({
56     _metricSet: null,
57     _testSet: null,
58     metrics: DS.hasMany('metric'),
59     containsMetric: function (metric)
60     {
61         if (!this._metricSet)
62             this._metricSet = new Ember.Set(this.get('metrics'));
63         return this._metricSet.contains(metric);
64     },
65     containsTest: function (test)
66     {
67         if (!this._testSet) {
68             var set = new Ember.Set();
69             this.get('metrics').forEach(function (metric) {
70                 for (var test = metric.get('test'); test; test = test.get('parent'))
71                     set.push(test);
72             });
73             this._testSet = set;
74         }
75         return this._testSet.contains(test);
76     },
77 });
78
79 App.Repository = App.NameLabelModel.extend({
80     url: DS.attr('string'),
81     blameUrl: DS.attr('string'),
82     hasReportedCommits: DS.attr('boolean'),
83     urlForRevision: function (currentRevision) {
84         return (this.get('url') || '').replace(/\$1/g, currentRevision);
85     },
86     urlForRevisionRange: function (from, to) {
87         return (this.get('blameUrl') || '').replace(/\$1/g, from).replace(/\$2/g, to);
88     },
89 });
90
91 App.MetricSerializer = App.PlatformSerializer = DS.RESTSerializer.extend({
92     normalizePayload: function (payload)
93     {
94         var results = {
95             platforms: this._normalizeIdMap(payload['all']),
96             builders: this._normalizeIdMap(payload['builders']),
97             tests: this._normalizeIdMap(payload['tests']).map(function (test) {
98                 test['parent'] = test['parentId'];
99                 return test;
100             }),
101             metrics: this._normalizeIdMap(payload['metrics']),
102             repositories: this._normalizeIdMap(payload['repositories']),
103             bugTrackers: this._normalizeIdMap(payload['bugTrackers']),
104         };
105
106         for (var testId in payload['tests']) {
107             var test = payload['tests'][testId];
108             var parent = payload['tests'][test['parent']];
109             if (!parent)
110                 continue;
111             if (!parent['childTests'])
112                 parent['childTests'] = [];
113             parent['childTests'].push(testId);
114         }
115
116         for (var metricId in payload['metrics']) {
117             var metric = payload['metrics'][metricId];
118             var test = payload['tests'][metric['test']];
119             if (!test['metrics'])
120                 test['metrics'] = [];
121             test['metrics'].push(metricId);
122         }
123
124         return results;
125     },
126     _normalizeIdMap: function (idMap)
127     {
128         var results = [];
129         for (var id in idMap) {
130             var definition = idMap[id];
131             definition['id'] = id;
132             results.push(definition);
133         }
134         return results;
135     }
136 });
137
138 App.PlatformAdapter = DS.RESTAdapter.extend({
139     buildURL: function (type, id)
140     {
141         return '../data/manifest.json';
142     },
143 });
144
145 App.MetricAdapter = DS.RESTAdapter.extend({
146     buildURL: function (type, id)
147     {
148         return '../data/manifest.json';
149     },
150 });
151
152 App.Manifest = Ember.Controller.extend({
153     platforms: null,
154     topLevelTests: null,
155     repositories: [],
156     repositoriesWithReportedCommits: [],
157     bugTrackers: [],
158     _platformById: {},
159     _metricById: {},
160     _builderById: {},
161     _repositoryById: {},
162     _fetchPromise: null,
163     fetch: function ()
164     {
165         if (this._fetchPromise)
166             return this._fetchPromise;
167         // FIXME: We shouldn't use DS.Store at all.
168         var store = App.__container__.lookup('store:main');
169         var promise = store.findAll('platform');
170         this._fetchPromise = promise.then(this._fetchedManifest.bind(this, store));
171         return this._fetchPromise;
172     },
173     isFetched: function () { return !!this.get('platforms'); }.property('platforms'),
174     platform: function (id) { return this._platformById[id]; },
175     metric: function (id) { return this._metricById[id]; },
176     builder: function (id) { return this._builderById[id]; },
177     repository: function (id) { return this._repositoryById[id]; },
178     _fetchedManifest: function (store)
179     {
180         var startTime = Date.now();
181         var self = this;
182
183         var topLevelTests = [];
184         store.all('test').forEach(function (test) {
185             var parent = test.get('parent');
186             if (!parent)
187                 topLevelTests.push(test);
188         });
189         this.set('topLevelTests', topLevelTests);
190
191         store.all('metric').forEach(function (metric) {
192             self._metricById[metric.get('id')] = metric;
193         });
194         var platforms = store.all('platform');
195         platforms.forEach(function (platform) {
196             self._platformById[platform.get('id')] = platform;
197         });
198         this.set('platforms', platforms);
199
200         store.all('builder').forEach(function (builder) {
201             self._builderById[builder.get('id')] = builder;
202         });
203
204         var repositories = store.all('repository');
205         repositories.forEach(function (repository) {
206             self._repositoryById[repository.get('id')] = repository;
207         });
208         this.set('repositories', repositories.sortBy('id'));
209         this.set('repositoriesWithReportedCommits',
210             repositories.filter(function (repository) { return repository.get('hasReportedCommits'); }));
211
212         this.set('bugTrackers', store.all('bugTracker').sortBy('name'));
213     },
214     fetchRunsWithPlatformAndMetric: function (store, platformId, metricId)
215     {
216         return Ember.RSVP.all([
217             RunsData.fetchRuns(platformId, metricId),
218             this.fetch(store),
219         ]).then(function (values) {
220             var runs = values[0];
221
222             var platform = App.Manifest.platform(platformId);
223             var metric = App.Manifest.metric(metricId);
224
225             // FIXME: Include this information in JSON and process it in RunsData.fetchRuns
226             var unit = {'Combined': '', // Assume smaller is better for now.
227                 'FrameRate': 'fps',
228                 'Runs': 'runs/s',
229                 'Time': 'ms',
230                 'Malloc': 'bytes',
231                 'JSHeap': 'bytes',
232                 'Allocations': 'bytes',
233                 'EndAllocations': 'bytes',
234                 'MaxAllocations': 'bytes',
235                 'MeanAllocations': 'bytes'}[metric.get('name')];
236             runs.unit = unit;
237
238             return {platform: platform, metric: metric, runs: runs};
239         });
240     },
241 }).create();