Make it possible to find before and after runs of arbitrary revision

This commit is contained in:
Hannes Verschore 2016-04-04 08:56:13 -07:00
Родитель 92aadfa9db
Коммит 000a68f9e4
8 изменённых файлов: 357 добавлений и 12 удалений

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

@ -34,6 +34,32 @@ class Run extends DB {
return new Run(mysql_insert_id());
}
public static function closestRun($machine_id, $mode_id, $revisions) {
if (count($revisions) == 0)
throw new Exception("No revisions provided.");
$revs = "";
for ($i = 0; $i < count($revisions); $i++) {
if ($i != 0)
$revs .= ",";
$revs .= "'".$revisions[$i]->revision()."'";
}
$qRun = mysql_query("SELECT awfy_run.id FROM awfy_run
LEFT JOIN awfy_build ON run_id = awfy_run.id
WHERE cset IN (".$revs.") AND
machine = $machine_id AND
mode_id = $mode_id AND
status = 1 AND
error = ''
ORDER BY sort_order DESC
LIMIT 1") or die(mysql_error());
if (mysql_num_rows($qRun) == 0)
return null;
$run = mysql_fetch_object($qRun);
return new Run($run->id);
}
public function finish($status, $error = "") {
if (empty($error))
$error = "NULL";
@ -80,13 +106,6 @@ class Run extends DB {
return $this->select("detector");
}
public function builds() {
$qRun = mysql_query("SELECT approx_stamp from awfy_builds
WHERE id = {$this->id}") or die(mysql_error());
$run = mysql_fetch_object($qRun);
return $run->approx_stamp;
}
public function isBuildInfoComplete() {
// The set of builds cannot change anymore, when the run is finished
// or if this run is an out of order run. Out of order runs immediately
@ -102,6 +121,8 @@ class Run extends DB {
machine = {$machine}
ORDER BY sort_order ASC
LIMIT 1") or throw_exception(mysql_error());
if (mysql_num_rows($qRun) == 0)
return null;
$run = mysql_fetch_object($qRun);
return new Run($run->id);
}

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

@ -45,7 +45,7 @@ class TaskQueue {
FROM control_task_queue
WHERE control_unit_id = {$this->unit_id} AND
start = 0
ORDER BY id LIMIT 1") or die(mysql_error());
ORDER BY id") or die(mysql_error());
$tasks = Array();
while ($task = mysql_fetch_object($qTask)) {
$tasks[] = QueuedTask::FromId($task->id);

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

@ -3,6 +3,8 @@
require_once("ManipulateTask.php");
require_once("VersionControl.php");
require_once("DB/Mode.php");
require_once("DB/Run.php");
require_once("DB/Build.php");
class RetriggerController {
@ -80,9 +82,45 @@ class RetriggerController {
return true;
}
public static function computeBeforeAfterId($machine_id, $mode_id, $revision) {
$version_control = VersionControl::forMode($mode_id);
if (!$version_control->exists($revision))
throw new Exception("Revision does not exists.");
$next_revision = $revision;
$run = null;
$it = 0;
while (!$run) {
$revisions = $version_control->before($next_revision);
assert($revisions[0] == $revision);
$run = Run::closestRun($machine_id, $mode_id, $revisions);
$next_revision = $revisions[count($revisions) - 1]->revision();
if ($it > 50)
throw new Exception("Too much revisions given revision and previous datapoint.");
}
$run_before_id = $run->id;
$next = $run->next();
while (true) {
$cur = $next;
$next = $next->next();
if (!$cur)
throw new Exception("Couldn't find a revision with results after the given revision.");
if (!$cur->isFinished())
continue;
if ($cur->hasError())
continue;
if (!Build::withRunAndMode($cur->id, $mode_id))
continue;
break;
}
$run_after_id = $cur->id;
return Array($run_before_id, $run_after_id);
}
public function convertToRevision($mode_id, $revision, $run_before_id, $run_after_id) {
$mode = new Mode($mode_id);
foreach ($this->tasks as $task) {
$task->update_modes(Array("jmim"/*$mode->mode()*/));
$task->setBuildRevision($revision);
@ -91,13 +129,17 @@ class RetriggerController {
}
private function normalizeBenchmark($benchmark) {
// Keep in accordance with retrigger/index.php
$benchmark = str_replace("local.", "", $benchmark);
$benchmark = str_replace("remote.", "", $benchmark);
$benchmark = str_replace("shell.", "", $benchmark);
$benchmark = str_replace("-", "", $benchmark);
$benchmark = str_replace("misc", "assorted", $benchmark);
$benchmark = str_replace("ss", "sunspider", $benchmark);
$benchmark = str_replace("asmjsubench", "asmjsmicro", $benchmark);
if ($benchmark == "misc")
$benchmark = "assorted";
if ($benchmark == "ss")
$benchmark = "sunspider";
if ($benchmark == "asmjsubench")
$benchmark = "asmjsmicro";
return $benchmark;
}

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

@ -25,6 +25,12 @@ class HGWeb {
throw new Exception("Couldn't find relationship between $revision1 and $revision2.");
}
public function exists($revision) {
$html = file_get_contents($this->url."log?rev=$revision");
$pattern = '#<a href="/integration/mozilla-inbound/rev/'.$revision.'">diff</a><br/>#';
return preg_match($pattern, $html) == 1;
}
public function revisions($from, $to) {
$html = file_get_contents($this->url."log?rev=$from%3A%3A$to%20and%20!$from");
$html = preg_replace("/[\r\n]*/", "", $html);
@ -48,4 +54,20 @@ class HGWeb {
}
return $revisions;
}
public function before($revision) {
$html = file_get_contents($this->url."shortlog/".$revision);
$pattern = '#<a href="/integration/mozilla-inbound/rev/(.*)">diff</a><br/>#';
preg_match_all($pattern, $html, $matches);
$revisions = Array();
for ($i = 0; $i < count($matches[0]); $i++) {
$revision = $matches[1][$i];
$revisions[] = new Revision("", "", $revision, "");
}
assert($revisions[0] == $revision);
return $revisions;
}
}

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

@ -0,0 +1,28 @@
<?php
/* 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/. */
require_once("../internals.php");
require_once("../lib/RetriggerController.php");
require_once("../lib/VersionControl/HGWeb.php");
require_once("../lib/DB/ControlTasks.php");
require_once("../lib/DB/Mode.php");
init_database();
$machine_id = (int)$_GET["machine_id"];
$mode_id = (int)$_GET["mode_id"];
$retrigger = RetriggerController::fromMachine($machine_id, $mode_id);
if (count($retrigger->tasks) != 1)
die("Machine doesn't support retriggering yet.");
foreach ($retrigger->tasks as $task) {
$benchmarks = Array();
foreach ($task->benchmarks() as $task_benchmark) {
$benchmarks[] = $task_benchmark;
}
echo JSON_encode($benchmarks);
die();
}

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

@ -0,0 +1,30 @@
<?php
/* 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/. */
require_once("../internals.php");
require_once("../lib/RetriggerController.php");
require_once("../lib/VersionControl/HGWeb.php");
require_once("../lib/DB/ControlTasks.php");
require_once("../lib/DB/Mode.php");
init_database();
$machines = Array();
$control_tasks = ControlTasks::all();
foreach ($control_tasks as $control_task) {
$machine_id = $control_task->machine_id();
$mode_id = $control_task->mode_id() ? $control_task->mode_id() : Mode::FromMode("jmim")->id;
if (RetriggerController::retriggerable($machine_id, $mode_id)) {
$description = $control_task->machine()->description();
if ($control_task->mode_id())
$description .= " - ".$control_task->mode()->name();
$machines[$description] = Array(
"machine_id" => $control_task->machine()->id,
"mode_id" => $mode_id
);
}
}
echo JSON_encode($machines);

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

@ -0,0 +1,29 @@
<?php
/* 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/. */
require_once("../internals.php");
require_once("../lib/RetriggerController.php");
require_once("../lib/VersionControl/HGWeb.php");
require_once("../lib/DB/ControlTasks.php");
require_once("../lib/DB/Mode.php");
init_database();
$machine_id = (int)$_GET["machine_id"];
$mode_id = (int)$_GET["mode_id"];
$revision = $_GET["revision"];
$benchmarks = $_GET["benchmarks"];
if (!ctype_alnum($revision))
throw new Exception("Given revision is not alphanumeric.");
try {
$retrigger = RetriggerController::fromMachine($machine_id, $mode_id);
$runs = RetriggerController::computeBeforeAfterId($machine_id, $mode_id, $revision);
$retrigger->convertToRevision($mode_id, $revision, $runs[0], $runs[1]);
$retrigger->selectBenchmarks($benchmarks);
$retrigger->enqueueNow();
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}

173
website/retrigger/index.php Normal file
Просмотреть файл

@ -0,0 +1,173 @@
<html>
<head>
<style>
body {
margin-left:auto;
margin-right:auto;
width: 500px;
}
label {
margin-top: 25px;
display: block;
}
input, select {
display: block;
width: 500px;
}
#benchmarks {
height: 150px;
}
</style>
<script src='../jquery/jquery-1.8.3.min.js'></script>
<script>
$(function() {
function report() {
alert("Internal error: Please report to hv1989@gmail.com / h4writer on #jsapi.");
}
function urlHas(key, value) {
var params = location.search.split(key+"="+value)
if (params.length != 2)
return false;
if (params[0].slice(-1) != "?" && params[0].slice(-1) != "&")
return false;
if (params[1].length != 0 && params[1].substr(0,1) != "&")
return false;
return true;
}
function normalizeBench(name) {
// keep in accordance with lib/RetriggerController.php
name = name.replace(/ [0-9\.]*$/, "");
name = name.replace("local.", "");
name = name.replace("remote.", "");
name = name.replace("shell.", "");
name = name.replace("-", "");
if (name == "misc")
name = "assorted";
if (name == "ss")
name = "sunspider";
if (name == "asmjsubench")
name = "asmjsmicro";
return name;
}
function benchmarksFromUrl() {
var params = decodeURIComponent(location.search).split("benchmarks[]=")
var benchmarks = []
for (var i = 1; i<params.length; i++) {
if (params[i-1].slice(-1) != '?' && params[i-1].slice(-1) != "&")
continue;
var parts = params[i].split("&");
var name = normalizeBench(parts[0]);
benchmarks.push(name);
}
return benchmarks;
}
var benchmarks = [];
$.ajax({
url: "data-machines.php",
dataType: "json",
statusCode: { 500: report }
}).done(function(data) {
var selection = []
$.each(data, function(descr, id) {
var option = $('<option>').text(descr);
option.data("key", id);
$('#machines').append(option);
var select = true;
$.each(id, function(key, value) {
if (!urlHas(key, value))
select = false;
});
if (select) {
benchmarks = benchmarksFromUrl();
$('#machines').val(descr).change();
}
});
});
$('#machines').change(function() {
var value = $("#machines option:selected").data("key");
$('#benchmarks').text("");
if (!value)
return;
$.ajax({
url: "data-benchmarks.php",
data: value,
dataType: "json",
statusCode: { 500: report }
}).done(function(data) {
if (typeof data === 'string') {
alert("Error: "+data);
return;
}
$.each(data, function(id, name) {
var option = $('<option>').text(name);
if ($.inArray(normalizeBench(name), benchmarks) != -1)
option.attr('selected','selected');
$('#benchmarks').append(option);
});
});
});
$('#benchmarks').change(function() {
benchmarks = $('#benchmarks').val();
for (var i = 0; i < benchmarks.length; i++) {
benchmarks[i] = normalizeBench(benchmarks[i]);
}
});
var match = location.search.match(/[&?]revision=([a-zA-Z0-9]*)(&|$)/);
if (match)
$('#revision').val(match[1]);
$("#trigger").submit(function(event) {
event.preventDefault();
var data = $("#machines option:selected").data("key");
data["revision"] = $("#revision").val();
data["benchmarks"] = $("#benchmarks").val();
console.log(data);
$.ajax({
url: "data-submit.php",
data: data,
statusCode: { 500: report }
}).done(function(data) {
if (data.length > 0) {
alert("Error: "+data);
} else {
alert("Succesfully enqueued");
}
});
return false;
});
});
</script>
</head>
<body>
<h1>Trigger a revision on AWFY</h1>
<form id='trigger'>
<label>Machine:
<select id='machines'>
<option>--- Select a machine ---</option>
</select>
</label>
<label>Revision:
<input type='text' name='revision' id='revision'>
</label>
<label>Benchmarks:
<select multiple id='benchmarks'>
</select>
</label>
<input type='submit' value='Trigger!'>
</form>
</body>
</html>