Skip to content

Commit

Permalink
Add report Model
Browse files Browse the repository at this point in the history
  • Loading branch information
tobami committed Jan 12, 2011
1 parent da2b8d1 commit 9ea24a6
Show file tree
Hide file tree
Showing 5 changed files with 282 additions and 152 deletions.
8 changes: 7 additions & 1 deletion speedcenter/codespeed/admin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
from codespeed.models import Project, Revision, Executable, Benchmark, Result, Environment
from codespeed.models import Project, Revision, Executable, Benchmark
from codespeed.models import Result, Environment, Report
from django.contrib import admin

class ProjectAdmin(admin.ModelAdmin):
Expand Down Expand Up @@ -35,3 +36,8 @@ class ResultAdmin(admin.ModelAdmin):
list_filter = ('date', 'executable', 'benchmark', 'environment')

admin.site.register(Result, ResultAdmin)

class ReportAdmin(admin.ModelAdmin):
list_display = ('revision', 'summary', 'colorcode')

admin.site.register(Report, ReportAdmin)
257 changes: 256 additions & 1 deletion speedcenter/codespeed/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
from django.db import models
from codespeed import settings

class Project(models.Model):
REPO_TYPES = (
Expand Down Expand Up @@ -66,7 +67,7 @@ def __unicode__(self):


class Environment(models.Model):
name = models.CharField(unique=True,max_length=30)
name = models.CharField(unique=True, max_length=30)
cpu = models.CharField(max_length=30, blank=True)
memory = models.CharField(max_length=30, blank=True)
os = models.CharField(max_length=30, blank=True)
Expand All @@ -92,3 +93,257 @@ def __unicode__(self):

class Meta:
unique_together = ("revision", "executable", "benchmark", "environment")


class Report(models.Model):
revision = models.ForeignKey(Revision)
environment = models.ForeignKey(Environment)
executable = models.ForeignKey(Executable)
summary = models.CharField(max_length=30, default="OK")
colorcode = models.CharField(max_length=10, default="none")

def __unicode__(self):
return "Report for " + str(self.revision.commitid)

class Meta:
unique_together = ("revision", "executable", "environment")

def save(self, *args, **kwargs):
tablelist = self.get_changes_table()
max_change, max_change_ben, max_change_color = 0, None, "none"
max_trend, max_trend_ben, max_trend_color = 0, None, "none"
average_change, average_change_units, average_change_color = 0, None, "none"
average_trend, average_trend_units, average_trend_color = 0, None, "none"

# Get default threshold values
change_threshold = 3.0
trend_threshold = 4.0
if hasattr(settings, 'change_threshold') and settings.change_threshold != None:
change_threshold = settings.change_threshold
if hasattr(settings, 'trend_threshold') and settings.trend_threshold != None:
trend_threshold = settings.trend_threshold

# Fetch big changes for each unit type and each benchmark
for units in tablelist:
# Total change
val = units['totals']['change']
if val == "-": continue
color = self.getcolorcode(val, units['lessisbetter'], change_threshold)
if self.is_big_change(val, color, average_change, average_change_color):
# Do update biggest total change
average_change = val
average_change_units = units['units_title']
average_change_color = color
# Total trend
val = units['totals']['trend']
if val == "-": continue
color = self.getcolorcode(val, units['lessisbetter'], trend_threshold)
if self.is_big_change(val, color, average_trend, average_trend_color):
# Do update biggest total trend change
average_trend = val
average_trend_units = units['units_title']
# A trend break is only a warning
if color == "red":
color = "yellow"
average_trend_color = color
for row in units['rows']:
# Single change
val = row['change']
if val == "-": continue
color = self.getcolorcode(val, units['lessisbetter'], change_threshold)
if self.is_big_change(val, color, max_change, max_change_color):
# Do update biggest single change
max_change = val
max_change_ben = row['benchmark']
max_change_color = color
# Single trend
val = row['trend']
if val == "-": continue
color = self.getcolorcode(val, units['lessisbetter'], trend_threshold)
if self.is_big_change(val, color, max_trend, max_trend_color):
# Do update biggest single trend change
max_trend = val
max_trend_ben = row['benchmark']
# A trend break is only a warning
if color == "red":
color = "yellow"
max_trend_color = color

if abs(max_trend) > trend_threshold:
self.summary = "%s trend %.1f%%" % (
max_trend_ben, round(max_trend, 1))
self.colorcode = max_trend_color
if abs(average_trend) > trend_threshold:
if average_trend_color == "yellow" or self.colorcode != "yellow":
self.summary = "Average %s trend %.1f%%" % (
average_trend_units.lower(), round(average_trend, 1))
self.colorcode = average_trend_color
if abs(max_change) > change_threshold:
if max_change_color == "red" or self.colorcode != "yellow":
self.summary = "%s %.1f%%" % (
max_change_ben, round(max_change, 1))
self.colorcode = max_change_color
if abs(average_change) > change_threshold:
if average_change_color == "red" or\
(self.colorcode != "red" and self.colorcode != "yellow"):
self.summary = "Average %s %.1f%%" % (
average_change_units.lower(), round(average_change, 1))
self.colorcode = average_change_color

super(Report, self).save(*args, **kwargs)

def is_big_change(self, val, color, current_val, current_color):
if color == "red" and\
abs(val) > abs(current_val):
return True
elif color == "green" and current_color != "red" and \
abs(val) > abs(current_val):
return True
else:
return False

def getcolorcode(self, val, lessisbetter, threshold):
if lessisbetter:
val = -val
colorcode = "yellow"
if val < -threshold:
colorcode = "red"
elif val > threshold:
colorcode = "green"
return colorcode;

def get_changes_table(self, trend_depth=10):
lastrevisions = Revision.objects.filter(
project=self.executable.project
).filter(
date__lte=self.revision.date
).order_by('-date')[:trend_depth+1]
lastrevision = lastrevisions[0]#same as self.revision unless in a different branch

change_list = []
pastrevisions = []
if len(lastrevisions) > 1:
changerevision = lastrevisions[1]
change_list = Result.objects.filter(
revision=changerevision
).filter(
environment=self.environment
).filter(
executable=self.executable
)
pastrevisions = lastrevisions[trend_depth-2:trend_depth+1]

result_list = Result.objects.filter(
revision=lastrevision
).filter(
environment=self.environment
).filter(
executable=self.executable
)

tablelist = []
for units in Benchmark.objects.all().values('units').distinct():
currentlist = []
units_title = ""
hasmin = False
hasmax = False
has_stddev = False
smallest = 1000
totals = {'change': [], 'trend': [],}
for bench in Benchmark.objects.filter(units=units['units']):
units_title = bench.units_title
lessisbetter = bench.lessisbetter
resultquery = result_list.filter(benchmark=bench)
if not len(resultquery): continue

resobj = resultquery.filter(benchmark=bench)[0]

std_dev = resobj.std_dev
if std_dev is not None: has_stddev = True
else: std_dev = "-"

val_min = resobj.val_min
if val_min is not None: hasmin = True
else: val_min = "-"

val_max = resobj.val_max
if val_max is not None: hasmax = True
else: val_max = "-"

# Calculate percentage change relative to previous result
result = resobj.value
change = "-"
if len(change_list):
c = change_list.filter(benchmark=bench)
if c.count() and c[0].value and result:
change = (result - c[0].value)*100/c[0].value
totals['change'].append(result / c[0].value)

# Calculate trend:
# percentage change relative to average of 3 previous results
# Calculate past average
average = 0
averagecount = 0
if len(pastrevisions):
for rev in pastrevisions:
past_rev = Result.objects.filter(
revision=rev
).filter(
environment=self.environment
).filter(
executable=self.executable
).filter(benchmark=bench)
if past_rev.count():
average += past_rev[0].value
averagecount += 1
trend = "-"
if average:
average = average / averagecount
trend = (result - average)*100/average
totals['trend'].append(result / average)

# Retain lowest number different than 0
# to be used later for calculating significant digits
if result < smallest and result:
smallest = result

currentlist.append({
'benchmark': bench,
'result': result,
'std_dev': std_dev,
'val_min': val_min,
'val_max': val_max,
'change': change,
'trend': trend
})

# Compute Arithmetic averages
for key in totals.keys():
if len(totals[key]):
totals[key] = float(sum(totals[key]) / len(totals[key]))
else:
totals[key] = "-"

if totals['change'] != "-":
totals['change'] = (totals['change'] - 1) * 100#transform ratio to percentage
if totals['trend'] != "-":
totals['trend'] = (totals['trend'] - 1) * 100#transform ratio to percentage

# Calculate significant digits
digits = 2;
while smallest < 1:
smallest *= 10
digits += 1

tablelist.append({
'units': units['units'],
'units_title': units_title,
'lessisbetter': lessisbetter,
'has_stddev': has_stddev,
'hasmin': hasmin,
'hasmax': hasmax,
'precission': digits,
'totals': totals,
'rows': currentlist
})
return tablelist
4 changes: 2 additions & 2 deletions speedcenter/codespeed/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
# Example: defaultbaseline = {'executable': 'myexe', 'revision': '21'}

# Threshold that determines when a performance change over the last result is significant
changethreshold = 3.0
change_threshold = 3.0

# Threshold that determines when a performance change
# over a number of revisions is significant
trendthreshold = 3.0
trend_threshold = 4.0

# Changes view options ##
defaultexecutable = None # Executable that should be chosen as default in the changes view
Expand Down
Loading

0 comments on commit 9ea24a6

Please sign in to comment.