Skip to content
Snippets Groups Projects
Commit b3382719 authored by Callum Linden's avatar Callum Linden
Browse files

SL-16124 First pass at a Python3 script to launch multiple non-interactive...

SL-16124 First pass at a Python3 script to launch multiple non-interactive Viewers with differing command line options
parent f3743b8e
No related branches found
No related tags found
1 merge request!83Merge Linden 6.6.7
#!/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)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment