From b3382719adbc3f695f5838bd496c990ea5edf94f Mon Sep 17 00:00:00 2001 From: Callum Linden Date: Fri, 1 Oct 2021 12:33:37 -0700 Subject: SL-16124 First pass at a Python3 script to launch multiple non-interactive Viewers with differing command line options --- scripts/perf/perfbot_run.py | 197 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 scripts/perf/perfbot_run.py (limited to 'scripts') diff --git a/scripts/perf/perfbot_run.py b/scripts/perf/perfbot_run.py new file mode 100644 index 0000000000..49d2002135 --- /dev/null +++ b/scripts/perf/perfbot_run.py @@ -0,0 +1,197 @@ +#!/usr/bin/env python3 +"""\ +@file perfbot_run.py +@brief Run a number of non interactive Viewers (PerfBots) with + a variety of options and settings. Pass --help for details. + +$LicenseInfo:firstyear=2007&license=viewerlgpl$ +Second Life Viewer Source Code +Copyright (C) 2021, Linden Research, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; +version 2.1 of the License only. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +$/LicenseInfo$ +""" + +import argparse +import subprocess +import os +import math +import time + +# Required parameters that are always passed in +# Specify noninteractive mode (SL-15999 for details) +PARAM_NON_INTERACTIVE = "--noninteractive" +# Run multiple Viewers at once +PARAM_MULTI = "--multiple" +# Specify username (first and last) and password +PARAM_LOGIN = "--login" +# SLURL to teleport to after login +PARAM_SLURL = "--slurl" + + +def gen_niv_script(args): + print(f"Launching {(args.num)} instances of the Viewer") + print(f"Reading creds from {(args.creds)} folder") + print(f"Using the non interactive Viewer from {(args.viewer)}") + print(f"Sleeping for {args.sleep}ms between Viewer launches") + + # Read the lines from the creds file. Typically this will be + # stored in the build-secrets-git private repository but you + # can point to any location with the --creds parameter + creds_lines = [] + with open(args.creds) as file: + creds_lines = file.readlines() + creds_lines = [line.rstrip() for line in creds_lines] + creds_lines = [line for line in creds_lines if not line.startswith("#") and len(line)] + # We cannot log in more users than we have credentials for + if args.num > len(creds_lines): + print( + f"The number of agents specified ({(args.num)}) exceeds " + f"the number of valid entries ({(len(creds_lines))}) in " + f"the creds file " + ) + return + # The Viewer (in dev environments at least) needs a well specified + # working directory to function properly. We try to guess what it + # might be based on the full path to the Viewer executable but + # you can also specify it explicitly with the --cwd parameter + # (required for dev builds) + working_dir = args.cwd + if len(args.cwd) == 0: + working_dir = os.path.dirname(os.path.abspath(args.viewer)) + print(f"Working directory is {working_dir}") + os.chdir(working_dir) + + if args.dryrun: + print("Ruuning in dry-run mode - no Viewers will be started") + print("") + + for inst in range(args.num): + + # Format of each cred line is username_first username_last password + # A space is used to separate each and a # at the start of a line + # removes it from the pool (useful if someone else is using a subset + # of the available ones) + creds = creds_lines[inst].split(" ") + username_first = creds[0] + username_last = creds[1] + password = creds[2] + + # The default layout is an evenly spaced circle in the + # center of the region. We may extend this to allow other + # patterns like a square/rectangle or a spiral. (Hint: it + # likely won't be needed :)) + center_x = 128 + center_y = 128 + if args.layout == "circle": + radius = 6 + angle = (2 * math.pi / args.num) * inst + region_x = int(math.sin(angle) * radius + center_x) + region_y = int(math.cos(angle) * radius + center_y) + region_z = 0 + elif args.layout == "square": + region_x = center_x + region_y = center_y + elif args.layout == "spiral": + region_x = center_x + region_y = center_y + slurl = f"secondlife://{args.region}/{region_x}/{region_y}/{region_z}" + + # Buold the script line + script_cmd = [args.viewer] + script_cmd.append(PARAM_NON_INTERACTIVE) + script_cmd.append(PARAM_MULTI) + script_cmd.append(PARAM_LOGIN) + script_cmd.append(username_first) + script_cmd.append(username_last) + script_cmd.append(password) + script_cmd.append(PARAM_SLURL) + script_cmd.append(slurl) + + # Display the script we will execute. + cmd = "" + for p in script_cmd: + cmd = cmd + " " + p + print(cmd) + + # If --dry-run is specified, we do everything (including, most + # usefully, display the script lines) but do not start the Viewer + if args.dryrun == False: + viewer_session = subprocess.Popen(script_cmd) + + # Sleeping a bit between launches seems to help avoid a CPU + # surge when N Viewers are started simulatanously. The default + # value can be changed with the --sleep parameter + time.sleep(args.sleep / 1000) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(allow_abbrev=False) + parser.add_argument( + "--num", + type=int, + required=True, + dest="num", + help="How many avatars to add to the script", + ) + parser.add_argument( + "--creds", + default="../../../build-secrets-git/perf/perfbot_creds.txt", + dest="creds", + help="Location of the text file containing user credentials", + ) + parser.add_argument( + "--viewer", + default="C:/Program Files/SecondLife/SecondLifeViewer.exe", + dest="viewer", + help="Location of the non interactive Viewer build", + ) + parser.add_argument( + "--cwd", + default="", + dest="cwd", + help="Location of the current working directory to use", + ) + parser.add_argument( + "--region", + default="Sandbox Cordova", + dest="region", + help="The SLURL for the Second Life region to visit", + ) + parser.add_argument( + "--layout", + default="circle", + dest="layout", + choices={"circle", "square", "spiral"}, + help="The geometric layout of the avatar destination locations", + ) + parser.add_argument( + "--sleep", + type=int, + default=1000, + dest="sleep", + help="Time to sleep between launches in milliseconds", + ) + parser.add_argument( + "--dry-run", + action="store_true", + dest="dryrun", + help="Dryrun mode - display parameters and script lines but do not start any Viewers", + ) + args = parser.parse_args() + + gen_niv_script(args) -- cgit v1.2.3 From 23ec0fb50ce0f7723e13a5ec5cf8694f3b5a7e06 Mon Sep 17 00:00:00 2001 From: Callum Linden Date: Fri, 1 Oct 2021 15:22:22 -0700 Subject: SL-16124 - switch default region to Lag Me 5 now that it is set up and working --- scripts/perf/perfbot_run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/perf/perfbot_run.py b/scripts/perf/perfbot_run.py index 49d2002135..993c60be74 100644 --- a/scripts/perf/perfbot_run.py +++ b/scripts/perf/perfbot_run.py @@ -168,7 +168,7 @@ if __name__ == "__main__": ) parser.add_argument( "--region", - default="Sandbox Cordova", + default="Lag Me 5", dest="region", help="The SLURL for the Second Life region to visit", ) -- cgit v1.2.3 From 910daee8887b41619b07a1e5c4431f77c095dac5 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Thu, 21 Oct 2021 14:31:03 +0100 Subject: SL-15999 - perfbot allow --num to default to number of creds --- scripts/perf/perfbot_run.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'scripts') diff --git a/scripts/perf/perfbot_run.py b/scripts/perf/perfbot_run.py index 993c60be74..4219b7bcda 100644 --- a/scripts/perf/perfbot_run.py +++ b/scripts/perf/perfbot_run.py @@ -44,7 +44,6 @@ PARAM_SLURL = "--slurl" def gen_niv_script(args): - print(f"Launching {(args.num)} instances of the Viewer") print(f"Reading creds from {(args.creds)} folder") print(f"Using the non interactive Viewer from {(args.viewer)}") print(f"Sleeping for {args.sleep}ms between Viewer launches") @@ -58,6 +57,8 @@ def gen_niv_script(args): creds_lines = [line.rstrip() for line in creds_lines] creds_lines = [line for line in creds_lines if not line.startswith("#") and len(line)] # We cannot log in more users than we have credentials for + if args.num==0: + args.num = len(creds_lines) if args.num > len(creds_lines): print( f"The number of agents specified ({(args.num)}) exceeds " @@ -65,19 +66,24 @@ def gen_niv_script(args): f"the creds file " ) return + + print(f"Launching {(args.num)} instances of the Viewer") + # The Viewer (in dev environments at least) needs a well specified # working directory to function properly. We try to guess what it # might be based on the full path to the Viewer executable but # you can also specify it explicitly with the --cwd parameter # (required for dev builds) + args.viewer = os.path.abspath(args.viewer) working_dir = args.cwd if len(args.cwd) == 0: working_dir = os.path.dirname(os.path.abspath(args.viewer)) print(f"Working directory is {working_dir}") - os.chdir(working_dir) + environ = os.environ + environ["cwd"] = working_dir if args.dryrun: - print("Ruuning in dry-run mode - no Viewers will be started") + print("Running in dry-run mode - no Viewers will be started") print("") for inst in range(args.num): @@ -111,7 +117,7 @@ def gen_niv_script(args): region_y = center_y slurl = f"secondlife://{args.region}/{region_x}/{region_y}/{region_z}" - # Buold the script line + # Build the script line script_cmd = [args.viewer] script_cmd.append(PARAM_NON_INTERACTIVE) script_cmd.append(PARAM_MULTI) @@ -131,7 +137,8 @@ def gen_niv_script(args): # If --dry-run is specified, we do everything (including, most # usefully, display the script lines) but do not start the Viewer if args.dryrun == False: - viewer_session = subprocess.Popen(script_cmd) + print("opening viewer session with",script_cmd) + viewer_session = subprocess.Popen(script_cmd,env=environ) # Sleeping a bit between launches seems to help avoid a CPU # surge when N Viewers are started simulatanously. The default @@ -144,7 +151,7 @@ if __name__ == "__main__": parser.add_argument( "--num", type=int, - required=True, + default=0, dest="num", help="How many avatars to add to the script", ) -- cgit v1.2.3 From a42b5d680935f08310de69f240435a7b67227a4d Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Fri, 22 Oct 2021 18:49:54 +0100 Subject: SL-15999 - made cwd handling a bit more robust in perfbot_run.py --- scripts/perf/perfbot_run.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'scripts') diff --git a/scripts/perf/perfbot_run.py b/scripts/perf/perfbot_run.py index 006d5f8934..55ea2fae66 100644 --- a/scripts/perf/perfbot_run.py +++ b/scripts/perf/perfbot_run.py @@ -75,12 +75,12 @@ def gen_niv_script(args): # you can also specify it explicitly with the --cwd parameter # (required for dev builds) args.viewer = os.path.abspath(args.viewer) - working_dir = args.cwd if len(args.cwd) == 0: working_dir = os.path.dirname(os.path.abspath(args.viewer)) - print(f"Working directory is {working_dir} {args.cwd=}") - environ = os.environ - environ["cwd"] = working_dir + else: + working_dir = os.path.abspath(args.cwd) + print(f"Working directory is {working_dir}, cwd {args.cwd}") + os.chdir(working_dir) if args.dryrun: print("Running in dry-run mode - no Viewers will be started") @@ -138,7 +138,7 @@ def gen_niv_script(args): # usefully, display the script lines) but do not start the Viewer if args.dryrun == False: print("opening viewer session with",script_cmd) - viewer_session = subprocess.Popen(script_cmd,env=environ) + viewer_session = subprocess.Popen(script_cmd) # Sleeping a bit between launches seems to help avoid a CPU # surge when N Viewers are started simulatanously. The default -- cgit v1.2.3