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.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()
|
||||
|
||||
def notProcessedRuns():
|
||||
|
@ -103,16 +103,30 @@ if __name__ == "__main__":
|
|||
score.dump()
|
||||
if not options.dryrun:
|
||||
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
|
||||
prev_build = score.prev().get("build_id")
|
||||
regression = [regression for regression in tables.Regression.where({
|
||||
"build_id": build,
|
||||
"prev_build_id": prev_build
|
||||
})]
|
||||
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:
|
||||
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:
|
||||
tables.RegressionBreakdown.insert({"build_id": build, "breakdown_id": score.get("id")})
|
||||
tables.RegressionBreakdown.insert({"regression_id": regression_id,
|
||||
"breakdown_id": score.get("id")})
|
||||
else:
|
||||
assert False
|
||||
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)+" \
|
||||
WHERE id = %s", (self.id, ))
|
||||
|
||||
def delete(self):
|
||||
c = awfy.db.cursor()
|
||||
c.execute("DELETE FROM "+self.table()+" \
|
||||
WHERE id = %s", (self.id, ))
|
||||
|
||||
@staticmethod
|
||||
def valuefy(value):
|
||||
if "'" in str(value):
|
||||
|
@ -109,6 +114,14 @@ class DBTable:
|
|||
for row in c.fetchall():
|
||||
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
|
||||
def maybeflush(class_):
|
||||
#TODO
|
||||
|
@ -211,27 +224,29 @@ class Regression(DBTable):
|
|||
def __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
|
||||
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)
|
||||
def score(self):
|
||||
return self.get("score")
|
||||
|
||||
@staticmethod
|
||||
def table():
|
||||
|
@ -271,22 +286,9 @@ class RegressionScoreNoise(DBTable):
|
|||
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)
|
||||
def score(self):
|
||||
return self.get("breakdown")
|
||||
|
||||
@staticmethod
|
||||
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;
|
||||
|
||||
// Hide a view modes by default. Since they aren't active anymore
|
||||
//AWFYMaster.modes["30"].hidden = true
|
||||
AWFYMaster.modes["35"].hidden = true
|
||||
AWFYMaster.modes["27"].hidden = true
|
||||
AWFYMaster.modes["29"].hidden = true
|
||||
|
|
|
@ -13,13 +13,13 @@ if ($subtest) {
|
|||
$query = mysql_query("SELECT awfy_regression.id, noise, status
|
||||
FROM `awfy_regression_breakdown`
|
||||
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);
|
||||
} else {
|
||||
$query = mysql_query("SELECT awfy_regression.id, noise, status
|
||||
FROM `awfy_regression_score`
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -143,6 +143,21 @@
|
|||
ga('send', 'pageview');
|
||||
|
||||
</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>
|
||||
</html>
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@ session_start();
|
|||
|
||||
function init_database()
|
||||
{
|
||||
mysql_connect("localhost", "***", "***") or die("ERROR: " . mysql_error());
|
||||
mysql_select_db("dvander") or die("ERROR: " . mysql_error());
|
||||
mysql_connect("localhost", "awfy", "LFQZdX6Ca57QcwhE") or die("ERROR: " . mysql_error());
|
||||
mysql_select_db("awfy") or die("ERROR: " . mysql_error());
|
||||
}
|
||||
|
||||
function username()
|
||||
|
|
|
@ -47,6 +47,21 @@
|
|||
ga('send', 'pageview');
|
||||
|
||||
</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>
|
||||
</html>
|
||||
|
|
|
@ -13,13 +13,13 @@ if (!has_permissions())
|
|||
$postdata = file_get_contents("php://input");
|
||||
$request = json_decode($postdata);
|
||||
|
||||
$build_id = (int)$request->build_id;
|
||||
$regression_id = (int)$request->regression_id;
|
||||
|
||||
foreach($request->noise->score as $score_id => $noise) {
|
||||
$noise = (int)$noise;
|
||||
$score_id = (int)$score_id;
|
||||
$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
|
||||
") or die(mysql_error());
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ foreach($request->noise->breakdown as $score_id => $noise) {
|
|||
$noise = (int)$noise;
|
||||
$score_id = (int)$score_id;
|
||||
$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
|
||||
") or die(mysql_error());
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ init_database();
|
|||
|
||||
$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
|
||||
WHERE (mode_id = 14 OR
|
||||
mode_id = 28 or
|
||||
|
@ -20,10 +20,10 @@ $query = mysql_query("SELECT build_id FROM awfy_regression
|
|||
status != 'fixed' AND status != 'improvement'");
|
||||
while ($regs = mysql_fetch_object($query)) {
|
||||
$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);
|
||||
$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);
|
||||
$qDate = mysql_query("SELECT stamp FROM awfy_build
|
||||
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()
|
||||
);
|
||||
$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)) {
|
||||
$suite_version_id = get("score", $scores["score_id"], "suite_version_id");
|
||||
$score = array(
|
||||
|
@ -67,7 +67,7 @@ for ($i=0; $i < count($ids); $i++) {
|
|||
$regression["scores"][] = $score;
|
||||
}
|
||||
$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)) {
|
||||
$suite_test_id = get("breakdown", $scores["breakdown_id"], "suite_test_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++)
|
||||
$request->states[$i] = "'".mysql_real_escape_string($request->states[$i])."'";
|
||||
$states = join(",", $request->states);
|
||||
$bug = (int)$request->bug;
|
||||
|
||||
$bug = null;
|
||||
if (isset($request->bug) && $request->bug !== "")
|
||||
$bug = (int)$request->bug;
|
||||
|
||||
#TODO
|
||||
date_default_timezone_set("Europe/Brussels");
|
||||
|
@ -34,6 +35,8 @@ if (!empty($states))
|
|||
$where[] = "awfy_regression.status in ($states)";
|
||||
if (!empty($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
|
||||
FROM awfy_regression
|
||||
|
|
|
@ -14,29 +14,10 @@ $request->id = (int) $request->id;
|
|||
if (!isset($request->subtest))
|
||||
$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");
|
||||
$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
|
||||
(build_id, breakdown_id) VALUES (".$build_id.",".$request->id.")");
|
||||
}
|
||||
} else {
|
||||
else
|
||||
$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
|
||||
WHERE build_id = ".$build_id);
|
||||
|
@ -49,6 +30,28 @@ if (mysql_num_rows($query) == 0) {
|
|||
$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
|
||||
(regression_id, name, extra, stamp) VALUES
|
||||
(".$regression_id.",'".username()."','Reported ".$suite." regression', UNIX_TIMESTAMP())");
|
||||
|
|
|
@ -107,6 +107,10 @@ awfyApp.config(['$routeProvider',
|
|||
templateUrl: 'partials/search.html',
|
||||
controller: 'searchCtrl'
|
||||
}).
|
||||
when('/bug/:bug', {
|
||||
templateUrl: 'partials/search.html',
|
||||
controller: 'searchCtrl'
|
||||
}).
|
||||
when('/open', {
|
||||
templateUrl: 'partials/open.html',
|
||||
controller: 'searchCtrl'
|
||||
|
|
|
@ -187,7 +187,7 @@ awfyCtrl.controller('regressionCtrl', ['$scope', '$http', '$routeParams', '$q',
|
|||
}
|
||||
$scope.saveNoiseFn = function() {
|
||||
$http.post('change-noise.php', {
|
||||
"build_id": $scope.regression["build_id"],
|
||||
"regression_id": $scope.regression["id"],
|
||||
"noise": $scope.noise
|
||||
}).success(function() {
|
||||
$scope.editNoise = false;
|
||||
|
@ -409,7 +409,7 @@ awfyCtrl.controller('searchCtrl', ['$scope', '$http', '$routeParams', '$q', 'mod
|
|||
$scope.regressions = [];
|
||||
var ids = $scope.ids.slice(($scope.currentPage - 1) * 10, $scope.currentPage * 10);
|
||||
var minimal = false;
|
||||
if (!$routeParams.search && !$routeParams.bug) { // confirmed regressions
|
||||
if ($location.path().indexOf("open") == 1 && !$routeParams.bug) {
|
||||
ids = $scope.ids;
|
||||
minimal = true;
|
||||
}
|
||||
|
@ -426,7 +426,7 @@ awfyCtrl.controller('searchCtrl', ['$scope', '$http', '$routeParams', '$q', 'mod
|
|||
|
||||
$scope.regressions = regressions;
|
||||
|
||||
if (!$routeParams.search && !$routeParams.bug) { // confirmed regressions
|
||||
if ($location.path().indexOf("open") == 1 && !$routeParams.bug) {
|
||||
var bugs = [];
|
||||
for (var j = 0; j < regressions.length; j++) {
|
||||
var bug = regressions[j].bug;
|
||||
|
@ -437,6 +437,22 @@ awfyCtrl.controller('searchCtrl', ['$scope', '$http', '$routeParams', '$q', 'mod
|
|||
var retBugs = [];
|
||||
bugs.forEach(function(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;
|
||||
}
|
||||
|
@ -462,6 +478,13 @@ awfyCtrl.controller('searchCtrl', ['$scope', '$http', '$routeParams', '$q', 'mod
|
|||
setBug(bug);
|
||||
fetch()
|
||||
}
|
||||
$scope.setRegressions = function(bug) {
|
||||
setTitle("Regressions for #"+bug);
|
||||
setDefaultModeAndMachine();
|
||||
setStates(["confirmed", "fixed", "improvement", "wontfix"]);
|
||||
setBug(bug);
|
||||
fetch()
|
||||
}
|
||||
$scope.setImprovements = function() {
|
||||
setTitle("Improvements");
|
||||
setDefaultModeAndMachine();
|
||||
|
@ -484,8 +507,10 @@ awfyCtrl.controller('searchCtrl', ['$scope', '$http', '$routeParams', '$q', 'mod
|
|||
$scope.advanced = ($routeParams.search == "advanced");
|
||||
$scope.regressions = [];
|
||||
|
||||
if (!$routeParams.search) // Confirmed regressions
|
||||
if ($location.path().indexOf("open") == 1)
|
||||
$scope.setNotFixedRegressions($routeParams.bug);
|
||||
else if ($location.path().indexOf("bug") == 1)
|
||||
$scope.setRegressions($routeParams.bug);
|
||||
else if ($routeParams.search == "improvements")
|
||||
$scope.setImprovements();
|
||||
else if ($routeParams.search == "advanced")
|
||||
|
|
|
@ -63,7 +63,9 @@
|
|||
<div>
|
||||
<a ng-repeat="bug in bugs" class='box' ng-href='#/open/{{bug.bug}}'>
|
||||
<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>
|
||||
</div>
|
||||
<div class='content'>
|
||||
|
|
|
@ -80,6 +80,7 @@
|
|||
<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="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>
|
||||
<div class='header'>
|
||||
Detected regressions/improvements
|
||||
|
@ -109,6 +110,7 @@
|
|||
</span>
|
||||
</div>
|
||||
<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>
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче