Loading comm/client/main.py +19 −60 Changes for comm/client/main.py: 19 added lines, 60 removed lines. Original line number Diff line number Diff line Loading @@ -17,65 +17,17 @@ from urllib.parse import urlparse sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../../solver') import BoardStr import pynqrouter import adc2018solver as pynqrouter app = Flask(__name__) args = {} pynq_thread = None # pynq_thread = None client_baseurl = "" # Reference: https://teratail.com/questions/52593 class StoppableThread(threading.Thread): def __init__(self, target, qname, qstr, qseed): super(StoppableThread, self).__init__(target=target) self._th_stop = threading.Event() self._qname = qname self._qstr = qstr self._qseed = int(qseed) self._answer = None def run(self): global client_baseurl global pynq_thread global args # Main funciton (the solver should be placed here) boardstr = BoardStr.conv_boardstr(self._qstr.split('\n'), 'random', self._qseed) result = pynqrouter.solve(boardstr, self._qseed) if result['solved']: answer = result['solution'] else: answer = None pynq_thread = None return res = { "client": client_baseurl, "qname": self._qname, "answer": answer, "cputime": result['elapsed'] } self._answer = answer r = requests.post("http://{}/post".format(args["host"]), data=res) if args["verbose"]: print(res) pynq_thread = None def stop(self): self._th_stop.set() def stopped(self): return self._th_stop.isSet() def get_answer(self): return self._answer @app.route('/start', methods=["POST"]) def start(): global pynq_thread # global pynq_thread global args global client_baseurl Loading @@ -84,13 +36,19 @@ def start(): if args["verbose"]: print(request.form) if pynq_thread is None: if pynqrouter.solver_thread is not None: pynqrouter.stop_solver() if pynqrouter.solver_thread is None: qstr = request.form["question"] qname = request.form["qname"] qseed = request.form["qseed"] pynq_thread = StoppableThread(target=StoppableThread, qname=qname, qstr=qstr, qseed=qseed) pynq_thread.start() boardstr = BoardStr.conv_boardstr(qstr.split('\n'), 'random', int(qseed)) option = {"name": qname, "host": args['host'], "client": client_baseurl} pynqrouter.start_solver(boardstr, qseed, option) # pynq_thread = pynqrouter.start_solver(boardstr, qseed, option) # 実行だけ開始する ans["status"] = "Processing" Loading @@ -106,26 +64,27 @@ def start(): @app.route('/stop') def stop(): global pynq_thread # global pynq_thread if pynq_thread is None: if pynqrouter.solver_thread is None: ans = {"status": "No threads"} else: pynq_thread.stop() # pynq_thread.stop() pynqrouter.stop_solver() ans = {"status": "Stopped"} pynq_thread = None # pynq_thread = None return json.dumps(ans) @app.route("/status") def status(): global pynq_thread # global pynq_thread res_mes = "" if pynq_thread is None: if pynqrouter.solver_thread is None: res_mes = "Ready" else: res_mes = "Working" Loading solver/adc2018solver.py 0 → 100644 +267 −0 Changes for solver/adc2018solver.py: 267 added lines, 0 removed lines. Original line number Diff line number Diff line #!/opt/python3.6/bin/python3.6 # -*- coding: utf-8 -*- """ PYNQ 上で pynqrouter を実行する。 """ from pynq import Overlay from pynq import PL from pynq import MMIO import argparse import requests import sys import time import threading import BoardStr # Settings -- pynqrouter IP = 'SEG_pynqrouter_0_Reg' OFFSET_BOARD = 65536 # 0x10000 ~ 0x1ffff OFFSET_SEED = 131072 # 0x20000 OFFSET_STATUS = 131080 # 0x20008 MAX_X = 72 MAX_Y = 72 MAX_Z = 8 BITWIDTH_Z = 3 # Settings -- LED IP_LED = 'SEG_axi_gpio_0_Reg' solver_thread = None class StoppableThread(threading.Thread): def __init__(self, target, args=()): super(StoppableThread, self).__init__(target=target, args=args) self._status = 'running' def stop(self): if self._status == 'running': self._status = 'stopping' def stopped(self): self._status = 'stopped' def is_running(self): return (self._status == 'running') def is_stopping(self): return (self._status == 'stopping') def is_stopped(self): return (self._status == 'stopped') def start_solver(boardstr, seed, option): global solver_thread if solver_thread is None: solver_thread = StoppableThread(target=solve, args=(boardstr, int(seed), False, option)) solver_thread.start() def stop_solver(): global solver_thread if solver_thread is not None: if solver_thread.is_running(): solver_thread.stop() solver_thread.join() solver_thread = None def solve(boardstr, seed=12345, zero_padding=False, option=dict()): global solver_thread print('boardstr:') print(boardstr) print('seed:') print(seed) print('') # ボード文字列から X, Y, Z を読んでくる size_x = (ord(boardstr[1]) - ord('0')) * 10 + (ord(boardstr[2]) - ord('0')) size_y = (ord(boardstr[4]) - ord('0')) * 10 + (ord(boardstr[5]) - ord('0')) size_z = (ord(boardstr[7]) - ord('0')) # Overlay 読み込み OL = Overlay('pynqrouter_lines128_length256.bit') OL.download() print(OL.ip_dict) print('Overlay loaded!') # MMIO 接続 (pynqrouter) mmio = MMIO(int(PL.ip_dict[IP][0], 16), int(PL.ip_dict[IP][1], 16)) # MMIO 接続 & リセット (LED) mmio_led = MMIO(int(PL.ip_dict[IP_LED][0], 16), int(PL.ip_dict[IP_LED][1], 16)) mmio_led.write(0, 0) # 入力データをセット imem = pack(boardstr) for i in range(len(imem)): mmio.write(OFFSET_BOARD + (i * 4), imem[i]) mmio.write(OFFSET_SEED, seed) # スタート # ap_start (0 番地の 1 ビット目 = 1) mmio.write(0, 1) print('Start!') time_start = time.time() # ap_done (0 番地の 2 ビット目 = 2) が立つまで待ってもいいが # done は一瞬だけ立つだけのことがあるから # ap_idle (0 番地の 3 ビット目 = 4) を待ったほうが良い iteration = 0 while (mmio.read(0) & 4) == 0: # 動いてるっぽく見えるようにLチカさせる iteration += 1 if iteration == 10000: mmio_led.write(0, 3) elif 20000 <= iteration: mmio_led.write(0, 12) iteration = 0 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 } # 完了の確認 print('Done!') print('control:', mmio.read(0)) time_done = time.time() elapsed = time_done - time_start print('elapsed:', elapsed) print('') # 状態の取得 status = int(mmio.read(OFFSET_STATUS)) print('status:', status) if status != 0: # 解けなかったら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 } print('Solved!') # 解けたらLEDを全部つける mmio_led.write(0, 15) # 出力 omem = [] for i in range(len(imem)): omem.append(mmio.read(OFFSET_BOARD + (i * 4))) boards = unpack(omem) # 回答の生成 solution = ('SIZE ' + str(size_x) + 'X' + str(size_y) + 'X' + str(size_z) + '\n') for z in range(size_z): solution += ('LAYER ' + str(z + 1) + '\n') for y in range(size_y): for x in range(size_x): if x != 0: solution += ',' i = ((x * MAX_X + y) << BITWIDTH_Z) | z if zero_padding: solution += '{0:0>2}'.format(boards[i]) # 2桁の0詰め else: solution += str(boards[i]) # 普通に表示 solution += '\n' 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 } def main(): parser = argparse.ArgumentParser(description="Solver with pynqrouter") # 入出力 parser.add_argument('-i', '--input', action='store', nargs='?', default=None, type=str, help='Path to input problem file') parser.add_argument('-b', '--boardstr', action='store', nargs='?', default=None, type=str, help='Problem boardstr (if you want to solve directly)') parser.add_argument('-o', '--output', action='store', nargs='?', default=None, type=str, help='Path to output answer file') # ソルバオプション parser.add_argument('-t', '--terminals', action='store', nargs='?', default='initial', type=str, help='Terminals order (initial, edgefirst, or random) (default: initial)') parser.add_argument('-s', '--seed', action='store', nargs='?', default=12345, type=int, help='Random seed') # 出力オプション parser.add_argument('-p', '--print', action='store_true', default=False, help='Enable to print the solution') parser.add_argument('-z', '--zero-padding', action='store_true', default=False, help='Enable to do zero-padding') args = parser.parse_args() if args.input is not None: # 問題ファイルの読み込み with open(args.input, 'r') as f: lines = f.readlines() # 問題ファイルを boardstr に変換 boardstr = BoardStr.conv_boardstr(lines, args.terminals, args.seed) elif args.boardstr is not None: boardstr = args.boardstr else: sys.stderr.write('Specify at least "input" or "boardstr"!\n') sys.exit(1) result = solve(boardstr, args.seed) if result['solved'] == False: sys.exit(1) # 表示 & ファイル出力 if args.print: print('') print('SOLUTION') print('========') print(result['solution']) if args.output is not None: with open(args.output, 'w') as f: f.write(result['solution']) def pack(_str): """ ボードストリング文字列をMMIOメモリにパックする """ _mem = [ 0 for _ in range(MAX_X * MAX_Y * MAX_Z // 4) ] for i in range(len(_str)): _index = i // 4; _offset = i % 4; if _offset == 0: _mem[_index] = _mem[_index] | (ord(_str[i])) elif _offset == 1: _mem[_index] = _mem[_index] | (ord(_str[i]) << 8) elif _offset == 2: _mem[_index] = _mem[_index] | (ord(_str[i]) << 16) elif _offset == 3: _mem[_index] = _mem[_index] | (ord(_str[i]) << 24) return _mem def unpack(_mem): """ MMIOメモリからボード情報をアンパックする """ _boards = [ 0 for _ in range(MAX_X * MAX_Y * MAX_Z) ] for i in range(len(_mem)): _boards[4 * i ] = (_mem[i]) & 255 _boards[4 * i + 1] = (_mem[i] >> 8) & 255 _boards[4 * i + 2] = (_mem[i] >> 16) & 255 _boards[4 * i + 3] = (_mem[i] >> 24) & 255 return _boards if __name__ == '__main__': main() Loading
comm/client/main.py +19 −60 Changes for comm/client/main.py: 19 added lines, 60 removed lines. Original line number Diff line number Diff line Loading @@ -17,65 +17,17 @@ from urllib.parse import urlparse sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../../solver') import BoardStr import pynqrouter import adc2018solver as pynqrouter app = Flask(__name__) args = {} pynq_thread = None # pynq_thread = None client_baseurl = "" # Reference: https://teratail.com/questions/52593 class StoppableThread(threading.Thread): def __init__(self, target, qname, qstr, qseed): super(StoppableThread, self).__init__(target=target) self._th_stop = threading.Event() self._qname = qname self._qstr = qstr self._qseed = int(qseed) self._answer = None def run(self): global client_baseurl global pynq_thread global args # Main funciton (the solver should be placed here) boardstr = BoardStr.conv_boardstr(self._qstr.split('\n'), 'random', self._qseed) result = pynqrouter.solve(boardstr, self._qseed) if result['solved']: answer = result['solution'] else: answer = None pynq_thread = None return res = { "client": client_baseurl, "qname": self._qname, "answer": answer, "cputime": result['elapsed'] } self._answer = answer r = requests.post("http://{}/post".format(args["host"]), data=res) if args["verbose"]: print(res) pynq_thread = None def stop(self): self._th_stop.set() def stopped(self): return self._th_stop.isSet() def get_answer(self): return self._answer @app.route('/start', methods=["POST"]) def start(): global pynq_thread # global pynq_thread global args global client_baseurl Loading @@ -84,13 +36,19 @@ def start(): if args["verbose"]: print(request.form) if pynq_thread is None: if pynqrouter.solver_thread is not None: pynqrouter.stop_solver() if pynqrouter.solver_thread is None: qstr = request.form["question"] qname = request.form["qname"] qseed = request.form["qseed"] pynq_thread = StoppableThread(target=StoppableThread, qname=qname, qstr=qstr, qseed=qseed) pynq_thread.start() boardstr = BoardStr.conv_boardstr(qstr.split('\n'), 'random', int(qseed)) option = {"name": qname, "host": args['host'], "client": client_baseurl} pynqrouter.start_solver(boardstr, qseed, option) # pynq_thread = pynqrouter.start_solver(boardstr, qseed, option) # 実行だけ開始する ans["status"] = "Processing" Loading @@ -106,26 +64,27 @@ def start(): @app.route('/stop') def stop(): global pynq_thread # global pynq_thread if pynq_thread is None: if pynqrouter.solver_thread is None: ans = {"status": "No threads"} else: pynq_thread.stop() # pynq_thread.stop() pynqrouter.stop_solver() ans = {"status": "Stopped"} pynq_thread = None # pynq_thread = None return json.dumps(ans) @app.route("/status") def status(): global pynq_thread # global pynq_thread res_mes = "" if pynq_thread is None: if pynqrouter.solver_thread is None: res_mes = "Ready" else: res_mes = "Working" Loading
solver/adc2018solver.py 0 → 100644 +267 −0 Changes for solver/adc2018solver.py: 267 added lines, 0 removed lines. Original line number Diff line number Diff line #!/opt/python3.6/bin/python3.6 # -*- coding: utf-8 -*- """ PYNQ 上で pynqrouter を実行する。 """ from pynq import Overlay from pynq import PL from pynq import MMIO import argparse import requests import sys import time import threading import BoardStr # Settings -- pynqrouter IP = 'SEG_pynqrouter_0_Reg' OFFSET_BOARD = 65536 # 0x10000 ~ 0x1ffff OFFSET_SEED = 131072 # 0x20000 OFFSET_STATUS = 131080 # 0x20008 MAX_X = 72 MAX_Y = 72 MAX_Z = 8 BITWIDTH_Z = 3 # Settings -- LED IP_LED = 'SEG_axi_gpio_0_Reg' solver_thread = None class StoppableThread(threading.Thread): def __init__(self, target, args=()): super(StoppableThread, self).__init__(target=target, args=args) self._status = 'running' def stop(self): if self._status == 'running': self._status = 'stopping' def stopped(self): self._status = 'stopped' def is_running(self): return (self._status == 'running') def is_stopping(self): return (self._status == 'stopping') def is_stopped(self): return (self._status == 'stopped') def start_solver(boardstr, seed, option): global solver_thread if solver_thread is None: solver_thread = StoppableThread(target=solve, args=(boardstr, int(seed), False, option)) solver_thread.start() def stop_solver(): global solver_thread if solver_thread is not None: if solver_thread.is_running(): solver_thread.stop() solver_thread.join() solver_thread = None def solve(boardstr, seed=12345, zero_padding=False, option=dict()): global solver_thread print('boardstr:') print(boardstr) print('seed:') print(seed) print('') # ボード文字列から X, Y, Z を読んでくる size_x = (ord(boardstr[1]) - ord('0')) * 10 + (ord(boardstr[2]) - ord('0')) size_y = (ord(boardstr[4]) - ord('0')) * 10 + (ord(boardstr[5]) - ord('0')) size_z = (ord(boardstr[7]) - ord('0')) # Overlay 読み込み OL = Overlay('pynqrouter_lines128_length256.bit') OL.download() print(OL.ip_dict) print('Overlay loaded!') # MMIO 接続 (pynqrouter) mmio = MMIO(int(PL.ip_dict[IP][0], 16), int(PL.ip_dict[IP][1], 16)) # MMIO 接続 & リセット (LED) mmio_led = MMIO(int(PL.ip_dict[IP_LED][0], 16), int(PL.ip_dict[IP_LED][1], 16)) mmio_led.write(0, 0) # 入力データをセット imem = pack(boardstr) for i in range(len(imem)): mmio.write(OFFSET_BOARD + (i * 4), imem[i]) mmio.write(OFFSET_SEED, seed) # スタート # ap_start (0 番地の 1 ビット目 = 1) mmio.write(0, 1) print('Start!') time_start = time.time() # ap_done (0 番地の 2 ビット目 = 2) が立つまで待ってもいいが # done は一瞬だけ立つだけのことがあるから # ap_idle (0 番地の 3 ビット目 = 4) を待ったほうが良い iteration = 0 while (mmio.read(0) & 4) == 0: # 動いてるっぽく見えるようにLチカさせる iteration += 1 if iteration == 10000: mmio_led.write(0, 3) elif 20000 <= iteration: mmio_led.write(0, 12) iteration = 0 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 } # 完了の確認 print('Done!') print('control:', mmio.read(0)) time_done = time.time() elapsed = time_done - time_start print('elapsed:', elapsed) print('') # 状態の取得 status = int(mmio.read(OFFSET_STATUS)) print('status:', status) if status != 0: # 解けなかったら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 } print('Solved!') # 解けたらLEDを全部つける mmio_led.write(0, 15) # 出力 omem = [] for i in range(len(imem)): omem.append(mmio.read(OFFSET_BOARD + (i * 4))) boards = unpack(omem) # 回答の生成 solution = ('SIZE ' + str(size_x) + 'X' + str(size_y) + 'X' + str(size_z) + '\n') for z in range(size_z): solution += ('LAYER ' + str(z + 1) + '\n') for y in range(size_y): for x in range(size_x): if x != 0: solution += ',' i = ((x * MAX_X + y) << BITWIDTH_Z) | z if zero_padding: solution += '{0:0>2}'.format(boards[i]) # 2桁の0詰め else: solution += str(boards[i]) # 普通に表示 solution += '\n' 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 } def main(): parser = argparse.ArgumentParser(description="Solver with pynqrouter") # 入出力 parser.add_argument('-i', '--input', action='store', nargs='?', default=None, type=str, help='Path to input problem file') parser.add_argument('-b', '--boardstr', action='store', nargs='?', default=None, type=str, help='Problem boardstr (if you want to solve directly)') parser.add_argument('-o', '--output', action='store', nargs='?', default=None, type=str, help='Path to output answer file') # ソルバオプション parser.add_argument('-t', '--terminals', action='store', nargs='?', default='initial', type=str, help='Terminals order (initial, edgefirst, or random) (default: initial)') parser.add_argument('-s', '--seed', action='store', nargs='?', default=12345, type=int, help='Random seed') # 出力オプション parser.add_argument('-p', '--print', action='store_true', default=False, help='Enable to print the solution') parser.add_argument('-z', '--zero-padding', action='store_true', default=False, help='Enable to do zero-padding') args = parser.parse_args() if args.input is not None: # 問題ファイルの読み込み with open(args.input, 'r') as f: lines = f.readlines() # 問題ファイルを boardstr に変換 boardstr = BoardStr.conv_boardstr(lines, args.terminals, args.seed) elif args.boardstr is not None: boardstr = args.boardstr else: sys.stderr.write('Specify at least "input" or "boardstr"!\n') sys.exit(1) result = solve(boardstr, args.seed) if result['solved'] == False: sys.exit(1) # 表示 & ファイル出力 if args.print: print('') print('SOLUTION') print('========') print(result['solution']) if args.output is not None: with open(args.output, 'w') as f: f.write(result['solution']) def pack(_str): """ ボードストリング文字列をMMIOメモリにパックする """ _mem = [ 0 for _ in range(MAX_X * MAX_Y * MAX_Z // 4) ] for i in range(len(_str)): _index = i // 4; _offset = i % 4; if _offset == 0: _mem[_index] = _mem[_index] | (ord(_str[i])) elif _offset == 1: _mem[_index] = _mem[_index] | (ord(_str[i]) << 8) elif _offset == 2: _mem[_index] = _mem[_index] | (ord(_str[i]) << 16) elif _offset == 3: _mem[_index] = _mem[_index] | (ord(_str[i]) << 24) return _mem def unpack(_mem): """ MMIOメモリからボード情報をアンパックする """ _boards = [ 0 for _ in range(MAX_X * MAX_Y * MAX_Z) ] for i in range(len(_mem)): _boards[4 * i ] = (_mem[i]) & 255 _boards[4 * i + 1] = (_mem[i] >> 8) & 255 _boards[4 * i + 2] = (_mem[i] >> 16) & 255 _boards[4 * i + 3] = (_mem[i] >> 24) & 255 return _boards if __name__ == '__main__': main()