Permalink
Browse files

Merge pull request #84 from mozilla/b2g-perbranch-revision-combo

added group by revision and branch select functionality
  • Loading branch information...
2 parents c753d09 + 7346f0e commit 2c94e4ce30cbac503018addaba09cc2e7e7f0339 @jeads jeads committed Feb 1, 2013
View
14 datazilla/controller/admin/refdata/objectstore_refdata.py
@@ -1,4 +1,5 @@
from datazilla.model.refdata import PerformanceTestRefDataModel
+from datazilla.model.base import PerformanceTestModel
def get_error_count(project, startdate, enddate):
@@ -40,6 +41,19 @@ def get_json_blob_by_test_run_id(project, test_run_id):
return {}
+def get_json_blob_by_revisions(project, branch, gaia_revision, gecko_revision):
+
+ ptm = PerformanceTestModel(project)
+ test_run_ids = ptm.get_test_run_ids_by_revisions(
+ branch, gaia_revision, gecko_revision
+ )
+ ptm.disconnect()
+
+ ptrm = PerformanceTestRefDataModel(project)
+ blobs = ptrm.get_object_json_blob_for_test_run(test_run_ids)
+ ptm.disconnect()
+
+ return blobs
def get_error_detail_count(project, startdate, enddate):
"""Return counts attempting to parse some of the bad JSON to extract details."""
View
4 datazilla/controller/admin/testdata.py
@@ -233,12 +233,12 @@ def get_default_version(project, branch, product_name):
return version
-def get_test_value_summary(project, test_ids, url, begin, now):
+def get_test_value_summary(project, branch, test_ids, url, begin, now):
ptm = factory.get_ptm(project)
data = ptm.get_value_summary_by_test_ids(
- test_ids, url, begin, now
+ branch, test_ids, url, begin, now
)
ptm.disconnect()
View
65 datazilla/model/base.py
@@ -967,17 +967,18 @@ def get_test_run_value_summary(self, test_run_id):
return test_run_value_table
def get_value_summary_by_test_ids(
- self, test_ids, url, begin_date, end_date
+ self, branch, test_ids, url, begin_date, end_date
):
data = []
- if test_ids and url and begin_date and end_date:
+ if branch and test_ids and url and begin_date and end_date:
proc = 'perftest.selects.get_value_summary_by_test_id'
r_string = ','.join( map( lambda t_id: '%s', test_ids ) )
+ test_ids.append( branch )
test_ids.append( url )
test_ids.append( begin_date )
test_ids.append( end_date )
@@ -991,6 +992,25 @@ def get_value_summary_by_test_ids(
return data
+ def get_test_run_ids_by_revisions(
+ self, branch, revision, gecko_revision):
+ #TODO: This method is specific to the b2g project and should
+ # be placed in a derived class
+
+ proc = 'perftest.selects.get_test_run_ids_from_revisions'
+
+ data = self.sources["perftest"].dhub.execute(
+ proc=proc,
+ debug_show=self.DEBUG,
+ placeholders=[revision, gecko_revision, branch]
+ )
+
+ test_run_ids = []
+ for d in data:
+ test_run_ids.append(d['id'])
+
+ return test_run_ids
+
def get_test_run_ids(
self, branch, revisions, product_name=None, os_name=None,
os_version=None, branch_version=None, processor=None,
@@ -1234,6 +1254,9 @@ def load_test_data(self, data):
self._set_test_values(data, test_id, test_run_id)
self._set_test_aux_data(data, test_id, test_run_id)
+ # Make project specific changes
+ self._adapt_project_specific_data(data, test_run_id)
+
return test_run_id
@@ -1354,6 +1377,44 @@ def _adapt_production_data(self, data):
if ('mac' in os) and ('os x' in osversion):
data['test_build']['branch'] += '-Non-PGO'
+ def _adapt_project_specific_data(self, data, test_run_id):
+
+ ###
+ #TODO: This should be moved into a derived class
+ ###
+ if self.project == 'b2g':
+ ###
+ #b2g has two unique test run fields, gecko_revision and
+ #build_revision, they need to be loaded here
+ ###
+ self._update_b2g_test_run(data, test_run_id)
+
+ def _update_b2g_test_run(self, data, test_run_id):
+
+ if 'gecko_revision' in data['test_build']:
+
+ gecko_proc = 'perftest.inserts.set_gecko_revision'
+
+ gecko_revision = data['test_build']['gecko_revision']
+
+ test_dict = self.sources["perftest"].dhub.execute(
+ proc=gecko_proc,
+ debug_show=self.DEBUG,
+ placeholders=[ gecko_revision, test_run_id ]
+ )
+
+ if 'build_revision' in data['test_build']:
+
+ build_proc = 'perftest.inserts.set_build_revision'
+
+ build_revision = data['test_build']['build_revision']
+
+ test_dict = self.sources["perftest"].dhub.execute(
+ proc=build_proc,
+ debug_show=self.DEBUG,
+ placeholders=[ build_revision, test_run_id ]
+ )
+
def _set_test_aux_data(self, data, test_id, test_run_id):
"""Insert test aux data to db for given test_id and test_run_id."""
for aux_data, aux_values in data.get('results_aux', {}).items():
View
2 datazilla/model/metrics.py
@@ -1109,7 +1109,7 @@ def log_msg(self, revision, test_run_id, msg_type, msg):
def get_application_log(self, revision):
- proc = 'perftest.inserts.get_application_log'
+ proc = 'perftest.selects.get_application_log'
placeholders = [ revision ]
View
47 datazilla/model/sql/perftest.json
@@ -333,7 +333,26 @@
"host":"master_host"
},
- "get_application_log":{
+ "set_gecko_revision":{
+
+ "sql":"UPDATE test_run
+ SET gecko_revision = ?
+ WHERE id = ?",
+
+ "host":"master_host"
+ },
+ "set_build_revision":{
+
+ "sql":"UPDATE test_run
+ SET build_revision = ?
+ WHERE id = ?",
+
+ "host":"master_host"
+ }
+ },
+ "selects":{
+
+ "get_application_log":{
"sql":"SELECT `revision`,
`test_run_id`,
`msg_type`,
@@ -343,9 +362,8 @@
WHERE `revision` = ?",
"host":"read_host"
- }
- },
- "selects":{
+ },
+
"get_test_run_summary":{
"sql":"SELECT tr.id AS 'test_run_id',
@@ -530,10 +548,11 @@
"sql":"SELECT tv.test_run_id,
tv.page_id,
tr.revision,
+ tr.gecko_revision,
+ tr.build_revision,
tr.test_id,
tr.date_run,
b.product_id,
- tr.test_id,
m.operating_system_id,
p.url,
ROUND( AVG(tv.value), 2 ) AS avg,
@@ -546,13 +565,25 @@
LEFT JOIN test_run AS tr ON tv.test_run_id = tr.id
LEFT JOIN machine AS m ON tr.machine_id = m.id
LEFT JOIN build AS b ON tr.build_id = b.id
- WHERE tr.test_id IN (REP0) AND p.url = ? AND tr.date_run >= ? AND tr.date_run <= ?
- GROUP BY tr.id, p.url
- ORDER BY tr.id DESC",
+ LEFT JOIN product AS pr ON b.product_id = pr.id
+ WHERE tr.test_id IN (REP0) AND pr.branch = ? AND p.url = ? AND tr.date_run >= ? AND tr.date_run <= ?
+ GROUP BY tr.revision, tr.gecko_revision, tr.test_id, p.url
+ ORDER BY tr.date_run, tr.id DESC",
"host":"read_host"
},
+ "get_test_run_ids_from_revisions":{
+
+ "sql":"SELECT tr.id
+ FROM test_run AS tr
+ LEFT JOIN build AS b ON tr.build_id = b.id
+ LEFT JOIN product AS pr ON b.product_id = pr.id
+ WHERE tr.revision = ? AND tr.gecko_revision = ? AND pr.branch = ?
+ ORDER BY tr.id ASC",
+
+ "host":"read_host"
+ },
"get_page_values":{
"sql":"SELECT tv.id AS test_value_id,
View
21 datazilla/webapp/apps/datazilla/refdata/objectstore_views.py
@@ -33,6 +33,27 @@ def get_error_count(request, project):
)
return HttpResponse(json.dumps(stats), content_type=API_CONTENT_TYPE)
+def get_json_blob_by_revisions(request, project):
+
+ branch = request.GET.get("branch")
+ gaia_revision = request.GET.get("gaia_revision")
+ gecko_revision = request.GET.get("gecko_revision")
+
+ blobs = objectstore_refdata.get_json_blob_by_revisions(
+ project, branch, gaia_revision, gecko_revision)
+
+ if blobs:
+ try:
+ for index, b in enumerate(blobs):
+ blobs[index]['json_blob'] = json.loads(b['json_blob'])
+ except ValueError as e:
+ pass
+
+ return HttpResponse(json.dumps(blobs), content_type=API_CONTENT_TYPE)
+ else:
+ return HttpResponse(
+ "gaia revision, {0}, and gecko revision, {1} not found".format(gaia_revision, gecko_revision),
+ status=404)
def get_json_blob(request, project, id):
"""Return a json object for the objectstore id provided"""
View
5 datazilla/webapp/apps/datazilla/refdata/urls.py
@@ -8,9 +8,12 @@
(r"^objectstore/error_list/?$", "objectstore_views.get_error_list"),
+ (r"^objectstore/json_blob/revisions/?$", "objectstore_views.get_json_blob_by_revisions"),
+
(r"^objectstore/json_blob/(?P<id>\d+)/?$", "objectstore_views.get_json_blob"),
- (r"^objectstore/json_blob/test_run/(?P<test_run_id>\d+)/?$", "objectstore_views.get_json_blob_by_test_run_id"),
+ (r"^objectstore/json_blob/test_run/(?P<test_run_id>\d+)/?$",
+ "objectstore_views.get_json_blob_by_test_run_id"),
(r"^objectstore/db_size/?$", "objectstore_views.get_db_size"),
View
7 datazilla/webapp/apps/datazilla/testdata/views.py
@@ -217,6 +217,7 @@ def get_application_log(request, project, revision):
def get_test_value_summary(request, project):
+ branch = request.GET['branch']
test_ids = utils.get_id_list(request.GET['test_ids'])
page_name = request.GET.get("page_name", "")
range = request.GET.get("range", 30)
@@ -232,11 +233,7 @@ def get_test_value_summary(request, project):
return HttpResponse(
json.dumps(testdata.get_test_value_summary(
- project,
- test_ids,
- page_name,
- begin,
- now
+ project, branch, test_ids, page_name, begin, now
)),
content_type=API_CONTENT_TYPE,
)
View
1 datazilla/webapp/static/js/b2g_apps/AppsPage.js
@@ -19,6 +19,7 @@ var AppsPage = new Class( {
this.gaiaHrefBase = "https://github.com/mozilla-b2g/gaia/commit/";
this.geckoHrefBase = "http://git.mozilla.org/?p=releases/gecko.git;a=commit;h=";
+ this.buildHrefBase = "https://github.com/mozilla-b2g/platform_build/commit/";
},
setRefData: function(){
View
48 datazilla/webapp/static/js/b2g_apps/GraphControlsComponent.js
@@ -20,6 +20,7 @@ var GraphControlsComponent = new Class({
this.appLookup = {};
this.testLookup = {};
+ this.branchLookup = {};
this.model.getApps(this, this.initializeAppList);
@@ -75,15 +76,32 @@ var GraphControlsComponent = new Class({
this.appLookup[ seriesDatum.id ] = seriesDatum;
}
- this.model.getTests(this, this.initializeTestList);
+ this.model.getBranches(this, this.initializeBranchList);
},
+ initializeBranchList: function(data){
+
+ var keys = _.keys(data).sort();
+
+ var branch = "";
+ var i = 0;
+
+ for(i = 0; i<keys.length; i++){
+
+ branch = data[ keys[i] ].branch;
+ if(!this.branchLookup[branch]){
+ this.branchLookup[branch] = true;
+ this.view.addBranch(branch);
+ }
+ }
+
+ //Make sure apps and branches are loaded before tests are initialized
+ this.model.getTests(this, this.initializeTestList);
+ },
initializeTestList: function(data){
var sortOrder = this.view.getAlphabeticalSortKeys(data);
- sortOrder.reverse();
-
for(var i=0; i<sortOrder.length; i++){
var seriesDatum = data[ sortOrder[i] ];
@@ -154,10 +172,12 @@ var GraphControlsView = new Class({
this.appSeriesContainerSel = '#app_series';
this.testSeriesContainerSel = '#test_series';
+ this.branchSelectMenuSel = '#app_branch';
+
this.idRegex = /^.*_(\d+)$/;
this.colors = [
- '#0b3b40', '#99911c', '#a66247', '#7989b3', '#8bccc4', '#f2eba5', '#ff622e', '#cc8bc7', '#2254bf', '#22bf90', '#666345', '#ffbead', '#481059', '#2c96f2', '#10593d', '#ffc42e', '#4c1a0e', '#a35dd9', '#add9ff', '#196612', '#332409', '#604e73', '#103859', '#3dbf22', '#7f5717', '#462eff', '#1e84a6', '#88b379', '#f2cea5', '#1e1ea6', '#2cdbf2', '#d4f22c', '#e58729', '#091233', '#a61e88', '#ff2ee3',
+ '#0b3b40', '#99911c', '#a66247', '#7989b3', '#8bccc4', '#a35dd9', '#ff622e', '#cc8bc7', '#2254bf', '#22bf90', '#666345', '#ffbead', '#481059', '#2c96f2', '#10593d', '#ffc42e', '#4c1a0e', '#add9ff', '#196612', '#332409', '#604e73', '#103859', '#3dbf22', '#7f5717', '#462eff', '#1e84a6', '#88b379', '#f2cea5', '#1e1ea6', '#2cdbf2', '#d4f22c', '#e58729', '#091233', '#a61e88', '#ff2ee3', '#f2eba5'
];
this.testColor = '#5CB2CB';
@@ -255,6 +275,12 @@ var GraphControlsView = new Class({
}
}
return id;
+ },
+ addBranch: function(branch){
+ var optionEl = $('<option></option>');
+ $(optionEl).attr('value', branch);
+ $(optionEl).text(branch);
+ $(this.branchSelectMenuSel).append(optionEl);
}
});
var GraphControlsModel = new Class({
@@ -271,6 +297,20 @@ var GraphControlsModel = new Class({
},
+ getBranches: function(context, fnSuccess){
+
+ var uri = '/' + APPS_PAGE.refData.project + '/refdata/perftest/ref_data/products';
+
+ jQuery.ajax( uri, {
+ accepts:'application/json',
+ dataType:'json',
+ cache:false,
+ type:'GET',
+ data:data,
+ context:context,
+ success:fnSuccess,
+ });
+ },
getApps: function(context, fnSuccess){
var uri = '/' + APPS_PAGE.refData.project + '/refdata/perftest/ref_data/tests';
View
17 datazilla/webapp/static/js/b2g_apps/PerformanceGraphComponent.js
@@ -84,6 +84,10 @@ var PerformanceGraphComponent = new Class({
$(this.view.timeRangeSel).bind(
'change', _.bind(this.changeTimeRange, this)
);
+
+ $(this.view.branchSel).bind(
+ 'change', _.bind(this.changeTimeRange, this)
+ );
},
formatLabel: function(label, series){
return this.tickDisplayDates[label] || "";
@@ -117,11 +121,13 @@ var PerformanceGraphComponent = new Class({
var testIds = _.keys(data.test_ids);
var range = $(this.view.timeRangeSel).val();
+ var branch = $(this.view.branchSel).val();
this.view.hideData();
this.model.getAppData(
- this, this.renderPlot, testIds.join(','), data.url, range
+ this, this.renderPlot, testIds.join(','), data.url, range,
+ branch
);
},
renderPlot: function(data){
@@ -159,6 +165,7 @@ var PerformanceGraphComponent = new Class({
timestamp = data[i]['date_run'];
+ //Don't add x-axis labels to the first and last x-axis values
if((i > 0) && (i < data.length - 1)){
if(!this.tickDisplayDates[ data[i]['test_run_id'] ]){
formattedTime = this.view.convertTimestampToDate(timestamp);
@@ -224,6 +231,8 @@ var PerformanceGraphComponent = new Class({
this._hoverPlot(event, pos, item);
+ datapointDatum[0]['branch'] = $(this.view.branchSel).val();
+
$(this.view.appContainerSel).trigger(
this.perfPlotClickEvent,
{ 'series':seriesDatum, 'datapoint':datapointDatum[0] }
@@ -256,6 +265,7 @@ var PerformanceGraphView = new Class({
this.appContainerSel = '#app_container';
this.timeRangeSel = '#app_time_range';
+ this.branchSel = '#app_branch';
this.chartContainerSel = '#app_perf_chart';
this.appTestName = '#app_test_name';
this.graphDetailContainerSel = '#app_perf_detail_container';
@@ -345,11 +355,12 @@ var PerformanceGraphModel = new Class({
},
- getAppData: function(context, fnSuccess, testIds, pageName, range){
+ getAppData: function(context, fnSuccess, testIds, pageName, range, branch){
var uri = '/' + APPS_PAGE.refData.project + '/testdata/test_values?' +
- 'test_ids=TEST_IDS&page_name=PAGE_NAME&range=RANGE';
+ 'branch=BRANCH&test_ids=TEST_IDS&page_name=PAGE_NAME&range=RANGE';
+ uri = uri.replace('BRANCH', branch);
uri = uri.replace('TEST_IDS', testIds);
uri = uri.replace('PAGE_NAME', pageName);
uri = uri.replace('RANGE', range);
View
96 datazilla/webapp/static/js/b2g_apps/ReplicateGraphComponent.js
@@ -20,9 +20,11 @@ var ReplicateGraphComponent = new Class({
this.perfPlotClickEvent = 'PERF_PLOT_CLICK_EV';
+ this.data = {};
this.series = {};
this.datapoint = {};
this.chartData = {};
+ this.hoverData = {};
this.chartOptions = {
'grid': {
@@ -53,10 +55,6 @@ var ReplicateGraphComponent = new Class({
);
$(this.view.chartContainerSel).bind(
- 'plotclick', _.bind(this._clickPlot, this)
- );
-
- $(this.view.chartContainerSel).bind(
'plothover', _.bind(this._hoverPlot, this)
);
},
@@ -68,15 +66,14 @@ var ReplicateGraphComponent = new Class({
this.view.hideData();
this.model.getReplicateData(
- this, this.renderPlot, this.datapoint.test_run_id
+ this, this.renderPlot, this.datapoint.branch,
+ this.datapoint.revision, this.datapoint.gecko_revision
);
},
renderPlot: function(data){
- this.view.setDetailContainer(this.series, this.datapoint, data);
-
- var results = data['json_blob']['results'][this.datapoint.url];
+ this.data = data;
this.chartData = {
'color':this.series['color'],
@@ -85,11 +82,37 @@ var ReplicateGraphComponent = new Class({
};
var i=0;
- for(i=0; i<results.length; i++){
- this.chartData['data'].push( [ i + 1, results[i] ] );
- }
+ var j=0;
+ var results = {};
+
+ this.hoverData = {};
+
+ var totalReplicates = 1;
+
+ for(j=0; j<data.length; j++){
+
+ results = data[j]['json_blob']['results'][this.datapoint.url];
- this.view.showData();
+ this.data[j]['replicate_range'] = { 'start':0, 'end':0 };
+ this.data[j]['replicate_range']['start'] = totalReplicates;
+
+ for(i=0; i<results.length; i++){
+
+ this.chartData['data'].push( [ totalReplicates, results[i] ] );
+ this.hoverData[ totalReplicates ] = j;
+
+ totalReplicates++;
+ }
+
+ this.data[j]['replicate_range']['end'] = totalReplicates - 1;
+
+ if( j === 0 ){
+ this.view.setDetailContainer(
+ this.series, this.datapoint, this.data[j]);
+ }
+
+ this.view.showData();
+ }
this.plot = $.plot(
$(this.view.chartContainerSel),
@@ -100,14 +123,16 @@ var ReplicateGraphComponent = new Class({
this.view.setHoverData(1, results[0]);
},
- _clickPlot: function(event, pos, item){
-
- },
_hoverPlot: function(event, pos, item){
if(!_.isEmpty(item)){
var datum = this.chartData['data'][ item.dataIndex ];
this.view.setHoverData(datum[0], datum[1]);
+ var dataIndex = this.hoverData[ datum[0] ];
+
+ if( this.data[dataIndex] ){
+ this.view.setDetailContainer(this.series, this.datapoint, this.data[dataIndex]);
+ }
}
}
});
@@ -133,8 +158,8 @@ var ReplicateGraphView = new Class({
this.idPrefix = 'app_replicate_';
this.idFields = [
- 'application', 'test', 'revision', 'gecko_revision',
- 'avg', 'min', 'max', 'std'
+ 'application', 'replicate range', 'test', 'revision',
+ 'gecko_revision', 'avg', 'min', 'max', 'std'
];
},
@@ -215,6 +240,15 @@ var ReplicateGraphView = new Class({
$(this.buildDataContainerSel).empty();
+ var replicateRange = jsonData['replicate_range']['start'] + " - " +
+ jsonData['replicate_range']['end'];
+
+ this.loadField(
+ 'replicate range:',
+ replicateRange,
+ this.buildDataContainerSel
+ );
+
this.loadField(
'date',
this.convertTimestampToDate(
@@ -259,6 +293,25 @@ var ReplicateGraphView = new Class({
this.buildDataContainerSel
);
+ if(jsonData['json_blob']['test_build']['build_revision']){
+
+ var fullBuildRevision = jsonData['json_blob']['test_build']['build_revision'];
+ var truncBuildRevision = APPS_PAGE.getRevisionSlice(fullBuildRevision);
+
+ var divEl = $('<div></div>');
+ $(divEl).addClass('app-control-element app-control-small-element app-build-data');
+ $(divEl).append('Build Revision:');
+
+ var aEl = $('<a></a>');
+ $(aEl).attr('href', APPS_PAGE.buildHrefBase + fullBuildRevision);
+ $(aEl).attr('target', '_blank');
+ $(aEl).text(truncBuildRevision);
+
+ $(divEl).append(aEl);
+
+ $(this.buildDataContainerSel).append(divEl);
+ }
+
},
loadField: function(fieldName, value, container){
@@ -289,10 +342,14 @@ var ReplicateGraphModel = new Class({
},
- getReplicateData: function(context, fnSuccess, testRunId){
+ getReplicateData: function(
+ context, fnSuccess, branch, gaiaRevision, geckoRevision
+ ){
var uri = '/' + APPS_PAGE.refData.project +
- '/refdata/objectstore/json_blob/test_run/' + testRunId;
+ '/refdata/objectstore/json_blob/revisions?branch=' + branch +
+ '&gaia_revision=' + gaiaRevision +
+ '&gecko_revision=' + geckoRevision;
jQuery.ajax( uri, {
accepts:'application/json',
@@ -303,6 +360,5 @@ var ReplicateGraphModel = new Class({
context:context,
success:fnSuccess,
});
-
}
});
View
2 datazilla/webapp/static/js/b2g_apps/apps-summary-min.js
1 addition, 1 deletion not shown because the diff is too large. Please use a local Git client to view these changes.
View
6 datazilla/webapp/templates/apps.summary.html
@@ -57,6 +57,10 @@
<option value="90">90 Days</option>
</select>
</div>
+ <div style="margin-left:30px; margin-right:30px;" class="app-control-element">Gaia Branch:
+ <select id="app_branch">
+ </select>
+ </div>
</div>
</div>
<div class="ui-widget ui-widget-header ui-corner-all app-graph-container">
@@ -98,7 +102,7 @@
<div class="app-control-element app-control-small-element">Std:<span id="app_replicate_std" class="app-data"></span></div>
</div>
<div class="ui-widget ui-widget-header ui-corner-all app-detail-graph-container app-replicate-graph-detail" style="width:300px; top:70px; left:648px;">
- <div style="width:120px;" class="app-control-element app-control-small-element">Replicate Number:<span id="app_replicate_x" class="app-data"></span></div>
+ <div style="width:120px;" class="app-control-element app-control-small-element">Replicate:<span id="app_replicate_x" class="app-data"></span></div>
<div style="width:150px;" class="app-control-element app-control-small-element">Run Time:<span id="app_replicate_y" class="app-data"></span></div>
</div>
<div id="app_replicate_build_data" class="ui-widget ui-widget-header ui-corner-all app-detail-graph-container app-replicate-graph-detail" style="width:300px; height:245px; top:105px; left:648px;">

0 comments on commit 2c94e4c

Please sign in to comment.