diff options
Diffstat (limited to 'scripts')
| -rw-r--r-- | scripts/perf/perfbot_run.py | 204 | 
1 files changed, 204 insertions, 0 deletions
diff --git a/scripts/perf/perfbot_run.py b/scripts/perf/perfbot_run.py new file mode 100644 index 0000000000..006d5f8934 --- /dev/null +++ b/scripts/perf/perfbot_run.py @@ -0,0 +1,204 @@ +#!/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) +    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  + +    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,env=environ) + +        # 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)  | 
