Remove obsolete code and database info.

This commit is contained in:
Hannes Verschore 2017-03-14 13:49:53 +01:00
Родитель 63fcafd3b0
Коммит 131b1b41f3
7 изменённых файлов: 51 добавлений и 1079 удалений

2
TODO
Просмотреть файл

@ -1,2 +0,0 @@
UPDATE.php: make sequential
migrate-2.php: create a sequence out of what used to be a stamp

51
database/migration-15.php Normal file
Просмотреть файл

@ -0,0 +1,51 @@
<?php
$migrate = function() {
mysql_query("DROP TABLE awfy_regression_breakdown_noise");
mysql_query("DROP TABLE awfy_regression_score_noise");
mysql_query("ALTER TABLE `awfy_suite` DROP `confidence_factor`;");
mysql_query("ALTER TABLE `awfy_suite_test` DROP `confidence_factor`;");
mysql_query("ALTER TABLE `awfy_machine` DROP `confidence_runs`");
};
$rollback = function() {
mysql_query("CREATE TABLE `awfy_regression_breakdown_noise` (
`id` int(10) UNSIGNED NOT NULL,
`machine_id` int(10) UNSIGNED NOT NULL,
`mode_id` int(10) UNSIGNED NOT NULL,
`suite_test_id` int(10) UNSIGNED NOT NULL,
`noise` double NOT NULL,
`disabled` tinyint(1) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='avg_consequent_diff'");
mysql_query("ALTER TABLE `awfy_regression_breakdown_noise`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `machine_id` (`machine_id`,`mode_id`,`suite_test_id`)");
mysql_query("ALTER TABLE `awfy_regression_breakdown_noise`
MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT");
mysql_query("CREATE TABLE `awfy_regression_score_noise` (
`id` int(10) UNSIGNED NOT NULL,
`machine_id` int(10) UNSIGNED NOT NULL,
`mode_id` int(10) UNSIGNED NOT NULL,
`suite_version_id` int(10) UNSIGNED NOT NULL,
`noise` double NOT NULL,
`disabled` tinyint(1) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='avg_consequent_diff'");
mysql_query("ALTER TABLE `awfy_regression_score_noise`
ADD PRIMARY KEY (`id`),
ADD KEY `machine_id` (`machine_id`),
ADD KEY `mode_id` (`mode_id`),
ADD KEY `suite_version_id` (`suite_version_id`)");
mysql_query("ALTER TABLE `awfy_regression_score_noise`
MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT");
mysql_query("ALTER TABLE `awfy_suite` ADD `confidence_factor` FLOAT NOT NULL DEFAULT '1' AFTER `visible`");
mysql_query("ALTER TABLE `awfy_suite_test` ADD `confidence_factor` FLOAT NOT NULL DEFAULT '1' AFTER `visible`");
mysql_query("ALTER TABLE `awfy_machine` ADD `confidence_runs` TINYINT NOT NULL DEFAULT '5' AFTER `message`");
};

Просмотреть файл

@ -1,109 +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/.
from optparse import OptionParser
import sys
import time
sys.path.append("../server")
import awfy
import tables
parser = OptionParser(usage="usage: %prog [options]")
parser.add_option("-n", "--non-existing", dest="nonexistonly", action="store_true", default=False,
help="Only compute noise of items that don't have one yet.")
(options, args) = parser.parse_args()
def median(x):
x.sort()
length = len(x)
if length % 2 == 1:
return x[length/2]
else:
return (x[(length-1)/2] + x[(length+1)/2]) / 2.0
def avg_diff(machine, suite, mode, first):
prev = first
current = first.next()
diffs = []
while current:
diff = abs(prev.get('score') - current.get('score'))
if diff != 0:
diffs.append(diff)
prev = current
current = current.next()
if len(diffs) == 0:
return None
return median(diffs)
def equal_sign(a, b):
if a >= 0 and b >= 0:
return True
if a <= 0 and b <= 0:
return True
return False
def avg_consequent_diff(machine, suite, mode, first):
prev = first
current = first.next()
diffs = []
consequent = 0
while current:
diff = prev.get('score') - current.get('score')
if diff != 0:
if equal_sign(diff, consequent):
consequent += diff
else:
diffs.append(abs(consequent))
consequent = diff
prev = current
current = current.next()
if consequent != 0:
diffs.append(abs(consequent))
if len(diffs) == 0:
return None
return median(diffs)
for machine in tables.Machine.all():
if (machine.id != 28 and # mac os x 32 bit shell
machine.id != 29 and # mac os x 64 bit shell
machine.id != 26 and # ffos flame browser
machine.id != 30 and # mac os x browser
machine.id != 17): # windows 8 browser
continue
for mode in tables.Mode.allWith(machine):
for suite in tables.SuiteVersion.all():
# Don't update, only insert new ones, if requested
if tables.RegressionScoreNoise(machine, suite, mode).id != 0 and options.nonexistonly:
continue
first = tables.Score.firstOfRecent(machine, suite, mode)
if not first:
continue
diff = avg_consequent_diff(machine, suite, mode, first)
if not diff:
continue
tables.RegressionScoreNoise.insertOrUpdate(machine, suite, mode, diff)
print suite.get('name'), mode.get('name'), diff
awfy.db.commit()
for suite in tables.SuiteTest.all():
# Don't update, only insert new ones, if requested
if tables.RegressionBreakdownNoise(machine, suite, mode).id != 0 and options.nonexistonly:
continue
first = tables.Breakdown.firstOfRecent(machine, suite, mode)
if not first:
continue
diff = avg_consequent_diff(machine, suite, mode, first)
if not diff:
continue
tables.RegressionBreakdownNoise.insertOrUpdate(machine, suite, mode, diff)
print suite.get('name'), mode.get('name'), diff
awfy.db.commit()

Просмотреть файл

@ -1,178 +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 os
import sys
pwd = os.path.dirname(os.path.realpath(__file__))
sys.path.append("../server")
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
if not item.score().hasNoise():
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
if not score.hasNoise():
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
def zoomNoRegression(item):
PARTITIONS = 5
CRUNS = 100 / PARTITIONS * PARTITIONS
AMOUNT = CRUNS / PARTITIONS
def _avg(items):
if len(items) == 0:
return 0
return sum(items)/len(items)
def partition(li):
nli = []
for i in range(PARTITIONS):
nli.append(_avg(li[i*AMOUNT:i*AMOUNT+AMOUNT]))
return nli
def _noise(li):
noise = []
for i in range(len(li)-1):
noise.append(abs(li[i] - li[i+1]))
return noise
def outliner(li, i, noise):
if i == 0:
return False
elif len(li) - 1 == i:
return False
if abs(li[i-1] - li[i+1]) < noise:
if abs(li[i] - li[i+1]) > noise and abs(li[i] - li[i-1]) > noise:
return True
return False
def remove_outliners(li, noise):
return [li[i] for i in range(len(li)) if not outliner(li, i, noise)]
score = item.score()
nexts = [score.get("score")] + [i.get("score") for i in score.nexts(CRUNS - 1)]
prevs = [i.get("score") for i in score.prevs(CRUNS)]
if len(nexts) != CRUNS:
return False
if len(prevs) != CRUNS:
return False
nexts = partition(nexts)
prevs = partition(prevs)
noise = _avg(_noise(nexts) + _noise(prevs))
nexts = remove_outliners(nexts, noise)
prevs = remove_outliners(prevs, noise)
noise = _avg(_noise(nexts) + _noise(prevs))
if abs(nexts[0] - prevs[0]) > noise:
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
if zoomNoRegression(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()

Просмотреть файл

@ -1,141 +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/.
from optparse import OptionParser
import os
import sys
import time
pwd = os.path.dirname(os.path.realpath(__file__))
sys.path.append(pwd + "../server")
import awfy
import tables
parser = OptionParser(usage="usage: %prog [options]")
parser.add_option( "--dry-run", dest="dryrun", action="store_true", default=False,
help="Don't commit the new regressions to the database yet.")
(options, args) = parser.parse_args()
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 finish_stamp > "+str(newer)+" AND \
status = 1 AND \
detector != 1 AND \
machine in (28,29,26,17,30)")
runs = []
for row in c.fetchall():
runs.append(tables.Run(row[0]))
return runs
def regressed(score):
# Disabled. So no testing
if score.disabled():
return False
# 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:
if not score.sane():
continue
regressed_ = regressed(score)
# Not enough info yet
if regressed_ is None:
finish = False
if regressed_ is True:
score.dump()
if not options.dryrun:
build = score.get("build_id")
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({"regression_id": regression_id,
"score_id": score.get("id")})
elif score.__class__ == tables.Breakdown:
tables.RegressionBreakdown.insert({"regression_id": regression_id,
"breakdown_id": score.get("id")})
else:
assert False
except:
pass
if finish and not options.dryrun:
run.update({"detector": "1"})
tables.DBTable.maybeflush()
awfy.db.commit()

Просмотреть файл

@ -1,35 +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 sys
sys.path.append("../server")
import awfy
c = awfy.db.cursor()
#TODO: ONLY DELETE IF REPORTED BY REGRESSION DETECTOR
c.execute("SELECT id, build_id \
FROM awfy_regression \
WHERE status = 'unconfirmed'")
for row in c.fetchall():
c.execute("DELETE FROM awfy_regression_breakdown \
WHERE build_id = %s", row[1])
c.execute("DELETE FROM awfy_regression_score \
WHERE build_id = %s", row[1])
c.execute("DELETE FROM awfy_regression_status \
WHERE regression_id = %s", row[0])
c.execute("DELETE FROM awfy_regression \
WHERE id = %s", row[0])
c.execute("UPDATE awfy_run \
LEFT JOIN awfy_build ON awfy_run.id = awfy_build.run_id \
SET detector = 0 \
WHERE awfy_build.id = %s", row[1])
print row[0]
#TODO: remove detector status from all itmes higher than the lowest run id
#c.execute("UPDATE awfy_run \
# SET detector = 0 \
# WHERE id > 249273")
awfy.db.commit()

Просмотреть файл

@ -149,19 +149,6 @@ class Run(DBTable):
def table():
return "awfy_run"
@staticmethod
def fromSortOrder(machine_id, sort_order):
c = awfy.db.cursor()
c.execute("SELECT id \
FROM awfy_run \
WHERE machine = %s AND \
sort_order = %s", (machine_id, sort_order))
rows = c.fetchall()
if len(rows) == 0:
return None
assert len(rows) == 1
return Run(rows[0][0])
def initialize(self):
if self.initialized:
return
@ -170,16 +157,6 @@ class Run(DBTable):
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 \
@ -190,9 +167,6 @@ class Run(DBTable):
scores += Build(row[0]).getScores()
return scores
def finishStamp(self):
pass
class SuiteTest(DBTable):
def __init__(self, id):
DBTable.__init__(self, id)
@ -229,137 +203,10 @@ 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():
if row[0] == 0:
continue
yield Mode(row[0])
@staticmethod
def table():
return "awfy_mode"
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 score(self):
return self.get("score")
@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 score(self):
return self.get("breakdown")
@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)
@ -391,231 +238,10 @@ class Build(DBTable):
scores.append(Score(row[0]))
return scores
def getScoresAndBreakdowns(self):
scores = self.getScores()
c = awfy.db.cursor()
c.execute("SELECT awfy_breakdown.id \
FROM awfy_breakdown \
LEFT JOIN awfy_score ON awfy_score.id = score_id \
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
if self.prev() is None:
return False
if not self.hasNoise():
return False
if abs(self.next().get("score") - self.prev().get("score")) < self.noise():
if (abs(self.next().get("score") - self.get("score")) > self.noise() and
abs(self.prev().get("score") - self.get("score")) > self.noise()):
return True
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():
# ?? should this be prevs - self.get("score") ? maybe ?
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)
@ -624,19 +250,6 @@ class Score(RegressionTools):
def table():
return "awfy_score"
@staticmethod
def fromBuildAndSuite(build_id, suite_version_id):
c = awfy.db.cursor()
c.execute("SELECT id \
FROM awfy_score \
WHERE build_id = %s AND \
suite_version_id = %s", (build_id, suite_version_id))
rows = c.fetchall()
if len(rows) == 0:
return None
assert len(rows) == 1
return Score(rows[0][0])
def getBreakdowns(self):
c = awfy.db.cursor()
c.execute("SELECT awfy_breakdown.id \
@ -647,116 +260,6 @@ class Score(RegressionTools):
breakdowns.append(Breakdown(row[0]))
return breakdowns
def sane(self):
if self.get("suite_version_id") == -1:
return False
if self.get("suite_version_id") == 0:
return False
if not self.hasNoise():
return False
return True
def prefetch_next(self, limit = 1):
sort_order = self.get("build").get("run").get("sort_order")
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 sort_order > %s AND \
machine = %s AND \
mode_id = %s AND \
suite_version_id = %s AND \
status = 1 \
ORDER BY sort_order ASC \
LIMIT "+str(limit), (sort_order, machine, mode, suite))
rows = c.fetchall()
return [Score(row[0]) for row in rows]
def prefetch_prev(self, limit = 1):
sort_order = self.get("build").get("run").get("sort_order")
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 sort_order < %s AND \
machine = %s AND \
mode_id = %s AND \
suite_version_id = %s AND \
status = 1 \
ORDER BY sort_order DESC \
LIMIT "+str(limit), (sort_order, 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 disabled(self):
return RegressionScoreNoise(self.get('build').get('run').get('machine'),
self.get('suite_version'),
self.get('build').get('mode')).get('disabled')
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
def hasNoise(self):
return RegressionScoreNoise(self.get('build').get('run').get('machine'),
self.get('suite_version'),
self.get('build').get('mode')).id != 0
@classmethod
def firstOfRecent(class_, machine, suite, mode):
assert machine.__class__ == Machine
assert suite.__class__ == SuiteVersion
assert mode.__class__ == Mode
c = awfy.db.cursor()
c.execute("SELECT id \
FROM (SELECT awfy_score.id, sort_order \
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 sort_order DESC \
LIMIT 1000) tmp \
ORDER BY sort_order 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):
import datetime
print datetime.datetime.fromtimestamp(
int(self.get("build").get("run").get("finish_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)
@ -772,120 +275,3 @@ class Breakdown(RegressionTools):
return Score(self.get("score_id")).get("build")
return super(Breakdown, self).get(field)
def sane(self):
if self.get("suite_test_id") == 0:
return False
if self.get("suite_test_id") == -1:
return False
if self.get("suite_test").get("suite_version_id") == -1:
return False
if self.get("suite_test").get("suite_version_id") == 0:
return False
if not self.hasNoise():
return False
return True
def prefetch_next(self, limit = 1):
sort_order = self.get("build").get("run").get("sort_order")
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_score ON awfy_score.id = awfy_breakdown.score_id \
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 sort_order > %s AND \
machine = %s AND \
mode_id = %s AND \
suite_test_id = %s AND \
status = 1 \
ORDER BY sort_order ASC \
LIMIT "+str(limit), (sort_order, machine, mode, suite))
rows = c.fetchall()
return [Breakdown(row[0]) for row in rows]
def prefetch_prev(self, limit = 1):
sort_order = self.get("build").get("run").get("sort_order")
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_score ON awfy_score.id = awfy_breakdown.score_id \
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 sort_order < %s AND \
machine = %s AND \
mode_id = %s AND \
suite_test_id = %s AND \
status = 1 \
ORDER BY sort_order DESC \
LIMIT "+str(limit), (sort_order, machine, mode, suite))
rows = c.fetchall()
return [Breakdown(row[0]) for row in rows]
@classmethod
def firstOfRecent(class_, machine, suite, mode):
assert machine.__class__ == Machine
assert suite.__class__ == SuiteTest
assert mode.__class__ == Mode
c = awfy.db.cursor()
c.execute("SELECT id \
FROM (SELECT awfy_breakdown.id, sort_order \
FROM awfy_breakdown \
INNER JOIN awfy_score ON awfy_score.id = awfy_breakdown.score_id \
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_test_id = %s AND \
status = 1 \
ORDER BY sort_order DESC \
LIMIT 1000) tmp \
ORDER BY sort_order 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 disabled(self):
return RegressionBreakdownNoise(self.get('build').get('run').get('machine'),
self.get('suite_test'),
self.get('build').get('mode')).get('disabled')
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 hasNoise(self):
return RegressionBreakdownNoise(self.get('build').get('run').get('machine'),
self.get('suite_test'),
self.get('build').get('mode')).id != 0
def dump(self):
import datetime
print datetime.datetime.fromtimestamp(
int(self.get("build").get("run").get("finish_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())+")"