Merge branch 'master' of http://github.com/dvander/arewefastyet
This commit is contained in:
Коммит
3ab135082b
|
@ -0,0 +1,107 @@
|
||||||
|
# vim: set ts=4 sw=4 tw=99 et:
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
import awfy
|
||||||
|
import tables
|
||||||
|
|
||||||
|
RUNS = 20
|
||||||
|
|
||||||
|
def isOutliner(item):
|
||||||
|
score = item.score()
|
||||||
|
nexts = [i.get("score") for i in score.nexts_no_outliners(RUNS)]
|
||||||
|
prevs = [i.get("score") for i in score.prevs_no_outliners(RUNS)]
|
||||||
|
if len(nexts) != RUNS:
|
||||||
|
return False
|
||||||
|
if len(prevs) != RUNS:
|
||||||
|
return False
|
||||||
|
avg_nexts = sum(nexts)/len(nexts)
|
||||||
|
avg_prevs = sum(prevs)/len(prevs)
|
||||||
|
|
||||||
|
if abs(avg_nexts - avg_prevs) < score.noise() / tables.NOISE_FACTOR:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def isEmptyRegression(item):
|
||||||
|
score = item.score()
|
||||||
|
if score.prev().get("build").get("cset") == score.get("build").get("cset"):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def isBiModal(item):
|
||||||
|
def divide(li):
|
||||||
|
h = max(li)
|
||||||
|
l = min(li)
|
||||||
|
highs = []
|
||||||
|
lows = []
|
||||||
|
for i in li:
|
||||||
|
if h-i < i-l:
|
||||||
|
highs.append(i)
|
||||||
|
else:
|
||||||
|
lows.append(i)
|
||||||
|
return highs, lows
|
||||||
|
|
||||||
|
|
||||||
|
score = item.score()
|
||||||
|
nexts = [i.get("score") for i in score.nexts(RUNS)]
|
||||||
|
prevs = [i.get("score") for i in score.prevs(RUNS)]
|
||||||
|
nexts_h, nexts_l = divide(nexts)
|
||||||
|
prevs_h, prevs_l = divide(prevs)
|
||||||
|
|
||||||
|
if len(nexts_h) < 4:
|
||||||
|
return False
|
||||||
|
if len(nexts_l) < 4:
|
||||||
|
return False
|
||||||
|
if len(prevs_h) < 4:
|
||||||
|
return False
|
||||||
|
if len(prevs_l) < 4:
|
||||||
|
return False
|
||||||
|
avg_nexts_h = sum(nexts_h)/len(nexts_h)
|
||||||
|
avg_nexts_l = sum(nexts_l)/len(nexts_l)
|
||||||
|
avg_prevs_h = sum(prevs_h)/len(prevs_h)
|
||||||
|
avg_prevs_l = sum(prevs_l)/len(prevs_l)
|
||||||
|
|
||||||
|
if abs(avg_nexts_h - avg_prevs_h) >= score.noise() / tables.NOISE_FACTOR:
|
||||||
|
return False
|
||||||
|
if abs(avg_nexts_l - avg_prevs_l) >= score.noise() / tables.NOISE_FACTOR:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
modes = [14,16,20,21,22,23,25,26,27,28,29,31,32,33,35]
|
||||||
|
for regression in tables.Regression.where({'status':'unconfirmed'}):
|
||||||
|
if regression.get("build").get("mode_id") not in modes:
|
||||||
|
continue
|
||||||
|
|
||||||
|
allRemoved = True
|
||||||
|
for item in regression.regressions():
|
||||||
|
if item.get("noise"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
print "item"
|
||||||
|
|
||||||
|
if isEmptyRegression(item):
|
||||||
|
print "remove", regression.id
|
||||||
|
item.score().dump()
|
||||||
|
item.update({"noise":"1"})
|
||||||
|
continue
|
||||||
|
|
||||||
|
if isOutliner(item):
|
||||||
|
print "remove", regression.id
|
||||||
|
item.score().dump()
|
||||||
|
item.update({"noise":"1"})
|
||||||
|
continue
|
||||||
|
|
||||||
|
if isBiModal(item):
|
||||||
|
print "remove", regression.id
|
||||||
|
item.score().dump()
|
||||||
|
item.update({"noise":"1"})
|
||||||
|
continue
|
||||||
|
|
||||||
|
allRemoved = False
|
||||||
|
|
||||||
|
if allRemoved:
|
||||||
|
print "remove item"
|
||||||
|
regression.update({"status":"noise"})
|
||||||
|
|
||||||
|
awfy.db.commit()
|
|
@ -12,7 +12,7 @@ from optparse import OptionParser
|
||||||
|
|
||||||
parser = OptionParser(usage="usage: %prog [options]")
|
parser = OptionParser(usage="usage: %prog [options]")
|
||||||
parser.add_option( "--dry-run", dest="dryrun", action="store_true", default=False,
|
parser.add_option( "--dry-run", dest="dryrun", action="store_true", default=False,
|
||||||
help="Don't cmomit the new regressions to the database yet.")
|
help="Don't commit the new regressions to the database yet.")
|
||||||
(options, args) = parser.parse_args()
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
def notProcessedRuns():
|
def notProcessedRuns():
|
||||||
|
@ -103,16 +103,30 @@ if __name__ == "__main__":
|
||||||
score.dump()
|
score.dump()
|
||||||
if not options.dryrun:
|
if not options.dryrun:
|
||||||
build = score.get("build_id")
|
build = score.get("build_id")
|
||||||
try:
|
prev_build = score.prev().get("build_id")
|
||||||
id_ = tables.Regression.insert({"build_id": build})
|
regression = [regression for regression in tables.Regression.where({
|
||||||
tables.RegressionStatus.insert({"regression_id": id_, "name": "awfy", "extra": "Submitted", "stamp":"UNIX_TIMESTAMP()"})
|
"build_id": build,
|
||||||
except:
|
"prev_build_id": prev_build
|
||||||
pass
|
})]
|
||||||
|
if len(regression) == 0:
|
||||||
|
regression_id = tables.Regression.insert({
|
||||||
|
"build_id": build,
|
||||||
|
"prev_build_id": prev_build
|
||||||
|
})
|
||||||
|
tables.RegressionStatus.insert({"regression_id": regression_id,
|
||||||
|
"name": "awfy",
|
||||||
|
"extra": "Submitted",
|
||||||
|
"stamp":"UNIX_TIMESTAMP()"})
|
||||||
|
else:
|
||||||
|
regression_id = regression[0].id
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if score.__class__ == tables.Score:
|
if score.__class__ == tables.Score:
|
||||||
tables.RegressionScore.insert({"build_id": build, "score_id": score.get("id")})
|
tables.RegressionScore.insert({"regression_id": regression_id,
|
||||||
|
"score_id": score.get("id")})
|
||||||
elif score.__class__ == tables.Breakdown:
|
elif score.__class__ == tables.Breakdown:
|
||||||
tables.RegressionBreakdown.insert({"build_id": build, "breakdown_id": score.get("id")})
|
tables.RegressionBreakdown.insert({"regression_id": regression_id,
|
||||||
|
"breakdown_id": score.get("id")})
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
except:
|
except:
|
||||||
|
|
|
@ -1,111 +0,0 @@
|
||||||
# vim: set ts=4 sw=4 tw=99 et:
|
|
||||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
|
|
||||||
import awfy
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
import tables_old as tables
|
|
||||||
|
|
||||||
|
|
||||||
def notProcessedRuns():
|
|
||||||
# Only look at reports in the last week
|
|
||||||
newer = int(time.time() - 60 * 60 * 24 * 7)
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("SELECT id \
|
|
||||||
FROM awfy_run \
|
|
||||||
WHERE stamp > "+str(newer)+" AND \
|
|
||||||
status = 1 AND \
|
|
||||||
detector != 1 AND \
|
|
||||||
machine in (28,29)")
|
|
||||||
runs = []
|
|
||||||
for row in c.fetchall():
|
|
||||||
runs.append(tables.Run(row[0]))
|
|
||||||
return runs
|
|
||||||
|
|
||||||
def regressed(score):
|
|
||||||
# Lower than threshold, no regression.
|
|
||||||
change = score.change()
|
|
||||||
if change is None:
|
|
||||||
return None
|
|
||||||
if abs(change) <= score.noise():
|
|
||||||
return False
|
|
||||||
|
|
||||||
#Don't report outliners
|
|
||||||
if score.outliner():
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Don't report if same revision
|
|
||||||
if score.prev() is not None:
|
|
||||||
if score.get('build').get('cset') == score.prev().get('build').get('cset'):
|
|
||||||
return False
|
|
||||||
|
|
||||||
# average change over multiple runs.
|
|
||||||
change = score.avg_change()
|
|
||||||
|
|
||||||
# No change, so wait for more data before reporting.
|
|
||||||
if change is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# Next is not available. Wait for that before reporting.
|
|
||||||
if not score.next():
|
|
||||||
return None
|
|
||||||
if score.next().avg_change() is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# Next has a bigger change. Regression is more likely to be that.
|
|
||||||
if change >= 0 and score.next().avg_change() > change:
|
|
||||||
return False
|
|
||||||
if change <= 0 and score.next().avg_change() < change:
|
|
||||||
return False
|
|
||||||
|
|
||||||
# If there is a prev, test that prev change is smaller
|
|
||||||
if score.prev():
|
|
||||||
if change >= 0 and score.prev().avg_change() >= change:
|
|
||||||
return False
|
|
||||||
if change <= 0 and score.prev().avg_change() <= change:
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
os.environ['TZ'] = "Europe/Amsterdam"
|
|
||||||
time.tzset()
|
|
||||||
|
|
||||||
start = time.time()
|
|
||||||
for run in notProcessedRuns():
|
|
||||||
scores = run.getScoresAndBreakdowns()
|
|
||||||
finish = True
|
|
||||||
print "run:", run.get("id")
|
|
||||||
for score in scores:
|
|
||||||
regressed_ = regressed(score)
|
|
||||||
|
|
||||||
# Not enough info yet
|
|
||||||
if regressed_ is None:
|
|
||||||
finish = False
|
|
||||||
|
|
||||||
if regressed_ is True:
|
|
||||||
score.dump()
|
|
||||||
build = score.get("build_id")
|
|
||||||
try:
|
|
||||||
id_ = tables.Regression.insert({"build_id": build})
|
|
||||||
tables.RegressionStatus.insert({"regression_id": id_, "name": "awfy", "extra": "Submitted", "stamp":"UNIX_TIMESTAMP()"})
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
if score.__class__ == tables.Score:
|
|
||||||
tables.RegressionScore.insert({"build_id": build, "score_id": score.get("id")})
|
|
||||||
elif score.__class__ == tables.Breakdown:
|
|
||||||
tables.RegressionBreakdown.insert({"build_id": build, "breakdown_id": score.get("id")})
|
|
||||||
else:
|
|
||||||
assert False
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
if finish:
|
|
||||||
run.update({"detector": "1"})
|
|
||||||
tables.DBTable.maybeflush()
|
|
||||||
|
|
||||||
awfy.db.commit()
|
|
|
@ -84,6 +84,11 @@ class DBTable:
|
||||||
SET "+",".join(sets)+" \
|
SET "+",".join(sets)+" \
|
||||||
WHERE id = %s", (self.id, ))
|
WHERE id = %s", (self.id, ))
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
c = awfy.db.cursor()
|
||||||
|
c.execute("DELETE FROM "+self.table()+" \
|
||||||
|
WHERE id = %s", (self.id, ))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def valuefy(value):
|
def valuefy(value):
|
||||||
if "'" in str(value):
|
if "'" in str(value):
|
||||||
|
@ -109,6 +114,14 @@ class DBTable:
|
||||||
for row in c.fetchall():
|
for row in c.fetchall():
|
||||||
yield class_(row[0])
|
yield class_(row[0])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def where(class_, data):
|
||||||
|
where = [name+" = "+DBTable.valuefy(data[name]) for name in data]
|
||||||
|
c = awfy.db.cursor()
|
||||||
|
c.execute("SELECT id FROM "+class_.table()+" WHERE "+" AND ".join(where))
|
||||||
|
for row in c.fetchall():
|
||||||
|
yield class_(row[0])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def maybeflush(class_):
|
def maybeflush(class_):
|
||||||
#TODO
|
#TODO
|
||||||
|
@ -211,27 +224,29 @@ class Regression(DBTable):
|
||||||
def __init__(self, id):
|
def __init__(self, id):
|
||||||
DBTable.__init__(self, id)
|
DBTable.__init__(self, id)
|
||||||
|
|
||||||
|
def regressions(self):
|
||||||
|
c = awfy.db.cursor()
|
||||||
|
c.execute("SELECT id FROM awfy_regression_breakdown \
|
||||||
|
WHERE regression_id = %s", (self.id,))
|
||||||
|
for row in c.fetchall():
|
||||||
|
if row[0] == 0:
|
||||||
|
continue
|
||||||
|
yield RegressionBreakdown(row[0])
|
||||||
|
c.execute("SELECT id FROM awfy_regression_score \
|
||||||
|
WHERE regression_id = %s", (self.id,))
|
||||||
|
for row in c.fetchall():
|
||||||
|
if row[0] == 0:
|
||||||
|
continue
|
||||||
|
yield RegressionScore(row[0])
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def table():
|
def table():
|
||||||
return "awfy_regression"
|
return "awfy_regression"
|
||||||
|
|
||||||
class RegressionScore(DBTable):
|
class RegressionScore(DBTable):
|
||||||
def __init__(self, build, score):
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("SELECT id FROM "+self.table()+" \
|
|
||||||
WHERE build_id = %s AND \
|
|
||||||
score_id = %s", (build.get("id"), score.get("id")))
|
|
||||||
row = c.fetchone()
|
|
||||||
id = row[0] if row else 0
|
|
||||||
DBTable.__init__(self, id)
|
|
||||||
|
|
||||||
def regression(self):
|
def score(self):
|
||||||
c = awfy.db.cursor()
|
return self.get("score")
|
||||||
c.execute("SELECT id FROM awfy_regression \
|
|
||||||
WHERE build_id = %s", (self.get("build_id"),))
|
|
||||||
row = c.fetchone()
|
|
||||||
id = row[0] if row else 0
|
|
||||||
return Regression(id)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def table():
|
def table():
|
||||||
|
@ -271,22 +286,9 @@ class RegressionScoreNoise(DBTable):
|
||||||
return "awfy_regression_score_noise"
|
return "awfy_regression_score_noise"
|
||||||
|
|
||||||
class RegressionBreakdown(DBTable):
|
class RegressionBreakdown(DBTable):
|
||||||
def __init__(self, build, breakdown):
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("SELECT id FROM "+self.table()+" \
|
|
||||||
WHERE build_id = %s AND \
|
|
||||||
breakdown_id = %s", (build.get("id"), breakdown.get("id")))
|
|
||||||
row = c.fetchone()
|
|
||||||
id = row[0] if row else 0
|
|
||||||
DBTable.__init__(self, id)
|
|
||||||
|
|
||||||
def regression(self):
|
def score(self):
|
||||||
c = awfy.db.cursor()
|
return self.get("breakdown")
|
||||||
c.execute("SELECT id FROM awfy_regression \
|
|
||||||
WHERE build_id = %s", (self.get("build_id"),))
|
|
||||||
row = c.fetchone()
|
|
||||||
id = row[0] if row else 0
|
|
||||||
return Regression(id)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def table():
|
def table():
|
||||||
|
|
|
@ -1,759 +0,0 @@
|
||||||
# vim: set ts=4 sw=4 tw=99 et:
|
|
||||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
|
|
||||||
import awfy
|
|
||||||
import types
|
|
||||||
|
|
||||||
RUNS_FACTOR = 1
|
|
||||||
NOISE_FACTOR = 3
|
|
||||||
|
|
||||||
def get_class(field):
|
|
||||||
try:
|
|
||||||
identifier = globals()[field]
|
|
||||||
except AttributeError:
|
|
||||||
raise NameError("%s doesn't exist." % field)
|
|
||||||
if isinstance(identifier, (types.ClassType, types.TypeType)):
|
|
||||||
return identifier
|
|
||||||
raise TypeError("%s is not a class." % field)
|
|
||||||
|
|
||||||
def camelcase(string):
|
|
||||||
"""Convert string or unicode from lower-case underscore to camel-case"""
|
|
||||||
splitted_string = string.split('_')
|
|
||||||
# use string's class to work on the string to keep its type
|
|
||||||
class_ = string.__class__
|
|
||||||
return class_.join('', map(class_.capitalize, splitted_string))
|
|
||||||
|
|
||||||
class DBTable:
|
|
||||||
globalcache = {}
|
|
||||||
|
|
||||||
def __init__(self, id):
|
|
||||||
self.id = int(id)
|
|
||||||
self.initialized = False
|
|
||||||
self.cached = None
|
|
||||||
|
|
||||||
def prefetch(self):
|
|
||||||
if self.table() not in self.__class__.globalcache:
|
|
||||||
self.__class__.globalcache[self.table()] = {}
|
|
||||||
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("SELECT * \
|
|
||||||
FROM "+self.table()+" \
|
|
||||||
WHERE id > %s - 100 AND \
|
|
||||||
id < %s + 100 \
|
|
||||||
", (self.id, self.id))
|
|
||||||
for row in c.fetchall():
|
|
||||||
cache = {}
|
|
||||||
for i in range(len(row)):
|
|
||||||
cache[c.description[i][0]] = row[i]
|
|
||||||
self.__class__.globalcache[self.table()][cache["id"]] = cache
|
|
||||||
|
|
||||||
def initialize(self):
|
|
||||||
if self.initialized:
|
|
||||||
return
|
|
||||||
|
|
||||||
self.initialized = True
|
|
||||||
if self.table() in self.__class__.globalcache:
|
|
||||||
if self.id in self.__class__.globalcache[self.table()]:
|
|
||||||
self.cached = self.__class__.globalcache[self.table()][self.id]
|
|
||||||
return
|
|
||||||
|
|
||||||
self.prefetch()
|
|
||||||
self.cached = self.__class__.globalcache[self.table()][self.id]
|
|
||||||
return
|
|
||||||
|
|
||||||
def get(self, field):
|
|
||||||
self.initialize()
|
|
||||||
|
|
||||||
if field in self.cached:
|
|
||||||
return self.cached[field]
|
|
||||||
|
|
||||||
if field+"_id" in self.cached:
|
|
||||||
id_ = self.cached[field+"_id"]
|
|
||||||
class_ = get_class(camelcase(field))
|
|
||||||
value = class_(id_)
|
|
||||||
self.cached[field] = value
|
|
||||||
return self.cached[field]
|
|
||||||
assert False
|
|
||||||
|
|
||||||
def update(self, data):
|
|
||||||
sets = [key + " = " + DBTable.valuefy(data[key]) for key in data]
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("UPDATE "+self.table()+" \
|
|
||||||
SET "+",".join(sets)+" \
|
|
||||||
WHERE id = %s", (self.id, ))
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def valuefy(value):
|
|
||||||
if "'" in str(value):
|
|
||||||
raise TypeError("' is not allowed as value.")
|
|
||||||
if value == "UNIX_TIMESTAMP()":
|
|
||||||
return value
|
|
||||||
else:
|
|
||||||
return "'"+str(value)+"'"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def insert(class_, data):
|
|
||||||
values = [DBTable.valuefy(value) for value in data.values()]
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("INSERT INTO "+class_.table()+" \
|
|
||||||
("+",".join(data.keys())+") \
|
|
||||||
VALUES ("+",".join(values)+")")
|
|
||||||
return c.lastrowid
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def all(class_):
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("SELECT id FROM "+class_.table())
|
|
||||||
for row in c.fetchall():
|
|
||||||
yield class_(row[0])
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def maybeflush(class_):
|
|
||||||
#TODO
|
|
||||||
records = 0
|
|
||||||
for i in class_.globalcache:
|
|
||||||
records += len(class_.globalcache[i].keys())
|
|
||||||
|
|
||||||
class Run(DBTable):
|
|
||||||
def __init__(self, id):
|
|
||||||
DBTable.__init__(self, id)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def table():
|
|
||||||
return "awfy_run"
|
|
||||||
|
|
||||||
def initialize(self):
|
|
||||||
if self.initialized:
|
|
||||||
return
|
|
||||||
DBTable.initialize(self)
|
|
||||||
if "machine_id" not in self.cached:
|
|
||||||
self.cached["machine_id"] = self.cached["machine"]
|
|
||||||
del self.cached["machine"]
|
|
||||||
|
|
||||||
def getScoresAndBreakdowns(self):
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("SELECT id \
|
|
||||||
FROM awfy_build \
|
|
||||||
WHERE run_id = %s", (self.id,))
|
|
||||||
scores = []
|
|
||||||
for row in c.fetchall():
|
|
||||||
scores += Build(row[0]).getScoresAndBreakdowns()
|
|
||||||
return scores
|
|
||||||
|
|
||||||
def getScores(self):
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("SELECT id \
|
|
||||||
FROM awfy_build \
|
|
||||||
WHERE run_id = %s", (self.id,))
|
|
||||||
scores = []
|
|
||||||
for row in c.fetchall():
|
|
||||||
scores += Build(row[0]).getScores()
|
|
||||||
return scores
|
|
||||||
|
|
||||||
def finishStamp(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class SuiteTest(DBTable):
|
|
||||||
def __init__(self, id):
|
|
||||||
DBTable.__init__(self, id)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def table():
|
|
||||||
return "awfy_suite_test"
|
|
||||||
|
|
||||||
class SuiteVersion(DBTable):
|
|
||||||
def __init__(self, id):
|
|
||||||
DBTable.__init__(self, id)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def table():
|
|
||||||
return "awfy_suite_version"
|
|
||||||
|
|
||||||
class Suite(DBTable):
|
|
||||||
def __init__(self, id):
|
|
||||||
DBTable.__init__(self, id)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def table():
|
|
||||||
return "awfy_suite"
|
|
||||||
|
|
||||||
class Machine(DBTable):
|
|
||||||
def __init__(self, id):
|
|
||||||
DBTable.__init__(self, id)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def table():
|
|
||||||
return "awfy_machine"
|
|
||||||
|
|
||||||
class Mode(DBTable):
|
|
||||||
def __init__(self, id):
|
|
||||||
DBTable.__init__(self, id)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def allWith(class_, machine):
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("SELECT distinct(awfy_build.mode_id) \
|
|
||||||
FROM awfy_build \
|
|
||||||
LEFT JOIN awfy_run ON awfy_build.run_id = awfy_run.id \
|
|
||||||
WHERE machine = %s", (machine.get("id"),))
|
|
||||||
for row in c.fetchall():
|
|
||||||
yield Mode(row[0])
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def table():
|
|
||||||
return "awfy_mode"
|
|
||||||
|
|
||||||
class Regression(DBTable):
|
|
||||||
def __init__(self, id):
|
|
||||||
DBTable.__init__(self, id)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def table():
|
|
||||||
return "awfy_regression"
|
|
||||||
|
|
||||||
class RegressionScore(DBTable):
|
|
||||||
def __init__(self, build, score):
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("SELECT id FROM "+self.table()+" \
|
|
||||||
WHERE build_id = %s AND \
|
|
||||||
score_id = %s", (build.get("id"), score.get("id")))
|
|
||||||
row = c.fetchone()
|
|
||||||
id = row[0] if row else 0
|
|
||||||
DBTable.__init__(self, id)
|
|
||||||
|
|
||||||
def regression(self):
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("SELECT id FROM awfy_regression \
|
|
||||||
WHERE build_id = %s", (self.get("build_id"),))
|
|
||||||
row = c.fetchone()
|
|
||||||
id = row[0] if row else 0
|
|
||||||
return Regression(id)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def table():
|
|
||||||
return "awfy_regression_score"
|
|
||||||
|
|
||||||
class RegressionScoreNoise(DBTable):
|
|
||||||
def __init__(self, machine, suite, mode):
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("SELECT id FROM "+self.table()+" \
|
|
||||||
WHERE machine_id = %s AND \
|
|
||||||
mode_id = %s AND \
|
|
||||||
suite_version_id = %s", (machine.get("id"), mode.get("id"), suite.get("id")))
|
|
||||||
row = c.fetchone()
|
|
||||||
id = row[0] if row else 0
|
|
||||||
DBTable.__init__(self, id)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def insertOrUpdate(class_, machine, suite, mode, noise):
|
|
||||||
try:
|
|
||||||
RegressionScoreNoise.insert({
|
|
||||||
"machine_id": machine.get("id"),
|
|
||||||
"suite_version_id": suite.get("id"),
|
|
||||||
"mode_id": mode.get("id"),
|
|
||||||
"noise": noise
|
|
||||||
})
|
|
||||||
except:
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("UPDATE "+class_.table()+" \
|
|
||||||
SET noise = %s \
|
|
||||||
WHERE machine_id = %s AND \
|
|
||||||
mode_id = %s AND \
|
|
||||||
suite_version_id = %s", (noise, machine.get("id"), mode.get("id"),
|
|
||||||
suite.get("id")))
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def table():
|
|
||||||
return "awfy_regression_score_noise"
|
|
||||||
|
|
||||||
class RegressionBreakdown(DBTable):
|
|
||||||
def __init__(self, build, breakdown):
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("SELECT id FROM "+self.table()+" \
|
|
||||||
WHERE build_id = %s AND \
|
|
||||||
breakdown_id = %s", (build.get("id"), breakdown.get("id")))
|
|
||||||
row = c.fetchone()
|
|
||||||
id = row[0] if row else 0
|
|
||||||
DBTable.__init__(self, id)
|
|
||||||
|
|
||||||
def regression(self):
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("SELECT id FROM awfy_regression \
|
|
||||||
WHERE build_id = %s", (self.get("build_id"),))
|
|
||||||
row = c.fetchone()
|
|
||||||
id = row[0] if row else 0
|
|
||||||
return Regression(id)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def table():
|
|
||||||
return "awfy_regression_breakdown"
|
|
||||||
|
|
||||||
class RegressionBreakdownNoise(DBTable):
|
|
||||||
def __init__(self, machine, suite, mode):
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("SELECT id FROM "+self.table()+" \
|
|
||||||
WHERE machine_id = %s AND \
|
|
||||||
mode_id = %s AND \
|
|
||||||
suite_test_id = %s", (machine.get("id"), mode.get("id"), suite.get("id")))
|
|
||||||
row = c.fetchone()
|
|
||||||
id = row[0] if row else 0
|
|
||||||
DBTable.__init__(self, id)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def insertOrUpdate(class_, machine, suite, mode, noise):
|
|
||||||
try:
|
|
||||||
RegressionBreakdownNoise.insert({
|
|
||||||
"machine_id": machine.get("id"),
|
|
||||||
"suite_test_id": suite.get("id"),
|
|
||||||
"mode_id": mode.get("id"),
|
|
||||||
"noise": noise
|
|
||||||
})
|
|
||||||
except:
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("UPDATE "+class_.table()+" \
|
|
||||||
SET noise = %s \
|
|
||||||
WHERE machine_id = %s AND \
|
|
||||||
mode_id = %s AND \
|
|
||||||
suite_test_id = %s", (noise, machine.get("id"), mode.get("id"),
|
|
||||||
suite.get("id")))
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def table():
|
|
||||||
return "awfy_regression_breakdown_noise"
|
|
||||||
|
|
||||||
class RegressionStatus(DBTable):
|
|
||||||
def __init__(self, id):
|
|
||||||
DBTable.__init__(self, id)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def table():
|
|
||||||
return "awfy_regression_status"
|
|
||||||
|
|
||||||
class Build(DBTable):
|
|
||||||
def __init__(self, id):
|
|
||||||
DBTable.__init__(self, id)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def table():
|
|
||||||
return "awfy_build"
|
|
||||||
|
|
||||||
def getScores(self):
|
|
||||||
scores = []
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("SELECT id \
|
|
||||||
FROM awfy_score \
|
|
||||||
WHERE build_id = %s", (self.id,))
|
|
||||||
for row in c.fetchall():
|
|
||||||
scores.append(Score(row[0]))
|
|
||||||
return scores
|
|
||||||
|
|
||||||
def getScoresAndBreakdowns(self):
|
|
||||||
scores = self.getScores()
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("SELECT id \
|
|
||||||
FROM awfy_breakdown \
|
|
||||||
WHERE build_id = %s", (self.id,))
|
|
||||||
for row in c.fetchall():
|
|
||||||
scores.append(Breakdown(row[0]))
|
|
||||||
return scores
|
|
||||||
|
|
||||||
class RegressionTools(DBTable):
|
|
||||||
def __init__(self, id):
|
|
||||||
DBTable.__init__(self, id)
|
|
||||||
|
|
||||||
def outliner(self):
|
|
||||||
if self.next() is None:
|
|
||||||
return False
|
|
||||||
prevs, _ = self.avg_prevs_nexts()
|
|
||||||
_, nexts = self.next().avg_prevs_nexts()
|
|
||||||
if prevs is None or nexts is None:
|
|
||||||
return False
|
|
||||||
if abs(prevs-nexts) <= self.noise():
|
|
||||||
if (abs(self.get('score') - self.prev().get('score')) > self.noise() and
|
|
||||||
abs(self.get('score') - self.next().get('score')) > self.noise()):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def next(self):
|
|
||||||
self.initialize()
|
|
||||||
if "next" not in self.cached:
|
|
||||||
self.cached["next"] = self.compute_next()
|
|
||||||
return self.cached["next"]
|
|
||||||
|
|
||||||
def compute_next(self):
|
|
||||||
nexts = self.prefetch_next(10)
|
|
||||||
|
|
||||||
prev = self
|
|
||||||
prev.cached["next"] = None
|
|
||||||
for score in nexts:
|
|
||||||
prev.initialize()
|
|
||||||
prev.cached["next"] = score
|
|
||||||
score.initialize()
|
|
||||||
score.cached["prev"] = prev
|
|
||||||
prev = score
|
|
||||||
|
|
||||||
return self.cached["next"]
|
|
||||||
|
|
||||||
def prev(self):
|
|
||||||
self.initialize()
|
|
||||||
if "prev" not in self.cached:
|
|
||||||
self.cached["prev"] = self.compute_prev()
|
|
||||||
if self.cached["prev"]:
|
|
||||||
self.cached["prev"].initialize()
|
|
||||||
self.cached["prev"].cached["next"] = self
|
|
||||||
else:
|
|
||||||
pass
|
|
||||||
return self.cached["prev"]
|
|
||||||
|
|
||||||
def compute_prev(self):
|
|
||||||
prevs = self.prefetch_prev(10)
|
|
||||||
|
|
||||||
next_ = self
|
|
||||||
next_.cached["prev"] = None
|
|
||||||
for score in prevs:
|
|
||||||
next_.initialize()
|
|
||||||
next_.cached["prev"] = score
|
|
||||||
score.initialize()
|
|
||||||
score.cached["next"] = next_
|
|
||||||
next_ = score
|
|
||||||
|
|
||||||
return self.cached["prev"]
|
|
||||||
|
|
||||||
def prevs(self, amount):
|
|
||||||
prevs = []
|
|
||||||
point = self
|
|
||||||
while len(prevs) < amount:
|
|
||||||
point = point.prev()
|
|
||||||
if not point:
|
|
||||||
break
|
|
||||||
prevs.append(point)
|
|
||||||
return prevs
|
|
||||||
|
|
||||||
def nexts(self, amount):
|
|
||||||
nexts = []
|
|
||||||
point = self
|
|
||||||
while len(nexts) < amount:
|
|
||||||
point = point.next()
|
|
||||||
if not point:
|
|
||||||
break
|
|
||||||
nexts.append(point)
|
|
||||||
return nexts
|
|
||||||
|
|
||||||
def prevs_no_outliners(self, amount):
|
|
||||||
# note this removes outliners
|
|
||||||
prevs = []
|
|
||||||
point = self
|
|
||||||
while len(prevs) < amount:
|
|
||||||
point = point.prev()
|
|
||||||
if not point:
|
|
||||||
break
|
|
||||||
if point.outliner():
|
|
||||||
continue
|
|
||||||
prevs.append(point)
|
|
||||||
return prevs
|
|
||||||
|
|
||||||
def nexts_no_outliners(self, amount):
|
|
||||||
# note this removes outliners
|
|
||||||
nexts = []
|
|
||||||
point = self
|
|
||||||
while len(nexts) < amount:
|
|
||||||
point = point.next()
|
|
||||||
if not point:
|
|
||||||
break
|
|
||||||
if point.outliner():
|
|
||||||
continue
|
|
||||||
nexts.append(point)
|
|
||||||
return nexts
|
|
||||||
|
|
||||||
def avg_prevs_no_outliners(self):
|
|
||||||
avg_prevs, _ = self.avg_prevs_nexts_no_outliners()
|
|
||||||
return avg_prevs
|
|
||||||
|
|
||||||
def avg_nexts_no_outliners(self):
|
|
||||||
_, avg_nexts = self.avg_prevs_nexts_no_outliners()
|
|
||||||
return avg_nexts
|
|
||||||
|
|
||||||
def avg_prevs_nexts_no_outliners(self):
|
|
||||||
self.initialize()
|
|
||||||
if "avg_prevs_no_outliners" not in self.cached:
|
|
||||||
self.cached["avg_prevs_no_outliners"], self.cached["avg_nexts_no_outliners"] = self.compute_avg_prevs_nexts_no_outliners()
|
|
||||||
return self.cached["avg_prevs_no_outliners"], self.cached["avg_nexts_no_outliners"]
|
|
||||||
|
|
||||||
def avg_prevs_nexts(self):
|
|
||||||
self.initialize()
|
|
||||||
if "avg_prevs" not in self.cached:
|
|
||||||
self.cached["avg_prevs"], self.cached["avg_nexts"] = self.compute_avg_prevs_nexts()
|
|
||||||
return self.cached["avg_prevs"], self.cached["avg_nexts"]
|
|
||||||
|
|
||||||
def compute_avg_prevs_nexts_no_outliners(self):
|
|
||||||
"Compute the change in runs before and after the current run"
|
|
||||||
# How many runs do we need to test?
|
|
||||||
runs = self.runs()
|
|
||||||
|
|
||||||
# Get scores before and after this run.
|
|
||||||
prevs = [i.get('score') for i in self.prevs_no_outliners(runs)]
|
|
||||||
nexts = [self.get('score')] + [i.get('score') for i in self.nexts_no_outliners(runs - 1)]
|
|
||||||
|
|
||||||
p_weight = [len(prevs)-i for i in range(len(prevs))]
|
|
||||||
n_weight = [len(nexts)-i for i in range(len(nexts))]
|
|
||||||
prevs = [prevs[i]*p_weight[i] for i in range(len(prevs))]
|
|
||||||
nexts = [nexts[i]*n_weight[i] for i in range(len(nexts))]
|
|
||||||
|
|
||||||
# Not enough data to compute change.
|
|
||||||
if len(nexts) != runs:
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
avg_prevs = sum(prevs)
|
|
||||||
avg_nexts = sum(nexts)
|
|
||||||
|
|
||||||
# Handle edge cases.
|
|
||||||
if avg_prevs != 0:
|
|
||||||
avg_prevs /= sum(p_weight)
|
|
||||||
if avg_nexts != 0:
|
|
||||||
avg_nexts /= sum(n_weight)
|
|
||||||
|
|
||||||
return avg_prevs, avg_nexts
|
|
||||||
|
|
||||||
def compute_avg_prevs_nexts(self):
|
|
||||||
"Compute the change in runs before and after the current run"
|
|
||||||
# How many runs do we need to test?
|
|
||||||
runs = self.runs()
|
|
||||||
|
|
||||||
# Get scores before and after this run.
|
|
||||||
prevs = [i.get('score') for i in self.prevs(runs)]
|
|
||||||
nexts = [self.get('score')] + [i.get('score') for i in self.nexts(runs - 1)]
|
|
||||||
|
|
||||||
p_weight = [len(prevs)-i for i in range(len(prevs))]
|
|
||||||
n_weight = [len(nexts)-i for i in range(len(nexts))]
|
|
||||||
prevs = [prevs[i]*p_weight[i] for i in range(len(prevs))]
|
|
||||||
nexts = [nexts[i]*n_weight[i] for i in range(len(nexts))]
|
|
||||||
|
|
||||||
# Not enough data to compute change.
|
|
||||||
if len(nexts) != runs:
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
avg_prevs = sum(prevs)
|
|
||||||
avg_nexts = sum(nexts)
|
|
||||||
|
|
||||||
# Handle edge cases.
|
|
||||||
if avg_prevs != 0:
|
|
||||||
avg_prevs /= sum(p_weight)
|
|
||||||
if avg_nexts != 0:
|
|
||||||
avg_nexts /= sum(n_weight)
|
|
||||||
|
|
||||||
return avg_prevs, avg_nexts
|
|
||||||
|
|
||||||
def change(self):
|
|
||||||
prevs, nexts = self.avg_prevs_nexts_no_outliners()
|
|
||||||
if not prevs or not nexts:
|
|
||||||
return None
|
|
||||||
|
|
||||||
return abs(prevs - nexts)
|
|
||||||
|
|
||||||
def avg_change(self):
|
|
||||||
prevs, nexts = self.avg_prevs_nexts_no_outliners()
|
|
||||||
if not prevs or not nexts:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if prevs == 0:
|
|
||||||
return float("inf")
|
|
||||||
|
|
||||||
change = (prevs - nexts) / (prevs)
|
|
||||||
return change
|
|
||||||
|
|
||||||
|
|
||||||
class Score(RegressionTools):
|
|
||||||
def __init__(self, id):
|
|
||||||
RegressionTools.__init__(self, id)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def table():
|
|
||||||
return "awfy_score"
|
|
||||||
|
|
||||||
def prefetch_next(self, limit = 1):
|
|
||||||
stamp = self.get("build").get("run").get("stamp")
|
|
||||||
machine = self.get("build").get("run").get("machine_id")
|
|
||||||
mode = self.get("build").get("mode_id")
|
|
||||||
suite = self.get("suite_version_id")
|
|
||||||
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("SELECT awfy_score.id \
|
|
||||||
FROM awfy_score \
|
|
||||||
INNER JOIN awfy_build ON awfy_build.id = awfy_score.build_id \
|
|
||||||
INNER JOIN awfy_run ON awfy_run.id = awfy_build.run_id \
|
|
||||||
WHERE stamp > %s AND \
|
|
||||||
machine = %s AND \
|
|
||||||
mode_id = %s AND \
|
|
||||||
suite_version_id = %s AND \
|
|
||||||
status = 1 \
|
|
||||||
ORDER BY stamp ASC \
|
|
||||||
LIMIT "+str(limit), (stamp, machine, mode, suite))
|
|
||||||
rows = c.fetchall()
|
|
||||||
return [Score(row[0]) for row in rows]
|
|
||||||
|
|
||||||
def prefetch_prev(self, limit = 1):
|
|
||||||
stamp = self.get("build").get("run").get("stamp")
|
|
||||||
machine = self.get("build").get("run").get("machine_id")
|
|
||||||
mode = self.get("build").get("mode_id")
|
|
||||||
suite = self.get("suite_version_id")
|
|
||||||
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("SELECT awfy_score.id \
|
|
||||||
FROM awfy_score \
|
|
||||||
INNER JOIN awfy_build ON awfy_build.id = awfy_score.build_id \
|
|
||||||
INNER JOIN awfy_run ON awfy_run.id = awfy_build.run_id \
|
|
||||||
WHERE stamp < %s AND \
|
|
||||||
machine = %s AND \
|
|
||||||
mode_id = %s AND \
|
|
||||||
suite_version_id = %s AND \
|
|
||||||
status = 1 \
|
|
||||||
ORDER BY stamp DESC \
|
|
||||||
LIMIT 1", (stamp, machine, mode, suite))
|
|
||||||
rows = c.fetchall()
|
|
||||||
return [Score(row[0]) for row in rows]
|
|
||||||
|
|
||||||
def runs(self):
|
|
||||||
runs = max(1, self.get('build').get('run').get('machine').get("confidence_runs"))
|
|
||||||
runs *= self.get('suite_version').get('suite').get("confidence_factor")
|
|
||||||
runs *= RUNS_FACTOR
|
|
||||||
runs = int(round(runs))
|
|
||||||
return runs
|
|
||||||
|
|
||||||
def noise(self):
|
|
||||||
noise = RegressionScoreNoise(self.get('build').get('run').get('machine'),
|
|
||||||
self.get('suite_version'),
|
|
||||||
self.get('build').get('mode')).get('noise')
|
|
||||||
return NOISE_FACTOR*noise
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def first(class_, machine, suite, mode):
|
|
||||||
assert machine.__class__ == Machine
|
|
||||||
assert suite.__class__ == SuiteVersion
|
|
||||||
assert mode.__class__ == Mode
|
|
||||||
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("SELECT awfy_score.id \
|
|
||||||
FROM awfy_score \
|
|
||||||
INNER JOIN awfy_build ON awfy_build.id = awfy_score.build_id \
|
|
||||||
INNER JOIN awfy_run ON awfy_run.id = awfy_build.run_id \
|
|
||||||
WHERE machine = %s AND \
|
|
||||||
mode_id = %s AND \
|
|
||||||
suite_version_id = %s AND \
|
|
||||||
status = 1 \
|
|
||||||
ORDER BY stamp ASC \
|
|
||||||
LIMIT 1", (machine.get("id"), mode.get("id"), suite.get("id")))
|
|
||||||
row = c.fetchone()
|
|
||||||
if row:
|
|
||||||
return Score(row[0])
|
|
||||||
return None
|
|
||||||
|
|
||||||
def dump(self):
|
|
||||||
if self.get("build").get("mode").get("name") != "Ion":
|
|
||||||
return
|
|
||||||
import datetime
|
|
||||||
print datetime.datetime.fromtimestamp(
|
|
||||||
int(self.get("build").get("run").get("stamp"))
|
|
||||||
).strftime('%Y-%m-%d %H:%M:%S'),
|
|
||||||
print "", self.get("build").get("run").get("machine").get("description"),
|
|
||||||
print "", self.get("build").get("mode").get("name"),
|
|
||||||
print "", self.get("suite_version").get("name")+":", self.avg_change(),
|
|
||||||
print "", self.prev().get("score") if self.prev() else "", self.get("score"),
|
|
||||||
print " ("+str(self.runs())+" runs, "+str(self.noise())+")"
|
|
||||||
|
|
||||||
class Breakdown(RegressionTools):
|
|
||||||
def __init__(self, id):
|
|
||||||
RegressionTools.__init__(self, id)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def table():
|
|
||||||
return "awfy_breakdown"
|
|
||||||
|
|
||||||
def prefetch_next(self, limit = 1):
|
|
||||||
stamp = self.get("build").get("run").get("stamp")
|
|
||||||
machine = self.get("build").get("run").get("machine_id")
|
|
||||||
mode = self.get("build").get("mode_id")
|
|
||||||
suite = self.get("suite_test_id")
|
|
||||||
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("SELECT awfy_breakdown.id \
|
|
||||||
FROM awfy_breakdown \
|
|
||||||
INNER JOIN awfy_build ON awfy_build.id = awfy_breakdown.build_id \
|
|
||||||
INNER JOIN awfy_run ON awfy_run.id = awfy_build.run_id \
|
|
||||||
WHERE stamp > %s AND \
|
|
||||||
machine = %s AND \
|
|
||||||
mode_id = %s AND \
|
|
||||||
suite_test_id = %s AND \
|
|
||||||
status = 1 \
|
|
||||||
ORDER BY stamp ASC \
|
|
||||||
LIMIT "+str(limit), (stamp, machine, mode, suite))
|
|
||||||
rows = c.fetchall()
|
|
||||||
return [Breakdown(row[0]) for row in rows]
|
|
||||||
|
|
||||||
def prefetch_prev(self, limit = 1):
|
|
||||||
stamp = self.get("build").get("run").get("stamp")
|
|
||||||
machine = self.get("build").get("run").get("machine_id")
|
|
||||||
mode = self.get("build").get("mode_id")
|
|
||||||
suite = self.get("suite_test_id")
|
|
||||||
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("SELECT awfy_breakdown.id \
|
|
||||||
FROM awfy_breakdown \
|
|
||||||
INNER JOIN awfy_build ON awfy_build.id = awfy_breakdown.build_id \
|
|
||||||
INNER JOIN awfy_run ON awfy_run.id = awfy_build.run_id \
|
|
||||||
WHERE stamp < %s AND \
|
|
||||||
machine = %s AND \
|
|
||||||
mode_id = %s AND \
|
|
||||||
suite_test_id = %s AND \
|
|
||||||
status = 1 \
|
|
||||||
ORDER BY stamp DESC \
|
|
||||||
LIMIT "+str(limit), (stamp, machine, mode, suite))
|
|
||||||
rows = c.fetchall()
|
|
||||||
return [Breakdown(row[0]) for row in rows]
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def first(class_, machine, suite, mode):
|
|
||||||
assert machine.__class__ == Machine
|
|
||||||
assert suite.__class__ == SuiteTest
|
|
||||||
assert mode.__class__ == Mode
|
|
||||||
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
c.execute("SELECT awfy_breakdown.id \
|
|
||||||
FROM awfy_breakdown \
|
|
||||||
INNER JOIN awfy_build ON awfy_build.id = awfy_breakdown.build_id \
|
|
||||||
INNER JOIN awfy_run ON awfy_run.id = awfy_build.run_id \
|
|
||||||
WHERE machine = %s AND \
|
|
||||||
mode_id = %s AND \
|
|
||||||
suite_test_id = %s AND \
|
|
||||||
status = 1 \
|
|
||||||
ORDER BY stamp ASC \
|
|
||||||
LIMIT 1", (machine.get("id"), mode.get("id"), suite.get("id")))
|
|
||||||
row = c.fetchone()
|
|
||||||
if row:
|
|
||||||
return Breakdown(row[0])
|
|
||||||
return None
|
|
||||||
|
|
||||||
def runs(self):
|
|
||||||
runs = max(1, self.get('build').get('run').get('machine').get("confidence_runs"))
|
|
||||||
runs *= self.get('suite_test').get("confidence_factor")
|
|
||||||
runs *= RUNS_FACTOR
|
|
||||||
runs = int(round(runs))
|
|
||||||
return runs
|
|
||||||
|
|
||||||
def noise(self):
|
|
||||||
noise = RegressionBreakdownNoise(self.get('build').get('run').get('machine'),
|
|
||||||
self.get('suite_test'),
|
|
||||||
self.get('build').get('mode')).get('noise')
|
|
||||||
return NOISE_FACTOR*noise
|
|
||||||
|
|
||||||
def dump(self):
|
|
||||||
import datetime
|
|
||||||
print datetime.datetime.fromtimestamp(
|
|
||||||
int(self.get("build").get("run").get("stamp"))
|
|
||||||
).strftime('%Y-%m-%d %H:%M:%S'),
|
|
||||||
#print "", self.get("build").get("run").get("machine").get("description"),
|
|
||||||
print "", self.get("build").get("mode").get("name"),
|
|
||||||
print "", self.get("suite_test").get("suite_version").get("name")+":", self.get("suite_test").get("name")+":", self.avg_change(),
|
|
||||||
print "", self.prev().get("score") if self.prev() else "", self.get("score"),
|
|
||||||
print " ("+str(self.runs())+" runs, "+str(self.noise())+", "+str(self.change())+")"
|
|
|
@ -1,108 +0,0 @@
|
||||||
# vim: set ts=4 sw=4 tw=99 et:
|
|
||||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
|
|
||||||
import awfy
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
import tables
|
|
||||||
import tables_old
|
|
||||||
import regression_detector
|
|
||||||
import regression_detector_old
|
|
||||||
from collections import defaultdict
|
|
||||||
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
import datetime
|
|
||||||
os.environ['TZ'] = "Europe/Amsterdam"
|
|
||||||
time.tzset()
|
|
||||||
|
|
||||||
def testRuns():
|
|
||||||
c = awfy.db.cursor()
|
|
||||||
newer = int(time.time() - 60 * 60 * 24 * 30)
|
|
||||||
older = int(time.time() - 60 * 60 * 24 * 1)
|
|
||||||
c.execute("SELECT id \
|
|
||||||
FROM awfy_run \
|
|
||||||
WHERE stamp > "+str(newer)+" AND \
|
|
||||||
stamp < "+str(older)+" AND \
|
|
||||||
status = 1 AND \
|
|
||||||
detector = 1 AND \
|
|
||||||
machine in (28, 29)")
|
|
||||||
runs = []
|
|
||||||
for row in c.fetchall():
|
|
||||||
runs.append(tables.Run(row[0]))
|
|
||||||
return runs
|
|
||||||
|
|
||||||
|
|
||||||
changes = defaultdict(int)
|
|
||||||
for run in testRuns():
|
|
||||||
scores = run.getScoresAndBreakdowns()
|
|
||||||
for score in scores:
|
|
||||||
if score.get("build").get("mode").get("name") != "Ion":
|
|
||||||
continue
|
|
||||||
|
|
||||||
if score.__class__ == tables.Score:
|
|
||||||
regression = tables.RegressionScore(score.get("build"), score)
|
|
||||||
score_old = tables_old.Score(score.id)
|
|
||||||
elif score.__class__ == tables.Breakdown:
|
|
||||||
regression = tables.RegressionBreakdown(score.get("build"), score)
|
|
||||||
score_old = tables_old.Breakdown(score.id)
|
|
||||||
|
|
||||||
status_db = "noregression"
|
|
||||||
if regression.id != 0:
|
|
||||||
if regression.get("noise") == 1:
|
|
||||||
status_db = "marked noregression"
|
|
||||||
elif regression.regression().get('status') == "noise":
|
|
||||||
status_db = "marked noregression"
|
|
||||||
elif regression.regression().get('status') == "unconfirmed":
|
|
||||||
status_db = "unconfirmed"
|
|
||||||
else:
|
|
||||||
status_db = "regressed"
|
|
||||||
|
|
||||||
status_old = "noregression"
|
|
||||||
regressed_ = regression_detector_old.regressed(score_old)
|
|
||||||
if regressed_ is None:
|
|
||||||
status_old = "nodata"
|
|
||||||
elif regressed_:
|
|
||||||
status_old = "regressed"
|
|
||||||
|
|
||||||
status_now = "noregression"
|
|
||||||
regressed_ = regression_detector.regressed(score)
|
|
||||||
if regressed_ is None:
|
|
||||||
status_now = "nodata"
|
|
||||||
elif regressed_:
|
|
||||||
status_now = "regressed"
|
|
||||||
|
|
||||||
key = status_db+"-"+status_now
|
|
||||||
changes["db_"+status_db] += 1
|
|
||||||
changes["now_"+status_now] += 1
|
|
||||||
changes["old_"+status_old] += 1
|
|
||||||
changes[key] += 1
|
|
||||||
|
|
||||||
if key == "regressed-noregression" or key == "noregression-regressed" or status_now == "regressed":
|
|
||||||
print datetime.datetime.fromtimestamp(
|
|
||||||
int(score.get("build").get("run").get("stamp"))
|
|
||||||
).strftime('%Y-%m-%d %H:%M:%S'),
|
|
||||||
if regression.id == 0:
|
|
||||||
print 0,
|
|
||||||
else:
|
|
||||||
print regression.regression().id,
|
|
||||||
print score.get("build").get("run").get("machine_id"),
|
|
||||||
print score.get("build").get("mode").get("name"),
|
|
||||||
print score.change(),
|
|
||||||
print score.noise(),
|
|
||||||
print score.avg_change(),
|
|
||||||
if score.__class__ == tables.Score:
|
|
||||||
print score.get("suite_version").get("name"),
|
|
||||||
else:
|
|
||||||
print score.get("suite_test").get("name"),
|
|
||||||
print key
|
|
||||||
|
|
||||||
print "Lost detections!:", changes["regressed-noregression"]
|
|
||||||
print "Over active detection: ", changes["noregression-regressed"]
|
|
||||||
print "% less detections: ", 1.0*int(changes["marked noregression-noregression"])/(int(changes["marked noregression-regressed"])+int(changes["marked noregression-noregression"]))
|
|
||||||
|
|
||||||
print "Db regressions: ", int(changes["db_marked noregression"]) + int(changes["db_regressed"]) + int(changes["db_unconfirmed"])
|
|
||||||
print "Old regressions: ", int(changes["old_regressed"])
|
|
||||||
print "Now regressions: ", int(changes["now_regressed"])
|
|
|
@ -20,7 +20,6 @@ AWFY.lastHash = null;
|
||||||
AWFY.lastRefresh = 0;
|
AWFY.lastRefresh = 0;
|
||||||
|
|
||||||
// Hide a view modes by default. Since they aren't active anymore
|
// Hide a view modes by default. Since they aren't active anymore
|
||||||
//AWFYMaster.modes["30"].hidden = true
|
|
||||||
AWFYMaster.modes["35"].hidden = true
|
AWFYMaster.modes["35"].hidden = true
|
||||||
AWFYMaster.modes["27"].hidden = true
|
AWFYMaster.modes["27"].hidden = true
|
||||||
AWFYMaster.modes["29"].hidden = true
|
AWFYMaster.modes["29"].hidden = true
|
||||||
|
|
|
@ -13,13 +13,13 @@ if ($subtest) {
|
||||||
$query = mysql_query("SELECT awfy_regression.id, noise, status
|
$query = mysql_query("SELECT awfy_regression.id, noise, status
|
||||||
FROM `awfy_regression_breakdown`
|
FROM `awfy_regression_breakdown`
|
||||||
LEFT JOIN awfy_regression
|
LEFT JOIN awfy_regression
|
||||||
ON awfy_regression.build_id = awfy_regression_breakdown.build_id
|
ON awfy_regression.id = awfy_regression_breakdown.regression_id
|
||||||
WHERE breakdown_id = ".$id);
|
WHERE breakdown_id = ".$id);
|
||||||
} else {
|
} else {
|
||||||
$query = mysql_query("SELECT awfy_regression.id, noise, status
|
$query = mysql_query("SELECT awfy_regression.id, noise, status
|
||||||
FROM `awfy_regression_score`
|
FROM `awfy_regression_score`
|
||||||
LEFT JOIN awfy_regression
|
LEFT JOIN awfy_regression
|
||||||
ON awfy_regression.build_id = awfy_regression_score.build_id
|
ON awfy_regression.id = awfy_regression_score.regression_id
|
||||||
WHERE breakdown_id = ".$id);
|
WHERE breakdown_id = ".$id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -143,6 +143,21 @@
|
||||||
ga('send', 'pageview');
|
ga('send', 'pageview');
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
<!-- Piwik -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var _paq = _paq || [];
|
||||||
|
_paq.push(['trackPageView']);
|
||||||
|
_paq.push(['enableLinkTracking']);
|
||||||
|
(function() {
|
||||||
|
var u="//arewefastyet.com/piwik/";
|
||||||
|
_paq.push(['setTrackerUrl', u+'piwik.php']);
|
||||||
|
_paq.push(['setSiteId', 1]);
|
||||||
|
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
||||||
|
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<noscript><p><img src="//arewefastyet.com/piwik/piwik.php?idsite=1" style="border:0;" alt="" /></p></noscript>
|
||||||
|
<!-- End Piwik Code -->
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,8 @@ session_start();
|
||||||
|
|
||||||
function init_database()
|
function init_database()
|
||||||
{
|
{
|
||||||
mysql_connect("localhost", "***", "***") or die("ERROR: " . mysql_error());
|
mysql_connect("localhost", "awfy", "LFQZdX6Ca57QcwhE") or die("ERROR: " . mysql_error());
|
||||||
mysql_select_db("dvander") or die("ERROR: " . mysql_error());
|
mysql_select_db("awfy") or die("ERROR: " . mysql_error());
|
||||||
}
|
}
|
||||||
|
|
||||||
function username()
|
function username()
|
||||||
|
|
|
@ -47,6 +47,21 @@
|
||||||
ga('send', 'pageview');
|
ga('send', 'pageview');
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
<!-- Piwik -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var _paq = _paq || [];
|
||||||
|
_paq.push(['trackPageView']);
|
||||||
|
_paq.push(['enableLinkTracking']);
|
||||||
|
(function() {
|
||||||
|
var u="//arewefastyet.com/piwik/";
|
||||||
|
_paq.push(['setTrackerUrl', u+'piwik.php']);
|
||||||
|
_paq.push(['setSiteId', 1]);
|
||||||
|
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
||||||
|
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<noscript><p><img src="//arewefastyet.com/piwik/piwik.php?idsite=1" style="border:0;" alt="" /></p></noscript>
|
||||||
|
<!-- End Piwik Code -->
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -13,13 +13,13 @@ if (!has_permissions())
|
||||||
$postdata = file_get_contents("php://input");
|
$postdata = file_get_contents("php://input");
|
||||||
$request = json_decode($postdata);
|
$request = json_decode($postdata);
|
||||||
|
|
||||||
$build_id = (int)$request->build_id;
|
$regression_id = (int)$request->regression_id;
|
||||||
|
|
||||||
foreach($request->noise->score as $score_id => $noise) {
|
foreach($request->noise->score as $score_id => $noise) {
|
||||||
$noise = (int)$noise;
|
$noise = (int)$noise;
|
||||||
$score_id = (int)$score_id;
|
$score_id = (int)$score_id;
|
||||||
$query = mysql_query("UPDATE awfy_regression_score SET noise = $noise
|
$query = mysql_query("UPDATE awfy_regression_score SET noise = $noise
|
||||||
WHERE build_id = $build_id AND
|
WHERE regression_id = $regression_id AND
|
||||||
score_id = $score_id
|
score_id = $score_id
|
||||||
") or die(mysql_error());
|
") or die(mysql_error());
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ foreach($request->noise->breakdown as $score_id => $noise) {
|
||||||
$noise = (int)$noise;
|
$noise = (int)$noise;
|
||||||
$score_id = (int)$score_id;
|
$score_id = (int)$score_id;
|
||||||
$query = mysql_query("UPDATE awfy_regression_breakdown SET noise = $noise
|
$query = mysql_query("UPDATE awfy_regression_breakdown SET noise = $noise
|
||||||
WHERE build_id = $build_id AND
|
WHERE regression_id = $regression_id AND
|
||||||
breakdown_id = $score_id
|
breakdown_id = $score_id
|
||||||
") or die(mysql_error());
|
") or die(mysql_error());
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ init_database();
|
||||||
|
|
||||||
$amount = Array();
|
$amount = Array();
|
||||||
|
|
||||||
$query = mysql_query("SELECT build_id FROM awfy_regression
|
$query = mysql_query("SELECT awfy_regression.id, build_id FROM awfy_regression
|
||||||
INNER JOIN awfy_build ON awfy_build.id = build_id
|
INNER JOIN awfy_build ON awfy_build.id = build_id
|
||||||
WHERE (mode_id = 14 OR
|
WHERE (mode_id = 14 OR
|
||||||
mode_id = 28 or
|
mode_id = 28 or
|
||||||
|
@ -20,10 +20,10 @@ $query = mysql_query("SELECT build_id FROM awfy_regression
|
||||||
status != 'fixed' AND status != 'improvement'");
|
status != 'fixed' AND status != 'improvement'");
|
||||||
while ($regs = mysql_fetch_object($query)) {
|
while ($regs = mysql_fetch_object($query)) {
|
||||||
$qScore = mysql_query("SELECT count(*) as count FROM awfy_regression_score
|
$qScore = mysql_query("SELECT count(*) as count FROM awfy_regression_score
|
||||||
WHERE build_id = ".$regs->build_id);
|
WHERE regression_id = ".$regs->id);
|
||||||
$score = mysql_fetch_object($qScore);
|
$score = mysql_fetch_object($qScore);
|
||||||
$qBreakdown = mysql_query("SELECT count(*) as count FROM awfy_regression_breakdown
|
$qBreakdown = mysql_query("SELECT count(*) as count FROM awfy_regression_breakdown
|
||||||
WHERE build_id = ".$regs->build_id);
|
WHERE regression_id = ".$regs->id);
|
||||||
$breakdown = mysql_fetch_object($qBreakdown);
|
$breakdown = mysql_fetch_object($qBreakdown);
|
||||||
$qDate = mysql_query("SELECT stamp FROM awfy_build
|
$qDate = mysql_query("SELECT stamp FROM awfy_build
|
||||||
LEFT JOIN awfy_run ON awfy_run.id = awfy_build.run_id
|
LEFT JOIN awfy_run ON awfy_run.id = awfy_build.run_id
|
||||||
|
|
|
@ -45,7 +45,7 @@ for ($i=0; $i < count($ids); $i++) {
|
||||||
"scores" => array()
|
"scores" => array()
|
||||||
);
|
);
|
||||||
$qScores = mysql_query("SELECT * FROM awfy_regression_score
|
$qScores = mysql_query("SELECT * FROM awfy_regression_score
|
||||||
WHERE build_id = '".$output["build_id"]."'") or die(mysql_error());
|
WHERE regression_id = '".$output["id"]."'") or die(mysql_error());
|
||||||
while ($scores = mysql_fetch_assoc($qScores)) {
|
while ($scores = mysql_fetch_assoc($qScores)) {
|
||||||
$suite_version_id = get("score", $scores["score_id"], "suite_version_id");
|
$suite_version_id = get("score", $scores["score_id"], "suite_version_id");
|
||||||
$score = array(
|
$score = array(
|
||||||
|
@ -67,7 +67,7 @@ for ($i=0; $i < count($ids); $i++) {
|
||||||
$regression["scores"][] = $score;
|
$regression["scores"][] = $score;
|
||||||
}
|
}
|
||||||
$qScores = mysql_query("SELECT * FROM awfy_regression_breakdown
|
$qScores = mysql_query("SELECT * FROM awfy_regression_breakdown
|
||||||
WHERE build_id = '".$output["build_id"]."'") or die(mysql_error());
|
WHERE regression_id = '".$output["id"]."'") or die(mysql_error());
|
||||||
while ($scores = mysql_fetch_assoc($qScores)) {
|
while ($scores = mysql_fetch_assoc($qScores)) {
|
||||||
$suite_test_id = get("breakdown", $scores["breakdown_id"], "suite_test_id");
|
$suite_test_id = get("breakdown", $scores["breakdown_id"], "suite_test_id");
|
||||||
$suite_version_id = get("suite_test", $suite_test_id, "suite_version_id");
|
$suite_version_id = get("suite_test", $suite_test_id, "suite_version_id");
|
||||||
|
|
|
@ -19,8 +19,9 @@ $modes = join(",", $request->modes);
|
||||||
for ($i=0; $i < count($request->states); $i++)
|
for ($i=0; $i < count($request->states); $i++)
|
||||||
$request->states[$i] = "'".mysql_real_escape_string($request->states[$i])."'";
|
$request->states[$i] = "'".mysql_real_escape_string($request->states[$i])."'";
|
||||||
$states = join(",", $request->states);
|
$states = join(",", $request->states);
|
||||||
$bug = (int)$request->bug;
|
$bug = null;
|
||||||
|
if (isset($request->bug) && $request->bug !== "")
|
||||||
|
$bug = (int)$request->bug;
|
||||||
|
|
||||||
#TODO
|
#TODO
|
||||||
date_default_timezone_set("Europe/Brussels");
|
date_default_timezone_set("Europe/Brussels");
|
||||||
|
@ -34,6 +35,8 @@ if (!empty($states))
|
||||||
$where[] = "awfy_regression.status in ($states)";
|
$where[] = "awfy_regression.status in ($states)";
|
||||||
if (!empty($bug))
|
if (!empty($bug))
|
||||||
$where[] = "awfy_regression.bug = $bug";
|
$where[] = "awfy_regression.bug = $bug";
|
||||||
|
if ($bug === 0)
|
||||||
|
$where[] = "awfy_regression.bug = ''";
|
||||||
|
|
||||||
$query = mysql_query("SELECT awfy_regression.id, machine, mode_id, awfy_run.stamp, build_id, cset, bug
|
$query = mysql_query("SELECT awfy_regression.id, machine, mode_id, awfy_run.stamp, build_id, cset, bug
|
||||||
FROM awfy_regression
|
FROM awfy_regression
|
||||||
|
|
|
@ -14,29 +14,10 @@ $request->id = (int) $request->id;
|
||||||
if (!isset($request->subtest))
|
if (!isset($request->subtest))
|
||||||
$request->subtest = false;
|
$request->subtest = false;
|
||||||
|
|
||||||
if ($request->subtest == 1 || $request->subtest == 'true') {
|
if ($request->subtest == 1 || $request->subtest == 'true')
|
||||||
$build_id = get("breakdown", $request->id, "build_id");
|
$build_id = get("breakdown", $request->id, "build_id");
|
||||||
$suite_test_id = get("breakdown", $request->id, "suite_test_id");
|
else
|
||||||
$suite = get("suite_test", $suite_test_id, "name");
|
|
||||||
|
|
||||||
$query = mysql_query("SELECT id FROM awfy_regression_breakdown
|
|
||||||
WHERE breakdown_id = ".$request->id);
|
|
||||||
if (mysql_num_rows($query) == 0) {
|
|
||||||
mysql_query("INSERT INTO awfy_regression_breakdown
|
|
||||||
(build_id, breakdown_id) VALUES (".$build_id.",".$request->id.")");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$build_id = get("score", $request->id, "build_id");
|
$build_id = get("score", $request->id, "build_id");
|
||||||
$suite_version_id = get("score", $request->id, "suite_version_id");
|
|
||||||
$suite = get("suite_version", $suite_version_id, "name");
|
|
||||||
|
|
||||||
$query = mysql_query("SELECT id FROM awfy_regression_score
|
|
||||||
WHERE score_id = ".$request->id);
|
|
||||||
if (mysql_num_rows($query) == 0) {
|
|
||||||
mysql_query("INSERT INTO awfy_regression_score
|
|
||||||
(build_id, score_id) VALUES (".$build_id.",".$request->id.")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$query = mysql_query("SELECT id FROM awfy_regression
|
$query = mysql_query("SELECT id FROM awfy_regression
|
||||||
WHERE build_id = ".$build_id);
|
WHERE build_id = ".$build_id);
|
||||||
|
@ -49,6 +30,28 @@ if (mysql_num_rows($query) == 0) {
|
||||||
$regression_id = $data["id"];
|
$regression_id = $data["id"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($request->subtest == 1 || $request->subtest == 'true') {
|
||||||
|
$suite_test_id = get("breakdown", $request->id, "suite_test_id");
|
||||||
|
$suite = get("suite_test", $suite_test_id, "name");
|
||||||
|
|
||||||
|
$query = mysql_query("SELECT id FROM awfy_regression_breakdown
|
||||||
|
WHERE breakdown_id = ".$request->id);
|
||||||
|
if (mysql_num_rows($query) == 0) {
|
||||||
|
mysql_query("INSERT INTO awfy_regression_breakdown
|
||||||
|
(regression_id, breakdown_id) VALUES (".$regression_id.",".$request->id.")");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$suite_version_id = get("score", $request->id, "suite_version_id");
|
||||||
|
$suite = get("suite_version", $suite_version_id, "name");
|
||||||
|
|
||||||
|
$query = mysql_query("SELECT id FROM awfy_regression_score
|
||||||
|
WHERE score_id = ".$request->id);
|
||||||
|
if (mysql_num_rows($query) == 0) {
|
||||||
|
mysql_query("INSERT INTO awfy_regression_score
|
||||||
|
(regression_id, score_id) VALUES (".$regression_id.",".$request->id.")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mysql_query("INSERT INTO awfy_regression_status
|
mysql_query("INSERT INTO awfy_regression_status
|
||||||
(regression_id, name, extra, stamp) VALUES
|
(regression_id, name, extra, stamp) VALUES
|
||||||
(".$regression_id.",'".username()."','Reported ".$suite." regression', UNIX_TIMESTAMP())");
|
(".$regression_id.",'".username()."','Reported ".$suite." regression', UNIX_TIMESTAMP())");
|
||||||
|
|
|
@ -107,6 +107,10 @@ awfyApp.config(['$routeProvider',
|
||||||
templateUrl: 'partials/search.html',
|
templateUrl: 'partials/search.html',
|
||||||
controller: 'searchCtrl'
|
controller: 'searchCtrl'
|
||||||
}).
|
}).
|
||||||
|
when('/bug/:bug', {
|
||||||
|
templateUrl: 'partials/search.html',
|
||||||
|
controller: 'searchCtrl'
|
||||||
|
}).
|
||||||
when('/open', {
|
when('/open', {
|
||||||
templateUrl: 'partials/open.html',
|
templateUrl: 'partials/open.html',
|
||||||
controller: 'searchCtrl'
|
controller: 'searchCtrl'
|
||||||
|
|
|
@ -187,7 +187,7 @@ awfyCtrl.controller('regressionCtrl', ['$scope', '$http', '$routeParams', '$q',
|
||||||
}
|
}
|
||||||
$scope.saveNoiseFn = function() {
|
$scope.saveNoiseFn = function() {
|
||||||
$http.post('change-noise.php', {
|
$http.post('change-noise.php', {
|
||||||
"build_id": $scope.regression["build_id"],
|
"regression_id": $scope.regression["id"],
|
||||||
"noise": $scope.noise
|
"noise": $scope.noise
|
||||||
}).success(function() {
|
}).success(function() {
|
||||||
$scope.editNoise = false;
|
$scope.editNoise = false;
|
||||||
|
@ -409,7 +409,7 @@ awfyCtrl.controller('searchCtrl', ['$scope', '$http', '$routeParams', '$q', 'mod
|
||||||
$scope.regressions = [];
|
$scope.regressions = [];
|
||||||
var ids = $scope.ids.slice(($scope.currentPage - 1) * 10, $scope.currentPage * 10);
|
var ids = $scope.ids.slice(($scope.currentPage - 1) * 10, $scope.currentPage * 10);
|
||||||
var minimal = false;
|
var minimal = false;
|
||||||
if (!$routeParams.search && !$routeParams.bug) { // confirmed regressions
|
if ($location.path().indexOf("open") == 1 && !$routeParams.bug) {
|
||||||
ids = $scope.ids;
|
ids = $scope.ids;
|
||||||
minimal = true;
|
minimal = true;
|
||||||
}
|
}
|
||||||
|
@ -426,7 +426,7 @@ awfyCtrl.controller('searchCtrl', ['$scope', '$http', '$routeParams', '$q', 'mod
|
||||||
|
|
||||||
$scope.regressions = regressions;
|
$scope.regressions = regressions;
|
||||||
|
|
||||||
if (!$routeParams.search && !$routeParams.bug) { // confirmed regressions
|
if ($location.path().indexOf("open") == 1 && !$routeParams.bug) {
|
||||||
var bugs = [];
|
var bugs = [];
|
||||||
for (var j = 0; j < regressions.length; j++) {
|
for (var j = 0; j < regressions.length; j++) {
|
||||||
var bug = regressions[j].bug;
|
var bug = regressions[j].bug;
|
||||||
|
@ -437,6 +437,22 @@ awfyCtrl.controller('searchCtrl', ['$scope', '$http', '$routeParams', '$q', 'mod
|
||||||
var retBugs = [];
|
var retBugs = [];
|
||||||
bugs.forEach(function(el) {
|
bugs.forEach(function(el) {
|
||||||
retBugs[retBugs.length] = el;
|
retBugs[retBugs.length] = el;
|
||||||
|
$http.get(
|
||||||
|
'https://bugzilla.mozilla.org/rest/bug/'+el.bug+'?include_fields=summary'
|
||||||
|
).then(function(data) {
|
||||||
|
for (var j=0; j<$scope.bugs.length; j++) {
|
||||||
|
if ($scope.bugs[j]["bug"] == el.bug) {
|
||||||
|
$scope.bugs[j]["title"] = data.data["bugs"][0]["summary"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},function(data) {
|
||||||
|
for (var j=0; j<$scope.bugs.length; j++) {
|
||||||
|
if ($scope.bugs[j]["bug"] == el.bug) {
|
||||||
|
if (data.data["code"] && data.data["code"] == 102)
|
||||||
|
$scope.bugs[j]["title"] = "Security bug";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
$scope.bugs = retBugs;
|
$scope.bugs = retBugs;
|
||||||
}
|
}
|
||||||
|
@ -462,6 +478,13 @@ awfyCtrl.controller('searchCtrl', ['$scope', '$http', '$routeParams', '$q', 'mod
|
||||||
setBug(bug);
|
setBug(bug);
|
||||||
fetch()
|
fetch()
|
||||||
}
|
}
|
||||||
|
$scope.setRegressions = function(bug) {
|
||||||
|
setTitle("Regressions for #"+bug);
|
||||||
|
setDefaultModeAndMachine();
|
||||||
|
setStates(["confirmed", "fixed", "improvement", "wontfix"]);
|
||||||
|
setBug(bug);
|
||||||
|
fetch()
|
||||||
|
}
|
||||||
$scope.setImprovements = function() {
|
$scope.setImprovements = function() {
|
||||||
setTitle("Improvements");
|
setTitle("Improvements");
|
||||||
setDefaultModeAndMachine();
|
setDefaultModeAndMachine();
|
||||||
|
@ -484,8 +507,10 @@ awfyCtrl.controller('searchCtrl', ['$scope', '$http', '$routeParams', '$q', 'mod
|
||||||
$scope.advanced = ($routeParams.search == "advanced");
|
$scope.advanced = ($routeParams.search == "advanced");
|
||||||
$scope.regressions = [];
|
$scope.regressions = [];
|
||||||
|
|
||||||
if (!$routeParams.search) // Confirmed regressions
|
if ($location.path().indexOf("open") == 1)
|
||||||
$scope.setNotFixedRegressions($routeParams.bug);
|
$scope.setNotFixedRegressions($routeParams.bug);
|
||||||
|
else if ($location.path().indexOf("bug") == 1)
|
||||||
|
$scope.setRegressions($routeParams.bug);
|
||||||
else if ($routeParams.search == "improvements")
|
else if ($routeParams.search == "improvements")
|
||||||
$scope.setImprovements();
|
$scope.setImprovements();
|
||||||
else if ($routeParams.search == "advanced")
|
else if ($routeParams.search == "advanced")
|
||||||
|
|
|
@ -63,7 +63,9 @@
|
||||||
<div>
|
<div>
|
||||||
<a ng-repeat="bug in bugs" class='box' ng-href='#/open/{{bug.bug}}'>
|
<a ng-repeat="bug in bugs" class='box' ng-href='#/open/{{bug.bug}}'>
|
||||||
<div class='header'>
|
<div class='header'>
|
||||||
<span ng-if="bug.bug != 0">Bug {{bug.bug}}</span>
|
<span ng-if="bug.bug != 0">Bug {{bug.bug}}
|
||||||
|
<span ng-if="bug.title"> - {{bug.title}}</span>
|
||||||
|
</span>
|
||||||
<span ng-if="bug.bug == 0">No bug</span>
|
<span ng-if="bug.bug == 0">No bug</span>
|
||||||
</div>
|
</div>
|
||||||
<div class='content'>
|
<div class='content'>
|
||||||
|
|
|
@ -80,6 +80,7 @@
|
||||||
<a ng-click="editNoiseFn()" class='link txt' ng-if="currentUser&&!editNoise">mark noise</a>
|
<a ng-click="editNoiseFn()" class='link txt' ng-if="currentUser&&!editNoise">mark noise</a>
|
||||||
<a ng-click="showNoiseFn()" class='link txt' ng-if="!showNoise&&!editNoise&&noiseCount">show scores marked as noise ({{noiseCount}})</a>
|
<a ng-click="showNoiseFn()" class='link txt' ng-if="!showNoise&&!editNoise&&noiseCount">show scores marked as noise ({{noiseCount}})</a>
|
||||||
<a ng-click="hideNoiseFn()" class='link txt' ng-if="showNoise&&!editNoise&&noiseCount">hide scores marked as noise ({{noiseCount}})</a>
|
<a ng-click="hideNoiseFn()" class='link txt' ng-if="showNoise&&!editNoise&&noiseCount">hide scores marked as noise ({{noiseCount}})</a>
|
||||||
|
<!--<a ng-click="editFixedFn()" class='link txt' ng-if="currentUser&&!editFixed">mark fixed</a>-->
|
||||||
<a ng-href="#/compare/{{regression.id}}" class='link txt'>compare with tip</a>
|
<a ng-href="#/compare/{{regression.id}}" class='link txt'>compare with tip</a>
|
||||||
<div class='header'>
|
<div class='header'>
|
||||||
Detected regressions/improvements
|
Detected regressions/improvements
|
||||||
|
@ -109,6 +110,7 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<input type='button' ng-if='editNoise' value='Mark as noise' ng-click="saveNoiseFn()">
|
<input type='button' ng-if='editNoise' value='Mark as noise' ng-click="saveNoiseFn()">
|
||||||
|
<input type='button' ng-if='editFixed' value='Mark as fixed' ng-click="saveFixedFn()">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче