11# -*- coding: utf-8 -*-
22from __future__ import absolute_import , unicode_literals
33
4+ import logging
45import os
56import json
67
1213
1314from .commits .github import GITHUB_URL_RE
1415
16+ logger = logging .getLogger (__name__ )
17+
1518
1619@python_2_unicode_compatible
1720class Project (models .Model ):
@@ -73,6 +76,31 @@ def save(self, *args, **kwargs):
7376 super (Project , self ).save (* args , ** kwargs )
7477
7578
79+ class HistoricalValue (object ):
80+ def __init__ (self , name = None , val = 0 , color = 'none' ):
81+ self .name = name
82+ self .val = val
83+ self .color = color
84+
85+ def update_if_less_important_than (self , val , color , name ):
86+ if self .is_less_important_than (val , color ):
87+ # Do update biggest total change
88+ self .val = val
89+ self .color = color
90+ self .name = name
91+
92+ def is_less_important_than (self , val , color ):
93+ if color == "red" and self .color != "red" :
94+ return True
95+ elif color == "red" and abs (val ) > abs (self .val ):
96+ return True
97+ elif (color == "green" and self .color != "red" and
98+ abs (val ) > abs (self .val )):
99+ return True
100+ else :
101+ return False
102+
103+
76104@python_2_unicode_compatible
77105class Branch (models .Model ):
78106 name = models .CharField (max_length = 20 )
@@ -225,11 +253,44 @@ class Meta:
225253
226254 def save (self , * args , ** kwargs ):
227255 tablelist = self .get_changes_table (force_save = True )
228- max_change , max_change_ben , max_change_color = 0 , None , "none"
229- max_trend , max_trend_ben , max_trend_color = 0 , None , "none"
230- average_change , average_change_units , average_change_color = 0 , None , "none"
231- average_trend , average_trend_units , average_trend_color = 0 , None , "none"
256+ self .reinitialize ()
257+ changes = self .aggregate_significant_changes (tablelist )
258+ self .update_to_highest_priority_change (changes )
259+
260+ super (Report , self ).save (* args , ** kwargs )
261+
262+ def update_to_highest_priority_change (self , changes ):
263+ average_change = changes ['average_change' ]
264+ max_change = changes ['max_change' ]
265+ average_trend = changes ['average_trend' ]
266+ max_trend = changes ['max_trend' ]
267+
268+ # Average change
269+ if average_change .color != "none" :
270+ self .update_summary ("Average {} {}" , average_change )
271+ self .colorcode = average_change .color
272+
273+ # Single benchmark change
274+ elif max_change .color != "none" :
275+ self .update_summary ("{} {}" , max_change )
276+ self .colorcode = max_change .color
277+
278+ # Average trend
279+ elif average_trend .color != "none" :
280+ self .update_summary ("Average {} trend {}" , average_trend )
281+ self .update_by_trend_color (average_trend .color )
282+
283+ # Single benchmark trend
284+ elif max_trend .color != "none" :
285+ self .update_summary ("{} trend {}" , max_trend )
286+ # use lighter colors for trend results:
287+ self .update_by_trend_color (max_trend .color )
288+
289+ def reinitialize (self ):
290+ self .summary = ""
291+ self .colorcode = "none"
232292
293+ def aggregate_significant_changes (self , tablelist ):
233294 # Get default threshold values
234295 change_threshold = 3.0
235296 trend_threshold = 5.0
@@ -239,95 +300,54 @@ def save(self, *args, **kwargs):
239300 if hasattr (settings , 'TREND_THRESHOLD' ) and settings .TREND_THRESHOLD :
240301 trend_threshold = settings .TREND_THRESHOLD
241302
242- # Fetch big changes for each unit type and each benchmark
243- for units in tablelist :
244- # Total change
245- val = units ['totals' ]['change' ]
303+ max_change = HistoricalValue ()
304+ max_trend = HistoricalValue ()
305+ average_change = HistoricalValue ()
306+ average_trend = HistoricalValue ()
307+
308+ # Fetch big changes for each quantity and each benchmark
309+ for quantity in tablelist :
310+ quantity_name = quantity ['units_title' ].lower ()
311+ less_is_better = quantity ['lessisbetter' ]
312+
313+ val = quantity ['totals' ]['change' ]
246314 if val == "-" :
247315 continue
248- color = self .getcolorcode (val , units ['lessisbetter' ],
249- change_threshold )
250- if self .is_big_change (val , color , average_change , average_change_color ):
251- # Do update biggest total change
252- average_change = val
253- average_change_units = units ['units_title' ]
254- average_change_color = color
255- # Total trend
256- val = units ['totals' ]['trend' ]
316+ color = self .getcolorcode (val , less_is_better , change_threshold )
317+ average_change .update_if_less_important_than (val , color ,
318+ quantity_name )
319+
320+ val = quantity ['totals' ]['trend' ]
257321 if val != "-" :
258- color = self .getcolorcode (val , units ['lessisbetter' ],
259- trend_threshold )
260- if self .is_big_change (val , color , average_trend , average_trend_color ):
261- # Do update biggest total trend change
262- average_trend = val
263- average_trend_units = units ['units_title' ]
264- average_trend_color = color
265- for row in units ['rows' ]:
322+ color = self .getcolorcode (val , less_is_better , trend_threshold )
323+ average_trend .update_if_less_important_than (val , color ,
324+ quantity_name )
325+
326+ for row in quantity ['rows' ]:
327+ benchmark_name = row ['bench_name' ]
266328 # Single change
267329 val = row ['change' ]
268330 if val == "-" :
269331 continue
270- color = self .getcolorcode (val , units [ 'lessisbetter' ] ,
332+ color = self .getcolorcode (val , less_is_better ,
271333 change_threshold )
272- if self .is_big_change (val , color , max_change , max_change_color ):
273- # Do update biggest single change
274- max_change = val
275- max_change_ben = row ['bench_name' ]
276- max_change_color = color
334+ max_change .update_if_less_important_than (val , color ,
335+ benchmark_name )
277336 # Single trend
278337 val = row ['trend' ]
279338 if val == "-" :
280339 continue
281- color = self .getcolorcode (val , units ['lessisbetter' ], trend_threshold )
282- if self .is_big_change (val , color , max_trend , max_trend_color ):
283- # Do update biggest single trend change
284- max_trend = val
285- max_trend_ben = row ['bench_name' ]
286- max_trend_color = color
287- # Reinitialize
288- self .summary = ""
289- self .colorcode = "none"
290-
291- # Save summary in order of priority
292- # (changes results before trends, averages before individual results)
293-
294- # Average change
295- if average_change_color != "none" :
296- self .summary = "Average %s %s" % (
297- average_change_units .lower (),
298- self .updown (average_change ))
299- self .colorcode = average_change_color
300-
301- # Single benchmark change
302- elif max_change_color != "none" :
303- self .summary = "%s %s" % (
304- max_change_ben ,
305- self .updown (max_change ))
306- self .colorcode = max_change_color
307-
308- # Average trend
309- elif average_trend_color != "none" :
310- self .summary = "Average %s trend %s" % (
311- average_trend_units .lower (),
312- self .updown (average_trend ))
313- # use lighter colors for trend results:
314- if average_trend_color == "red" :
315- self .colorcode = "yellow"
316- elif average_trend_color == "green" :
317- self .colorcode = "lightgreen"
318-
319- # Single benchmark trend
320- elif max_trend_color != "none" :
321- self .summary = "%s trend %s" % (
322- max_trend_ben ,
323- self .updown (max_trend ))
324- # use lighter colors for trend results:
325- if max_trend_color == "red" :
326- self .colorcode = "yellow"
327- elif max_trend_color == "green" :
328- self .colorcode = "lightgreen"
329-
330- super (Report , self ).save (* args , ** kwargs )
340+ color = self .getcolorcode (val , less_is_better , trend_threshold )
341+ max_trend .update_if_less_important_than (val , color ,
342+ benchmark_name )
343+ return {'max_change' : max_change ,
344+ 'max_trend' : max_trend ,
345+ 'average_change' : average_change ,
346+ 'average_trend' : average_trend }
347+
348+ def update_summary (self , format , hist_value ):
349+ self .summary = format .format (hist_value .name ,
350+ self .updown (hist_value .val ))
331351
332352 def updown (self , val ):
333353 """Substitutes plus/minus with up/down"""
@@ -338,16 +358,12 @@ def updown(self, val):
338358 else :
339359 return "%s %.1f%%" % (direction , aval )
340360
341- def is_big_change (self , val , color , current_val , current_color ):
342- if color == "red" and current_color != "red" :
343- return True
344- elif color == "red" and abs (val ) > abs (current_val ):
345- return True
346- elif (color == "green" and current_color != "red" and
347- abs (val ) > abs (current_val )):
348- return True
349- else :
350- return False
361+ def update_by_trend_color (self , color ):
362+ # use lighter colors for trend results:
363+ if color == "red" :
364+ self .colorcode = "yellow"
365+ elif color == "green" :
366+ self .colorcode = "lightgreen"
351367
352368 def getcolorcode (self , val , lessisbetter , threshold ):
353369 if lessisbetter :
@@ -359,6 +375,20 @@ def getcolorcode(self, val, lessisbetter, threshold):
359375 else :
360376 return "none"
361377
378+ def get_last_revisions (self , depth ):
379+ lastrevisions = []
380+ try :
381+ lastrevisions = Revision .objects .filter (
382+ branch = self .revision .branch
383+ ).filter (
384+ date__lte = self .revision .date
385+ ).order_by ('-date' )[:depth + 1 ]
386+ # Same as self.revision unless in a different branch
387+ except Exception as e :
388+ logger .warning ("Exception while getting results: %s" , e ,
389+ exc_info = True )
390+ return lastrevisions
391+
362392 def get_changes_table (self , trend_depth = 10 , force_save = False ):
363393 # Determine whether required trend value is the default one
364394 default_trend = 10
@@ -370,16 +400,10 @@ def get_changes_table(self, trend_depth=10, force_save=False):
370400 return self ._get_tablecache ()
371401 # Otherwise generate a new changes table
372402 # Get latest revisions for this branch (which also sets the project)
373- try :
374- lastrevisions = Revision .objects .filter (
375- branch = self .revision .branch
376- ).filter (
377- date__lte = self .revision .date
378- ).order_by ('-date' )[:trend_depth + 1 ]
379- # Same as self.revision unless in a different branch
380- lastrevision = lastrevisions [0 ]
381- except :
403+ lastrevisions = self .get_last_revisions (trend_depth )
404+ if not lastrevisions :
382405 return []
406+
383407 change_list = []
384408 pastrevisions = []
385409 if len (lastrevisions ) > 1 :
@@ -394,7 +418,7 @@ def get_changes_table(self, trend_depth=10, force_save=False):
394418 pastrevisions = lastrevisions [trend_depth - 2 :trend_depth + 1 ]
395419
396420 result_list = Result .objects .filter (
397- revision = lastrevision
421+ revision = lastrevisions [ 0 ]
398422 ).filter (
399423 environment = self .environment
400424 ).filter (
@@ -463,23 +487,23 @@ def get_changes_table(self, trend_depth=10, force_save=False):
463487 # Calculate trend:
464488 # percentage change relative to average of 3 previous results
465489 # Calculate past average
466- average = 0
467- averagecount = 0
490+ result_sum = 0
491+ num_past_results = 0
468492 if len (pastrevisions ):
469493 for rev in pastrevisions :
470- past_rev = Result .objects .filter (
494+ past_result = Result .objects .filter (
471495 revision = rev
472496 ).filter (
473497 environment = self .environment
474498 ).filter (
475499 executable = self .executable
476500 ).filter (benchmark = bench )
477- if past_rev .count ():
478- average += past_rev [0 ].value
479- averagecount += 1
501+ if past_result .count ():
502+ result_sum += past_result [0 ].value
503+ num_past_results += 1
480504 trend = "-"
481- if average :
482- average = average / averagecount
505+ if result_sum :
506+ average = result_sum / num_past_results
483507 trend = (result - average ) * 100 / average
484508 totals ['trend' ].append (result / average )
485509
0 commit comments