Commit ca2e8c1b authored by Kento HASEGAWA's avatar Kento HASEGAWA

Merge branch 'comm' into 'master'

Add support for resolver and improve UI

See merge request adc2018/adc2018-system!9
parents 4cffa912 5e4c621e
......@@ -3,6 +3,8 @@
.DS_Store
*.txt
*.tmp
*.json
# Object files
*.o
......@@ -17,3 +19,7 @@ solver
# Python files
*.pyc
__pycache__/
# client-icons
client-icon/
......@@ -21,7 +21,6 @@ import adc2018solver as pynqrouter
app = Flask(__name__)
args = {}
# pynq_thread = None
client_baseurl = ""
@app.route('/start', methods=["POST"])
......@@ -45,10 +44,15 @@ def start():
qseed = request.form["qseed"]
boardstr = BoardStr.conv_boardstr(qstr.split('\n'), 'random', int(qseed))
option = {"name": qname, "host": args['host'], "client": client_baseurl}
option = {
"name": qname,
"host": args['host'],
"client": client_baseurl,
"req_id": request.form['req_id'],
"resolver": request.form['resolver']
}
pynqrouter.start_solver(boardstr, qseed, option)
# pynq_thread = pynqrouter.start_solver(boardstr, qseed, option)
# 実行だけ開始する
ans["status"] = "Processing"
......@@ -64,8 +68,6 @@ def start():
@app.route('/stop')
def stop():
# global pynq_thread
if pynqrouter.solver_thread is None:
ans = {"status": "No threads"}
else:
......@@ -73,15 +75,11 @@ def stop():
pynqrouter.stop_solver()
ans = {"status": "Stopped"}
# pynq_thread = None
return json.dumps(ans)
@app.route("/status")
def status():
# global pynq_thread
res_mes = ""
if pynqrouter.solver_thread is None:
......@@ -121,3 +119,4 @@ if __name__ == "__main__":
if args["debug"]:
app.debug = True
app.run(host='0.0.0.0', port=args["port"], threaded=True)
DAS2018 ADC クライアント(リゾルバ)プログラム
===
DAS2018 アルゴリズムデザインコンテスト用クライアントプログラム
## Description
解答データをソルバから受信し,整形した結果をサーバへ返すプログラム.
## Requirements
- Python 3.5以上(くらい)
- Flask
## Usage
```
python3 main.py [--port XXXX] [--host XXXX]
```
### Options
<dl>
<dt>-H, --host</dt>
<dd>サーバホストのアドレス (デフォルト:192.168.5.1:5000)</dd>
<dt>-p, --port</dt>
<dd>使用するポート (デフォルト:5000)</dd>
</dl>
#!/usr/bin/env python3
"""
This script provides a PYNQ client.
This is intended to run on the client server (PYNQ).
"""
import argparse
import json
import os
import platform
import queue
import requests
import subprocess
import sys
import threading
import time
from flask import Flask, render_template, request, g
from urllib.parse import urlparse
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../../solver')
import BoardStr
# import adc2018solver as pynqrouter
app = Flask(__name__)
args = {}
client_baseurl = ""
resolve_queue = None
def resolve():
"""
queueを受け取りそこに入ってきた答えを整形し,ホストに送信します.
"""
global args
global client_baseurl
global resolve_queue
while True:
if resolve_queue is None:
time.sleep(1)
continue
else:
data = resolve_queue.get()
if args['verbose']:
print("Processing queued data...")
print(data)
outpath = "./works/resolved.txt"
probpath = "./problems/{}".format(data['qname'])
tmppath = "./works/answer.txt"
with open(tmppath, "w") as fp:
fp.write(data['answer'])
# Resolver
cmd = "/home/pi/adc2017/pynq-router/resolver/solver --reroute --output {} {} {}".format(outpath, probpath, tmppath)
subprocess.call(cmd.strip().split(" "))
resolved = ""
with open(outpath, "r") as fp:
resolved = fp.read()
res = {
'answer': resolved,
'solved': True,
'solver': data['client'],
'resolver': client_baseurl,
'client': client_baseurl,
'cputime': data['cputime'],
'qname': data['qname'],
'req_id': data['req_id']
}
# 結果をホストに返す
r = requests.post("http://{}/post".format(args['host']), data=res)
if args['verbose']:
print("Done.")
print(res)
@app.route('/post', methods=["POST"])
def start():
# global pynq_thread
global args
global client_baseurl
global resolve_queue
if args["verbose"]:
print(request.form)
data = {
'client': request.form['client'],
'qname': request.form['qname'],
'answer': request.form['solution'],
'cputime': request.form['cputime'],
'req_id': request.form['req_id']
}
resolve_queue.put(data)
ans = {"status": "Queued"}
if args["verbose"]:
print(ans)
return json.dumps(ans)
@app.route('/stop')
def stop():
global resolve_queue
if resolve_queue.empty() is None:
ans = {"status": "Nothing queued"}
else:
# pynq_thread.stop()
while not resolve_queue.empty():
resolve_queue.get()
ans = {"status": "Stopped"}
return json.dumps(ans)
@app.route("/status")
def status():
res_mes = ""
if resolve_queue.empty():
res_mes = "Ready"
else:
res_mes = "Working"
res = {"status": res_mes}
return json.dumps(res)
@app.route("/")
def index():
return platform.node()
@app.before_request
def before_request():
global client_baseurl
_url = request.url
parse = urlparse(_url)
client_baseurl = parse.netloc
if __name__ == "__main__":
# Check if this script runs as "root" user
# if os.getuid() != 0:
# raise Exception("Must run as root")
# sys.exit(1)
parser = argparse.ArgumentParser(description="PYNQ client (for resolver).")
parser.add_argument("-p", "--port", action="store", type=int, default=5000, help="Port")
parser.add_argument("-H", "--host", action="store", type=str, default="192.168.5.1:5000", help="Host address")
parser.add_argument("--debug", action="store_true", default=False, help="Debug mode.")
parser.add_argument("-v", "--verbose", action="store_true", default=False, help="Verbose.")
args = vars(parser.parse_args())
# Start resolver thread
resolve_queue = queue.Queue()
th = threading.Thread(target=resolve, args=())
th.setDaemon(True)
th.start()
if args["debug"]:
app.debug = True
app.run(host='0.0.0.0', port=args["port"], threaded=True)
DAS2017 ADC サーバプログラム
DAS218 ADC サーバプログラム
===
DAS2017 アルゴリズムデザインコンテスト用サーバプログラム
DAS2018 アルゴリズムデザインコンテスト用サーバプログラム
## Description
......@@ -32,12 +32,6 @@ python3 main.py [--question XXXX] [--port XXXX] [--clients XXXX]
<dt>-p, --port</dt>
<dd>サーバのポート (デフォルト:5000)</dd>
<dt>-l, --line-num-th</dt>
<dd>処理を分岐させるライン数の閾値</dd>
<dt>-t, --timeout</dt>
<dd>PYNQで処理させるタイムアウト(秒)</dd>
</dl>
## Comments
......
This diff is collapsed.
......@@ -43,12 +43,16 @@ body{
#client-control-pane{
height: 330px;
overflow: scroll;
overflow-y: scroll;
}
#client-control-pane table th,
#client-control-pane table td{
width: 50%;
#client-control-pane table th.large-cell,
#client-control-pane table td.large-cell{
width: 40%;
}
#client-control-pane table th.small-cell,
#client-control-pane table td.small-cell{
width: 20%;
}
#question-control-pane h3{
......
......@@ -63,7 +63,6 @@ var PynqManager = (function(){
}).done(function(res){
var answer = res;
$("#solving-question-status").text(answer["status"]);
$("#solved-result").text(answer["answer"]["answer"]);
$("#solved-client").text(answer["answer"]["client"]);
if (after !== null){
......@@ -75,7 +74,31 @@ var PynqManager = (function(){
_p.sendStop = function(){
console.log("Not implemented!");
for (var key in this.clients){
(function(_key, _client){
var statusObj = $(".client-status-row[data-cname='"+_key+"']").find(".client-status-value").eq(0)
$.ajax({
type: "POST",
url: "/stop",
dataType: "json",
data: {
"client": _client
}
}).done(function(res){
var answer = res["status"];
var message = "";
if (answer) {
message = answer;
}else{
message = "Illegal response: " + res;
}
statusObj.text(message);
}).fail(function(){
statusObj.text("Connection error");
});
})(key, this.clients[key]);
}
}
......@@ -102,13 +125,19 @@ $(function(){
$(".question-row").removeClass("q-selected");
$tr.addClass("q-selected");
var qname = $tr.data("qname");
show_question_status(qname);
// show_question_status(qname);
location.hash = "#" + qname;
return false;
});
var hash = location.hash.replace("#", "");
if(hash != ""){
$(".question-row[data-qname='" + hash + "']").addClass("q-selected");
}
});
}
var refresh_client_table = function(){
var show_client_table = function(){
$.ajax({
type: "GET",
dataType: "html",
......@@ -116,17 +145,8 @@ $(function(){
}).done(function(d){
$("#client-control-pane").html("");
$("#client-control-pane").html(d);
$.ajax({
type: "GET",
dataType: "json",
url: "/get_clients"
}).done(function(d){
pynqClients = d;
pm = PynqManager(pynqClients);
pm.getStatus();
});
});
}
var show_question_status = function(qname){
......@@ -143,15 +163,30 @@ $(function(){
var qname = $(this).data("qname");
pm.sendQuestion(qname, after=refresh_question_table);
});
$("#client-control-pane").find(".stop-button").eq(0).click(function(){
pm.sendStop();
});
});
}
$(window).on('hashchange', function(){
var hash = location.hash.replace("#", "");
if(hash == ""){
show_client_table();
}else{
show_question_status(hash);
}
}).trigger('hashchange');
refresh_question_table();
refresh_client_table();
$("#view-server-status-button").click(function(){
refresh_client_table();
return false;
$.ajax({
type: "GET",
dataType: "json",
url: "/get_clients"
}).done(function(d){
pynqClients = d;
pm = PynqManager(pynqClients);
});
});
......@@ -20,7 +20,7 @@
<div class="row">
<div class="col-5" id="question-control-pane">
<h3>問題一覧</h3>&nbsp;
<span><a href="#" id="view-server-status-button">クライアント状況</a></span>
<span><a href="/#" id="view-server-status-button">システム状況</a></span>
<div id="question-table-wrapper">
<p>Loading...</p>
</div>
......
<h3>クライアント状況</h3>
<h3>システム状況</h3>
<h4>動作モード</h4>
<p>
{% if local_mode %}
Normal Mode
{% else %}
Viewer Mode
{% endif %}
</p>
<h4>クライアント</h4>
<table class="table table-bordered" id="clients-table">
<tr>
<th>クライアント名</th>
<th>ステータス</th>
<th class="">Client</th>
<th class="">Role</th>
<th class="">Status</th>
</tr>
{% for c in clients %}
<tr class="client-status-row" data-cname="{{c}}">
<td class="client-status-name">{{c}}</td>
<tr class="client-status-row" data-cname="{{c[0]}}">
<td class="client-status-name">
{% if c|length > 3 %}
<img src="static/client-icon/{{c[3]}}" alt="{{c[2]}}" height="30" />&nbsp;
{% endif %}
{{c[0]}}
{% if c|length > 2 %}
&nbsp;({{c[2]}})
{% endif %}
</td>
<td class="">{{c[1]}}</td>
<td class="client-status-value"></td>
</tr>
{% endfor %}
......
<h3>問題 【{{qname}}】</h3>
<p>
<div class="row">
<div class="col-4">
<h3> 【{{qname}}】</h3>
<p>
<button class="btn btn-primary btn-lg start-button" type="button" data-qname="{{qname}}">Start</button>
</p>
<button class="btn btn-danger btn-lg stop-button" type="button" data-qname="all">Stop</button>
</p>
</div>
<div class="col-8">
<p>処理結果</p>
<table class="table table-bordered">
<tr>
<th>Client (Solver)</th>
<th>Status</th>
</tr>
{% for c in solvers %}
<tr>
<td>
{% if c|length > 3 %}
<img src="static/client-icon/{{c[3]}}" alt="{{c[2]}}" height="30" />&nbsp;
{% endif %}
{{c[0]}}
{% if c|length > 2 %}
&nbsp;({{c[2]}})
{% endif %}
</td>
<td></td>
</tr>
{% endfor %}
</table>
</div>
</div>
<div>
<h4>処理結果一覧</h4>
<table class="table table-bordered table-striped">
<tr>
<th>Timestamp</th>
<th>Client</th>
<th>Score</th>
</tr>
{% for v in qdata.answers %}
<tr>
<td>{{v.timestamp}}</td>
<td>{{v.solver}}</td>
<td>{{v.nlcheck}}</td>
</tr>
{% endfor %}
</table>
</div>
<p>状況:<span id="solving-question-status">{{qdata.status}}</span></p>
<h4>結果</h4>
<p>クライアント:<span id="solved-client">{{qdata.answer.client}}</span></p>
......
......@@ -78,6 +78,15 @@ def solve(boardstr, seed=12345, zero_padding=False, option=dict()):
print(seed)
print('')
res = {
'client': option['client'],
'qname': option['name'],
'solution': '',
'cputime': -1.0,
'req_id': option['req_id'],
'solved': False
}
# LINE数を数えてコンフィグするbitstreamを分岐
line_num = boardstr.count('L')
if line_num < 127:
......@@ -89,7 +98,9 @@ def solve(boardstr, seed=12345, zero_padding=False, option=dict()):
else:
solver_thread.stopped()
solver_thread = None
return {'solved': False, 'solution': '', 'elapsed': -1.0}
if "host" in option:
requests.post("http://{}/post".format(option['host']), data=res)
return res
# ボード文字列から X, Y, Z を読んでくる
size_x = (ord(boardstr[1]) - ord('0')) * 10 + (ord(boardstr[2]) - ord('0'))
......@@ -137,7 +148,9 @@ def solve(boardstr, seed=12345, zero_padding=False, option=dict()):
if (solver_thread is not None) and (not solver_thread.is_running()):
solver_thread.stopped()
solver_thread = None
return { 'solved': False, 'solution': '', 'elapsed': -1.0 }
if "host" in option:
requests.post("http://{}/post".format(option['host']), data=res)
return res
# 完了の確認
print('Done!')
......@@ -154,11 +167,11 @@ def solve(boardstr, seed=12345, zero_padding=False, option=dict()):
# 解けなかったらLEDを消す
mmio_led.write(0, 0)
sys.stderr.write('Cannot solve it!\n')
res = {'client': option['client'], 'qname': option['name'], 'answer': '', 'cputime': -1}
if "host" in option:
requests.post("http://{}/post".format(option['host']), data=res)
solver_thread = None
return { 'solved': False, 'solution': '', 'elapsed': -1.0 }
return res
print('Solved!')
# 解けたらLEDを全部つける
......@@ -185,13 +198,24 @@ def solve(boardstr, seed=12345, zero_padding=False, option=dict()):
solution += str(boards[i]) # 普通に表示
solution += '\n'
res = {
'client': option['client'],
'qname': option['name'],
'solution': solution,
'cputime': elapsed,
'req_id': option['req_id'],
'solved': True
}
if "resolver" in option:
r = requests.post("http://{}/post".format(option['resolver']), data=res)
elif "host" in option:
r = requests.post("http://{}/post".format(option['host']), data=res)
if solver_thread is not None:
solver_thread.stopped()
res = {'client': option['client'], 'qname': option['name'], 'answer': solution, 'cputime': elapsed}
if "host" in option:
r = requests.post("http://{}/post".format(option['host']), data=res)
solver_thread = None
return { 'solved': True, 'solution': solution, 'elapsed': elapsed }
return res
def main():
parser = argparse.ArgumentParser(description="Solver with pynqrouter")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment