Create start of a lib directory

This commit is contained in:
Hannes Verschore 2015-10-29 16:29:52 +01:00
Родитель 669999efbb
Коммит c87328a1bf
8 изменённых файлов: 474 добавлений и 32 удалений

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

@ -0,0 +1,49 @@
<?php
class BashInterpreter {
public static function matchCommand($text, $command) {
$command = str_replace("/", "\/", $command);
preg_match_all("/".$command." .*[;|$|\r\n]/", $text, $matches);
return $matches[0];
}
public static function matchFlag($command, $flag) {
$flag = str_replace("/", "\/", $flag);
preg_match_all("/".$flag." ([a-zA-Z0-9.~\-\/]*)/", $command, $matches);
return $matches[1];
}
public static function removeFlagFromCommand($text, $full_command, $full_flag) {
$replaced = str_replace($full_flag, "", $full_command);
$text = str_replace($full_command, $replaced, $text);
return $text;
}
public static function addFlagToCommands($text, $command, $full_flag) {
return str_replace($command, $command." ".$full_flag, $text);
}
public static function removeFlagFromCommands($text, $command, $full_flag) {
foreach(BashInterpreter::matchCommand($text, $command) as $match) {
$text = BashInterpreter::removeFlagFromCommand($text, $match, $full_flag);
}
return $text;
}
public static function removeCommand($text, $full_command) {
return str_replace($full_command, "", $text);
}
public static function normalizeDir($dir) {
$dir = str_replace("//", "/", $dir);
$dir = str_replace("/./", "/", $dir);
$dir = preg_replace("#^./#", "", $dir);
$dir = str_replace("~", '$HOME', $dir);
$dir = preg_replace("#/$#", "", $dir);
return $dir;
}
public static function sameDir($dir1, $dir2) {
return BashInterpreter::normalizeDir($dir1) == BashInterpreter::normalizeDir($dir2);
}
}

30
website/lib/DB/Mode.php Normal file
Просмотреть файл

@ -0,0 +1,30 @@
<?php
class Mode {
// db: awfy_mode
function __construct($id) {
$this->id = $id;
}
function vendor() {
$qMode = mysql_query("SELECT vendor_id
FROM awfy_mode
WHERE id = {$this->id}");
$mode = mysql_fetch_object($qMode);
return $mode->vendor_id;
}
function mode() {
$qMode = mysql_query("SELECT mode
FROM awfy_mode
WHERE id = {$this->id}");
$mode = mysql_fetch_object($qMode);
return $mode->mode;
}
function id() {
return $this->id;
}
}

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

@ -0,0 +1,30 @@
<?php
class QueuedTask {
// db: control_task_queue
function __construct($id) {
$this->id = $id;
}
function setBusy() {
mysql_query("UPDATE control_task_queue SET busy = 1 WHERE id = {$this->id}") or die(mysql_error());
}
function setFinished() {
mysql_query("DELETE FROM control_task_queue WHERE id = {$this->id}");
}
function task() {
$qTask = mysql_query("SELECT task
FROM control_task_queue
WHERE id = {$this->id}");
$task = mysql_fetch_object($qTask);
return $task->task;
}
function id() {
return $this->id;
}
}

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

@ -0,0 +1,42 @@
<?php
require_once("QueuedTask.php");
class TaskQueue {
// db: control_task_queue
function __construct($unit_id) {
$this->unit_id = $unit_id;
}
// Returns if there is a task still running.
function has_active_task() {
$qTask = mysql_query("SELECT *
FROM control_task_queue
WHERE control_unit_id = {$this->unit} AND busy = 1
ORDER BY id LIMIT 1");
return mysql_num_rows($qTask) != 0;
}
function has_queued_tasks() {
$qTask = mysql_query("SELECT *
FROM control_task_queue
WHERE control_unit_id = $unit and busy = 0
ORDER BY id LIMIT 1");
return mysql_num_rows($qTask) != 0;
}
function pop() {
$qTask = mysql_query("SELECT id
FROM control_task_queue
WHERE control_unit_id = $unit and busy = 0
ORDER BY id LIMIT 1");
$task = mysql_fetch_object($qTask);
$task = QueuedTask($task->id);
$task->setBusy();
return $task;
}
}

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

@ -0,0 +1,137 @@
<?php
include_once "BashInterpreter.php";
include_once "Task.php";
class ManipulateTask extends Task {
public function update_benchmarks($new_benchmarks) {
//Note: Impossible to add new benchmarks using this command. Only possible to prune ones.
$old_benchmarks = $this->benchmarks();
$removed_benchmarks = array_diff($old_benchmarks, $new_benchmarks);
foreach($removed_benchmarks as $removed) {
$this->task = BashInterpreter::removeFlagFromCommands($this->task, "python execute.py", "-b ".$removed);
}
$this->optimize();
}
public function update_configs($new_configs) {
//Note: Impossible to add new configs using this command. Only possible to prune ones.
$old_configs= $this->configs();
$removed_configs = array_diff($old_configs, $new_configs);
foreach($removed_configs as $removed) {
$this->task = BashInterpreter::removeFlagFromCommands($this->task, "python execute.py", "-c ".$removed);
}
$this->optimize();
}
public function update_engines($new_engines) {
//Note: Impossible to add new engines using this command. Only possible to prune ones.
$old_engines = $this->engines();
$removed_engines = array_diff($old_engines, $new_engines);
// Build engines
$commands = BashInterpreter::matchCommand($this->task, "python build.py");
foreach ($commands as $command) {
$source_matches = BashInterpreter::matchFlag($command, "-s");
$engine = $this->source_rules()[$source_matches[0]];
print_r($removed_engines);
if (in_array($engine, $removed_engines)) {
$this->removeBuildOrDownloadCommand($command);
}
}
$this->optimize();
}
public function update_modes($modes) {
$engines = [];
$configs = [];
$mode_rules = array_flip($this->mode_rules());
foreach ($modes as $mode) {
$rule = $mode_rules[$mode];
$rule = split(",", $rule);
$engines[] = $rule[0];
$configs[] = $rule[1];
}
$this->update_engines($engines);
$this->update_configs($configs);
}
public function setTipRevision() {
$this->removeRevisionInfo();
}
public function setRevision($new_revision) {
$this->removeRevisionInfo();
$this->task = BashInterpreter::addFlagToCommands($this->task, "python build.py", "-r ".$new_revision);
}
private function removeRevisionInfo() {
$commands = BashInterpreter::matchCommand($this->task, "python download.py");
if (count($commands) != 0)
throw new Exception("Not yet supported to specify revision for downloaded builds.");
$commands = BashInterpreter::matchCommand($this->task, "python build.py");
foreach ($commands as $command) {
$revision_matches = BashInterpreter::matchFlag($command, "-r");
for ($revision_matches as $revision) {
$this->task = BashInterpreter::removeFlagFromCommand($this->task, $command, "-r ".$revision);
}
}
}
private function removeBuildOrDownloadCommand($command) {
$output_matches = BashInterpreter::matchFlag($command, "-o");
$this->task = BashInterpreter::removeCommand($this->task, $command);
if (count($output_matches) == 0) {
// If there was no output dir specified, remove all executes where no engine dir is given.
// or where the default 'output' dir is specified.
$commands = BashInterpreter::matchCommand($this->task, "python execute.py");
foreach ($commands as $command) {
$engine_matches = BashInterpreter::matchFlag($command, "-e");
if (count($engine_matches) == 0) {
$this->task = BashInterpreter::removeCommand($this->task, $command);
continue;
}
foreach ($engine_matches as $engineDir) {
if (BashInterpreter::sameDir($engineDir, "output")) {
$this->task = BashInterpreter::removeFlagFromCommand($this->task, $command, "-e ".$engineDir);
if (count($engine_matches) == 1)
$this->task = BashInterpreter::removeCommand($this->task, $command);
}
}
}
} else {
$outputDir = $output_matches[0];
$commands = BashInterpreter::matchCommand($this->task, "python execute.py");
foreach ($commands as $command) {
$engine_matches = BashInterpreter::matchFlag($command, "-e");
foreach ($engine_matches as $engineDir) {
if (BashInterpreter::sameDir($engineDir, $outputDir)) {
$this->task = BashInterpreter::removeFlagFromCommand($this->task, $command, "-e ".$engineDir);
if (count($engine_matches) == 1)
$this->task = BashInterpreter::removeCommand($this->task, $command);
}
}
}
}
}
private function optimize() {
$commands = BashInterpreter::matchCommand($this->task, "python execute.py");
foreach ($commands as $command) {
// Any execute without benchmarks don't need to get run.
if (count(BashInterpreter::matchFlag($command, "-b")) == 0)
$this->task = BashInterpreter::removeCommand($this->task, $command);
}
}
}

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

@ -0,0 +1,65 @@
<?php
require_once("ManipulateTask.php");
require_once("DB/Mode.php");
class RetriggerController {
public function __construct() {
$this->tasks = [];
$this->unit_id = 0;
}
public static function fromUnit($unit_id) {
$retrigger = new RetriggerController();
$retrigger->unit_id = $unit_id;
$qTask = mysql_query("SELECT * FROM control_tasks WHERE control_unit_id = $unit_id");
while ($task = mysql_fetch_object($qTask)) {
$task = new ManipulateTask($task);
$retrigger->tasks[] = $task;
}
return $retrigger;
}
public static function fromMachine($machine, $mode_id = 0) {
$retrigger = new RetriggerController();
$mode = new Mode($mode_id);
$qTask = mysql_query("SELECT * FROM control_tasks WHERE machine_id = $machine");
while ($task = mysql_fetch_object($qTask)) {
if (!($mode_id == 0 || $task->mode_id == 0 || $task->mode_id == $mode_id))
continue;
$task = new ManipulateTask($task);
if ($mode_id != 0)
$task->update_modes($mode->mode());
$retrigger->tasks[] = $task;
if ($this->unit_id != 0 && $this->unit_id != $task->control_unit_id)
throw new Exception("Only one machine allowed.");
$this->unit_id = $task->control_unit_id;
}
return $retrigger;
}
public function setRevision($revision) {
foreach ($this->tasks as $task) {
$task->setRevision($revision);
}
}
public function enqueue() {
if ($this->unit_id == 0)
throw new Exception("No control_unit specified.");
foreach ($this->tasks as $task) {
mysql_query("INSERT INTO control_task_queue
(control_unit_id, task)
VALUES ({$this->unit_id}, '".mysql_escape_string($task)."')");
}
}
}

101
website/lib/Task.php Normal file
Просмотреть файл

@ -0,0 +1,101 @@
<?php
class Task {
// The build function contains the 'source' it needs to fetch
// the code from. We need to know which source is which engine.
// This makes the transition from source to engine.
// Note: an engine can have multiple sources.
public function source_rules() {
return [
"mozilla" => "firefox",
"v8" => "chrome",
"webkit" => "webkit"
];
}
// The execute function looks at engine+config to decide which
// mode it should send this data to. These contain the default rules.
// Though it is possible to add some extra rules in the task
// itself. These are not accounted for (TODO).
public function mode_rules() {
return [
"firefox,default" => "jmim",
"firefox,noasmjs" => "noasmjs",
"firefox,unboxedobjects" => "unboxedobjects",
"firefox,testbedregalloc" => "testbed",
"chrome,default" => "v8",
"chrome,turbofan" => "v8-turbofan",
"webkit,default" => "jsc",
"native,default" => "clang",
"servo,default" => "servo"
];
}
public function __construct($task) {
$this->task = $task;
}
public function task() {
return $this->task;
}
public function configs() {
$configs = [];
$commands = BashInterpreter::matchCommand($this->task, "python execute.py");
foreach ($commands as $command) {
$config_matches = BashInterpreter::matchFlag($command, "-c");
foreach ($config_matches as $match) {
$configs[] = $match;
}
}
return array_unique($configs);
}
public function engines() {
$engines = [];
// Fetch all engines that have been build.
$commands = BashInterpreter::matchCommand($this->task, "python build.py");
foreach ($commands as $command) {
$source_matches = BashInterpreter::matchFlag($command, "-s");
if (count($source_matches) != 1)
throw new Error("Expected one match.");
$engines[] = $this->source_rules()[$source_matches[0]];
}
// Fetch all engines that have been downloaded.
// TODO.
return array_unique($engines);
}
public function modes() {
$configs = $this->configs();
$engines = $this->engines();
$mode_rules = $this->mode_rules();
$modes = [];
foreach ($configs as $config) {
foreach ($engines as $engine) {
$rule = $engine.",".$config;
if (isset($mode_rules[$rule])) {
$modes[] = $mode_rules[$rule];
}
}
}
return $modes;
}
public function benchmarks() {
$configs = [];
$commands = BashInterpreter::matchCommand($this->task, "python execute.py");
foreach ($commands as $command) {
$config_matches = BashInterpreter::matchFlag($command, "-b");
foreach ($config_matches as $match) {
$configs[] = $match;
}
}
return array_unique($configs);
}
}

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

@ -5,48 +5,36 @@
require_once("internals.php"); require_once("internals.php");
require_once("lib/RetriggerController.php");
require_once("lib/DB/TaskQueue.php");
require_once("lib/DB/QueuedTask.php");
init_database(); init_database();
if (isset($_GET["unit"]) && is_numeric($_GET["unit"])) { if ($unit = GET_int("unit")) {
$unit = (int)$_GET["unit"];
$qTask = mysql_query("SELECT * $queue = new TaskQueue($unit);
FROM control_task_queue if ($queue->has_active_task())
WHERE control_unit_id = $unit AND busy = 1
ORDER BY id LIMIT 1");
if (mysql_num_rows($qTask) != 0) {
slack("requesting new task, while old task is still running!"); slack("requesting new task, while old task is still running!");
if (!$queue->has_queued_tasks())
$retrigger = RetriggerController::fromUnit($unit);
$retrigger->enqueue();
} }
$task = $queue->pop();
$qTask = mysql_query("SELECT * echo json_encode([
FROM control_task_queue "task" => $task->task(),
WHERE control_unit_id = $unit and busy = 0 "id" => $task->id()
ORDER BY id LIMIT 1"); ]);
if (mysql_num_rows($qTask) == 0) {
$qTask = mysql_query("SELECT task FROM control_tasks WHERE control_unit_id = $unit");
while ($task = mysql_fetch_object($qTask)) {
mysql_query("INSERT INTO control_task_queue
(control_unit_id, task)
VALUES ($unit, '".mysql_escape_string($tasks->task)."')");
}
}
$qTask = mysql_query("SELECT *
FROM control_task_queue
WHERE control_unit_id = $unit and busy = 0
ORDER BY id LIMIT 1");
$task = mysql_fetch_object($qTask);
echo json_encode(Array("task" => $task->task,
"id" => $task->id));
mysql_query("UPDATE control_task_queue SET busy = 1 WHERE id = ".$task->id);
die(); die();
} else if (isset($_GET["finish"]) && is_numeric($_GET["finish"])) { } else if ($task_id = GET_int("finish")) {
$task_id = $_GET["finish"];
mysql_query("DELETE FROM control_task_queue WHERE id = ".$task_id); $task = QueuedTask($task_id);
$task->setFinished();
die(); die();
} }