205 lines
7.0 KiB
Python
205 lines
7.0 KiB
Python
#!/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"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==0:
|
|
args.num = len(creds_lines)
|
|
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
|
|
|
|
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)
|
|
if len(args.cwd) == 0:
|
|
working_dir = os.path.dirname(os.path.abspath(args.viewer))
|
|
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")
|
|
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}"
|
|
|
|
# Build 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:
|
|
print("opening viewer session with",script_cmd)
|
|
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,
|
|
default=0,
|
|
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="Lag Me 5",
|
|
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)
|