#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # AWL simulator - Client interface # # Copyright 2013-2019 Michael Buesch # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # from __future__ import division, absolute_import, print_function, unicode_literals import sys import getopt from awlsim_loader.common import * from awlsim_loader.coreclient import * def printCpuStats(cpuStatsMsg): if not cpuStatsMsg: print("Failed to fetch CPU statistics.") return if cpuStatsMsg.insnPerSecond > 0.0: insnPerSecondStr = floatToHumanReadable(cpuStatsMsg.insnPerSecond) usPerInsnStr = "%.03f" % ((1.0 / cpuStatsMsg.insnPerSecond) * 1000000.0) else: insnPerSecondStr = "-/-" usPerInsnStr = "-/-" if (cpuStatsMsg.avgCycleTime <= 0.0 or cpuStatsMsg.minCycleTime <= 0.0 or cpuStatsMsg.maxCycleTime <= 0.0): avgCycleTimeStr = minCycleTimeStr = maxCycleTimeStr = "-/-" else: avgCycleTimeStr = "%.03f" % (cpuStatsMsg.avgCycleTime * 1000.0) minCycleTimeStr = "%.03f" % (cpuStatsMsg.minCycleTime * 1000.0) maxCycleTimeStr = "%.03f" % (cpuStatsMsg.maxCycleTime * 1000.0) if cpuStatsMsg.running: print("CPU RUN %.01f s (system uptime %.01f s)" % ( cpuStatsMsg.runtime, cpuStatsMsg.uptime)) else: print("CPU STOP (system uptime %.01f s)" % ( cpuStatsMsg.uptime)) print(" OB1: avg: %s ms min: %s ms max: %s ms" % ( avgCycleTimeStr, minCycleTimeStr, maxCycleTimeStr)) print(" Speed: %s stmt/s (= %s us/stmt) %.01f stmt/cycle" % ( insnPerSecondStr, usPerInsnStr, cpuStatsMsg.insnPerCycle)) class TextInterfaceAwlSimClient(AwlSimClient): pass def usage(): print("awlsim-client version %s" % VERSION_STRING) print("") print("Usage: awlsim-client [OPTIONS] ") print("") print("Options:") print(" -c|--connect HOST[:PORT] Connect to the server at HOST:PORT") print(" Defaults to %s:%d" % ( AwlSimServer.DEFAULT_HOST, AwlSimServer.DEFAULT_PORT)) print(" -t|--timeout 10.0 Set the connection timeout (default 10 s)") print(" -L|--loglevel LVL Set the client log level:") print(" 0: Log nothing") print(" 1: Log errors") print(" 2: Log errors and warnings (default)") print(" 3: Log errors, warnings and info messages") print(" 4: Verbose logging") print(" 5: Extremely verbose logging") print("") print(" -s|--ssh-tunnel Establish the connection via SSH tunnel.") print(" -P|--ssh-passphrase XYZ Use XYZ as SSH passphrase.") print(" Default: Ask user.") print(" --ssh-user %s SSH user. Default: %s" % ( SSHTunnel.SSH_DEFAULT_USER, SSHTunnel.SSH_DEFAULT_USER)) print(" --ssh-port %s SSH port. Default: %s" % ( SSHTunnel.SSH_PORT, SSHTunnel.SSH_PORT)) print(" --ssh-localport auto SSH localport number or 'auto'.") print(" --ssh-exe %s SSH client executable path. Default: %s" % ( SSHTunnel.SSH_DEFAULT_EXECUTABLE, SSHTunnel.SSH_DEFAULT_EXECUTABLE)) print("") print("Actions to be performed on the server:") print(" -r|--runstate RUN/STOP Set the run state of the CPU.") print(" -S|--stats Fetch and display CPU statistics.") print(" --meas-start Start instruction time measurements.") print(" --meas-stop Stop instruction time measurements.") print(" --shutdown Shutdown the core server system.") print(" --reboot Reboot the core server system.") def main(): opt_connect = (AwlSimServer.DEFAULT_HOST, AwlSimServer.DEFAULT_PORT) opt_timeout = 10.0 opt_loglevel = Logging.LOG_WARNING opt_sshTunnel = False opt_sshPassphrase = None opt_sshUser = SSHTunnel.SSH_DEFAULT_USER opt_sshPort = SSHTunnel.SSH_PORT opt_sshLocalPort = None opt_sshExe = SSHTunnel.SSH_DEFAULT_EXECUTABLE actions = [] try: (opts, args) = getopt.getopt(sys.argv[1:], "hc:t:L:sP:r:S", [ "help", "connect=", "timeout=", "loglevel=", "ssh-tunnel", "ssh-passphrase=", "ssh-user=", "ssh-port=", "ssh-localport=", "ssh-exe=", "runstate=", "stats", "meas-start", "meas-stop", "shutdown", "reboot", ]) except getopt.GetoptError as e: printError(str(e)) usage() return ExitCodes.EXIT_ERR_CMDLINE for (o, v) in opts: if o in ("-h", "--help"): usage() return ExitCodes.EXIT_OK if o in ("-c", "--connect"): try: host, port = parseNetAddress(v) if port is None: port = AwlSimServer.DEFAULT_PORT opt_connect = (host, port) except AwlSimError as e: printError("-c|--connect: %s" % e.message) sys.exit(1) if o in ("-t", "--timeout"): try: opt_timeout = float(v) except ValueError: printError("-t|--timeout: Invalid timeout value") sys.exit(1) if o in ("-L", "--loglevel"): try: opt_loglevel = int(v) except ValueError: printError("-L|--loglevel: Invalid log level") sys.exit(1) if o in ("-s", "--ssh-tunnel"): opt_sshTunnel = True if o in ("-P", "--ssh-passphrase"): opt_sshPassphrase = v if o == "--ssh-user": opt_sshUser = v if o == "--ssh-port": try: opt_sshPort = int(v) except ValueError: printError("--ssh-port: Invalid port number") sys.exit(1) if o == "--ssh-localport": try: if v.lower().strip() == "auto": opt_sshLocalPort = None else: opt_sshLocalPort = int(v) except ValueError: printError("--ssh-localport: Invalid port number") sys.exit(1) if o == "--ssh-exe": opt_sshExe = v if o in ("-r", "--runstate"): if v.upper().strip() in ("RUN", "1", "START"): actions.append(("runstate", True)) elif v.upper().strip() in ("STOP", "0"): actions.append(("runstate", False)) else: printError("-r|--runstate: Invalid run state") sys.exit(1) if o in ("-S", "--stats"): actions.append(("stats", None)) if o == "--meas-start": actions.append(("meas-start", None)) if o == "--meas-stop": actions.append(("meas-stop", None)) if o == "--shutdown": actions.append(("shutdown", None)) if o == "--reboot": actions.append(("reboot", None)) if args: usage() return ExitCodes.EXIT_ERR_CMDLINE if not actions: usage() return ExitCodes.EXIT_ERR_CMDLINE client = None try: Logging.setLoglevel(opt_loglevel) host, port = opt_connect if opt_sshTunnel: printInfo("Establishing SSH tunnel...") tunnel = SSHTunnel( remoteHost=host, remotePort=port, localPort=opt_sshLocalPort, sshUser=opt_sshUser, sshPort=opt_sshPort, sshExecutable=opt_sshExe, sshPassphrase=opt_sshPassphrase ) host, port = tunnel.connect() client = TextInterfaceAwlSimClient() client.connectToServer(host=host, port=port, timeout=opt_timeout) for action, actionValue in actions: if action == "runstate": client.setRunState(actionValue) elif action == "stats": printCpuStats(client.getCpuStats(sync=True)) elif action == "meas-start": if not client.measStart(): printError("Failed to start measurements.") elif action == "meas-stop": reportData = client.measStop() if reportData: sys.stdout.write(reportData) sys.stdout.flush() else: printError("Measurement failed. No data.") elif action == "shutdown": client.shutdownCoreServerSystem() elif action == "reboot": client.rebootCoreServerSystem() else: assert(0) except AwlSimError as e: printError(e.getReport()) return ExitCodes.EXIT_ERR_SIM finally: if client: client.shutdown() return ExitCodes.EXIT_OK if __name__ == "__main__": sys.exit(main())