diff --git a/website/lib/BashInterpreter.php b/website/lib/BashInterpreter.php new file mode 100644 index 0000000..793eb82 --- /dev/null +++ b/website/lib/BashInterpreter.php @@ -0,0 +1,49 @@ +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; + } +} + diff --git a/website/lib/DB/QueuedTask.php b/website/lib/DB/QueuedTask.php new file mode 100644 index 0000000..7cc4ca8 --- /dev/null +++ b/website/lib/DB/QueuedTask.php @@ -0,0 +1,30 @@ +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; + } +} + diff --git a/website/lib/DB/TaskQueue.php b/website/lib/DB/TaskQueue.php new file mode 100644 index 0000000..2484772 --- /dev/null +++ b/website/lib/DB/TaskQueue.php @@ -0,0 +1,42 @@ +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; + } +} diff --git a/website/lib/ManipulateTask.php b/website/lib/ManipulateTask.php new file mode 100644 index 0000000..ebba0f1 --- /dev/null +++ b/website/lib/ManipulateTask.php @@ -0,0 +1,137 @@ +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); + + } + } +} + diff --git a/website/lib/RetriggerController.php b/website/lib/RetriggerController.php new file mode 100644 index 0000000..c711c02 --- /dev/null +++ b/website/lib/RetriggerController.php @@ -0,0 +1,65 @@ +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)."')"); + } + } +} + diff --git a/website/lib/Task.php b/website/lib/Task.php new file mode 100644 index 0000000..96048ae --- /dev/null +++ b/website/lib/Task.php @@ -0,0 +1,101 @@ + "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); + } +} diff --git a/website/task.php b/website/task.php index 4408ddc..4411321 100644 --- a/website/task.php +++ b/website/task.php @@ -5,48 +5,36 @@ require_once("internals.php"); +require_once("lib/RetriggerController.php"); +require_once("lib/DB/TaskQueue.php"); +require_once("lib/DB/QueuedTask.php"); + init_database(); -if (isset($_GET["unit"]) && is_numeric($_GET["unit"])) { - $unit = (int)$_GET["unit"]; +if ($unit = GET_int("unit")) { - $qTask = mysql_query("SELECT * - FROM control_task_queue - WHERE control_unit_id = $unit AND busy = 1 - ORDER BY id LIMIT 1"); - if (mysql_num_rows($qTask) != 0) { + $queue = new TaskQueue($unit); + if ($queue->has_active_task()) 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 * - FROM control_task_queue - WHERE control_unit_id = $unit and busy = 0 - 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); + echo json_encode([ + "task" => $task->task(), + "id" => $task->id() + ]); die(); -} else if (isset($_GET["finish"]) && is_numeric($_GET["finish"])) { - $task_id = $_GET["finish"]; - mysql_query("DELETE FROM control_task_queue WHERE id = ".$task_id); +} else if ($task_id = GET_int("finish")) { + + $task = QueuedTask($task_id); + $task->setFinished(); die(); }