示例#1
0
    def run(self):
        """
        Run the load test.
        """

        if self.settings.run_time:
            self.set_run_time_in_sec(run_time_str=self.settings.run_time)

            logger.info("Run time limit set to %s seconds" %
                        self.run_time_in_sec)

            def timelimit_stop():
                logger.info(
                    "Run time limit reached: %s seconds. Stopping Locust Runner."
                    % self.run_time_in_sec)
                self.env.runner.quit()
                self.end_time = time.time()
                logger.info("Locust completed %s requests with %s errors" %
                            (self.env.runner.stats.num_requests,
                             len(self.env.runner.errors)))
                logger.info(json.dumps(self.stats()))

            gevent.spawn_later(self.run_time_in_sec, timelimit_stop)

        try:
            logger.info("Starting Locust with settings %s " %
                        vars(self.settings))

            self.env = Environment(
                user_classes=self.settings.classes,
                host=self.settings.host,
                tags=self.settings.tags,
                exclude_tags=self.settings.exclude_tags,
                reset_stats=self.settings.reset_stats,
                step_load=self.settings.step_load,
                stop_timeout=self.settings.stop_timeout,
            )

            self.env.create_local_runner()
            gevent.spawn(stats_printer(self.env.stats))

            self.env.runner.start(user_count=self.settings.num_users,
                                  hatch_rate=self.settings.hatch_rate)

            self.start_time = time.time()
            self.env.runner.greenlet.join()

        except Exception as e:
            logger.error("Locust exception {0}".format(repr(e)))

        finally:
            self.env.events.quitting.fire()
示例#2
0
def locust_executor(host,
                    port,
                    collection_name,
                    connection_type="single",
                    run_params=None):
    m = MilvusClient(host=host, port=port, collection_name=collection_name)
    MyUser.tasks = {}
    MyUser.op_info = run_params["op_info"]
    MyUser.params = {}
    tasks = run_params["tasks"]
    for op, value in tasks.items():
        task = {eval("Tasks." + op): value["weight"]}
        MyUser.tasks.update(task)
        MyUser.params[op] = value["params"] if "params" in value else None
    logger.info(MyUser.tasks)

    MyUser.tasks = {Tasks.load: 1, Tasks.flush: 1}
    MyUser.client = MilvusTask(host=host,
                               port=port,
                               collection_name=collection_name,
                               connection_type=connection_type,
                               m=m)
    # MyUser.info = m.get_info(collection_name)
    env = Environment(events=events, user_classes=[MyUser])

    runner = env.create_local_runner()
    # setup logging
    # setup_logging("WARNING", "/dev/null")
    # greenlet_exception_logger(logger=logger)
    gevent.spawn(stats_printer(env.stats))
    # env.create_web_ui("127.0.0.1", 8089)
    # gevent.spawn(stats_printer(env.stats), env, "test", full_history=True)
    # events.init.fire(environment=env, runner=runner)
    clients_num = run_params["clients_num"]
    spawn_rate = run_params["spawn_rate"]
    during_time = run_params["during_time"]
    runner.start(clients_num, spawn_rate=spawn_rate)
    gevent.spawn_later(during_time, lambda: runner.quit())
    runner.greenlet.join()
    print_stats(env.stats)
    result = {
        "rps": round(env.stats.total.current_rps, 1),
        "fail_ratio": env.stats.total.fail_ratio,
        "max_response_time": round(env.stats.total.max_response_time, 1),
        "avg_response_time": round(env.stats.total.avg_response_time, 1)
    }
    runner.stop()
    return result
示例#3
0
def web_ui():
    env.create_web_ui("127.0.0.1", 8089)

    # start a greenlet that periodically outputs the current stats
    gevent.spawn(stats_printer(env.stats))

    # start a greenlet that save current stats to history
    gevent.spawn(stats_history, env.runner)

    # start the test
    env.runner.start(1, spawn_rate=10)

    # in 60 seconds stop the runner
    gevent.spawn_later(30, lambda: env.runner.quit())

    # wait for the greenlets
    env.runner.greenlet.join()

    # stop the web server for good measures
    env.web_ui.stop()
def run_locust(test_file=None, directory=None, profile=None):
    from locust.env import Environment
    from locust.stats import stats_printer
    import gevent

    env = Environment(user_classes=[DocStorageUser])
    env.create_local_runner()
    setattr(env, "source_file", test_file or SOURCE_FILE)
    setattr(env, "working_directory", directory or WORKING_DIRECTORY)
    setattr(env, "aws_profile", profile)
    env.runner.start(CONCURRENT_USERS, hatch_rate=1)
    env.runner.greenlet.join()

    # start a greenlet that periodically outputs the current stats
    gevent.spawn(stats_printer(env.stats))

    # in 60 seconds stop the runner
    gevent.spawn_later(60, lambda: env.runner.quit())

    # wait for the greenlets
    env.runner.greenlet.join()
示例#5
0
文件: bench.py 项目: fsaez/pidotapi
def locust_run(c, r, t, base, path, webui):
    class User(HttpUser):
        wait_time = constant(1)
        host = base

        @task
        def my_task(self):
            self.client.get(path)

    env = Environment(user_classes=[User])
    env.create_local_runner()
    if webui:
        env.create_web_ui("127.0.0.1", 8089)
        webbrowser.open('http://127.0.0.1:8089')
    gevent.spawn(stats_printer(env.stats))
    gevent.spawn(stats_history, env.runner)
    env.runner.start(c, spawn_rate=c)
    gevent.spawn_later(t, lambda: env.runner.quit())
    env.runner.greenlet.join()
    if webui:
        env.web_ui.stop()
示例#6
0
    class task_set(TaskSet):
        @task
        def my_task(self):
            self.client.get("/")

        @task
        def task_404(self):
            self.client.get("/non-existing-path")


# setup Environment and Runner
env = Environment()
runner = LocalLocustRunner(environment=env, locust_classes=[User])
# start a WebUI instance
web_ui = WebUI(environment=env)
gevent.spawn(lambda: web_ui.start("127.0.0.1", 8089))

# TODO: fix
#def on_request_success(request_type, name, response_time, response_length, **kwargs):
#    report_to_grafana("%_%s" % (request_type, name), response_time)
#env.events.request_succes.add_listener(on_request_success)

# start a greenlet that periodically outputs the current stats
gevent.spawn(stats_printer(runner.stats))

# start the test
runner.start(1, hatch_rate=10)
# wait for the greenlets (indefinitely)
runner.greenlet.join()
示例#7
0
        self.client.get("/non-existing-path")

    @task
    def my_task(self):
        self.client.get("/api/Url/1")


# setup Environment and Runner
env = Environment(user_classes=[User])
env.create_local_runner()

# start a WebUI instance
env.create_web_ui("127.0.0.1", 8089)

# start a greenlet that periodically outputs the current stats
gevent.spawn(stats_printer(env.stats))

# start a greenlet that save current stats to history
gevent.spawn(stats_history, env.runner)

# start the test
env.runner.start(1, spawn_rate=100)

# in 60 seconds stop the runner
gevent.spawn_later(60, lambda: env.runner.quit())

# wait for the greenlets
env.runner.greenlet.join()

# stop the web server for good measures
env.web_ui.stop()
示例#8
0
def locust_executor(host,
                    port,
                    collection_name,
                    connection_type="single",
                    run_params=None):
    m = MilvusClient(host=host, port=port, collection_name=collection_name)
    MyUser.tasks = {}
    MyUser.op_info = run_params["op_info"]
    MyUser.params = {}
    tasks = run_params["tasks"]
    for op, value in tasks.items():
        task = {eval("Tasks." + op): value["weight"]}
        MyUser.tasks.update(task)
        MyUser.params[op] = value["params"] if "params" in value else None
    logger.info(MyUser.tasks)
    MyUser.values = {
        "ids": [random.randint(1000000, 10000000) for _ in range(nb)],
        "get_ids": [random.randint(1, 10000000) for _ in range(nb)],
        "X": utils.generate_vectors(nq, MyUser.op_info["dimension"])
    }

    # MyUser.tasks = {Tasks.query: 1, Tasks.flush: 1}
    MyUser.client = MilvusTask(host=host,
                               port=port,
                               collection_name=collection_name,
                               connection_type=connection_type,
                               m=m)
    if "load_shape" in run_params and run_params["load_shape"]:
        test = StepLoadShape()
        test.init(run_params["step_time"], run_params["step_load"],
                  run_params["spawn_rate"], run_params["during_time"])
        env = Environment(events=events,
                          user_classes=[MyUser],
                          shape_class=test)
        runner = env.create_local_runner()
        env.runner.start_shape()
    else:
        env = Environment(events=events, user_classes=[MyUser])
        runner = env.create_local_runner()
    # setup logging
    # setup_logging("WARNING", "/dev/null")
    # greenlet_exception_logger(logger=logger)
    gevent.spawn(stats_printer(env.stats))
    # env.create_web_ui("127.0.0.1", 8089)
    # gevent.spawn(stats_printer(env.stats), env, "test", full_history=True)
    # events.init.fire(environment=env, runner=runner)
    clients_num = run_params[
        "clients_num"] if "clients_num" in run_params else 0
    step_load = run_params["step_load"] if "step_load" in run_params else 0
    step_time = run_params["step_time"] if "step_time" in run_params else 0
    spawn_rate = run_params["spawn_rate"]
    during_time = run_params["during_time"]
    runner.start(clients_num, spawn_rate=spawn_rate)
    gevent.spawn_later(during_time, lambda: runner.quit())
    runner.greenlet.join()
    print_stats(env.stats)
    result = {
        "rps": round(env.stats.total.current_rps,
                     1),  # Number of interface requests per second
        "fail_ratio":
        env.stats.total.fail_ratio,  # Interface request failure rate
        "max_response_time": round(env.stats.total.max_response_time,
                                   1),  # Maximum interface response time
        "avg_response_time": round(env.stats.total.avg_response_time,
                                   1)  # ratio of average response time
    }
    runner.stop()
    return result
示例#9
0
def main(nosave, fault_profile, measurement_count, load_duration,
         locust_user_count, locust_spawn_rate, cluster_type, comment):

    check_working_dir()

    # Save the start time of the measurement sequence
    start_time = datetime.now().strftime("%m-%d-%Y_%H-%M-%S.%f")

    # lint helm chart
    try:
        logging.info('Linting Helm chart...')
        subprocess.check_output(['helm', 'lint', '../charts/kubedepend-chaos'])
        logging.info('Linting Helm chart finished OK')
    except subprocess.CalledProcessError as error:
        logging.error('Helm lint failed, exiting...')
        exit()

    # assembling helm value options according to fault profile
    helm_value_sets = assemble_helm_set_options(fault_profile)

    # filter out emtpy strings
    helm_command = [x for x in HELM_COMMAND_FIX_PART + helm_value_sets if x]

    # Save current stack into archive
    if not nosave:
        save_helm_chart(helm_command=helm_command)
        archive_stack(start_time)

    sequence_result = MeasurementSequenceResult(
        start_time=start_time,
        fault_profile=fault_profile,
        cluster_type=cluster_type,
        load_duration=load_duration,
        locust_user_count=locust_user_count,
        locust_spawn_rate=locust_spawn_rate,
        comment=comment)

    for i in range(measurement_count):

        logging.info(f'Start measurement #{i + 1}')

        logging.info('Waiting for stable system state...')
        wait_for_stable_state()

        # Initialize measurement result
        measurement_result = MeasurementResult()

        # Setup Locust objects

        # setup Environment and Runner
        env = Environment(user_classes=[User])
        env.create_local_runner()

        # start a greenlet that periodically outputs the current stats
        gevent.spawn(stats_printer(env.stats))

        # start a greenlet that save current stats to history
        gevent.spawn(stats_history, env.runner)

        logging.info('Creating chaos objects...')

        subprocess.run(helm_command)

        logging.info('Chaos objects applied.')

        logging.info('Generating load...')

        # start the test
        env.runner.start(user_count=locust_user_count,
                         spawn_rate=locust_spawn_rate)

        # in 'duartion' seconds stop the runner
        gevent.spawn_later(load_duration, lambda: env.runner.quit())

        # wait for the greenlets
        env.runner.greenlet.join()

        logging.info('Load generation finished')

        # get dependability metrics

        metrics = get_dependability_metrics(load_duration)

        # add metrics to measurement result
        measurement_result.backend_metrics = metrics
        # end measurement (fill end_time attribute)
        measurement_result.end()
        # add measurement result to sequence result
        sequence_result.add_measurement_result(measurement_result)

        # save dependability metrics

        logging.info('Deleting chaos objects...')

        subprocess.run(
            ['helm', 'delete', 'kubedepend-chaos', '-n', 'chaos-testing'])

        logging.info('Chaos objects deleted.')

    if not nosave:
        sequence_result.save_results('results/results.csv')

    # TODO stop running greenlets (stats)

    logging.info('Test finished')
示例#10
0
def main():
    # find specified locustfile and make sure it exists, using a very simplified
    # command line parser that is only used to parse the -f option
    locustfile = parse_locustfile_option()

    # import the locustfile
    docstring, user_classes, shape_class = load_locustfile(locustfile)

    # parse all command line options
    options = parse_options()

    if options.slave or options.expect_slaves:
        sys.stderr.write(
            "The --slave/--expect-slaves parameters have been renamed --worker/--expect-workers\n"
        )
        sys.exit(1)

    if options.hatch_rate:
        sys.stderr.write(
            "[DEPRECATED] The --hatch-rate parameter has been renamed --spawn-rate\n"
        )
        options.spawn_rate = options.hatch_rate

    # setup logging
    if not options.skip_log_setup:
        if options.loglevel.upper() in [
                "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"
        ]:
            setup_logging(options.loglevel, options.logfile)
        else:
            sys.stderr.write(
                "Invalid --loglevel. Valid values are: DEBUG/INFO/WARNING/ERROR/CRITICAL\n"
            )
            sys.exit(1)

    logger = logging.getLogger(__name__)
    greenlet_exception_handler = greenlet_exception_logger(logger)

    if options.list_commands:
        print("Available Users:")
        for name in user_classes:
            print("    " + name)
        sys.exit(0)

    if not user_classes:
        logger.error("No User class found!")
        sys.exit(1)

    # make sure specified User exists
    if options.user_classes:
        missing = set(options.user_classes) - set(user_classes.keys())
        if missing:
            logger.error("Unknown User(s): %s\n" % (", ".join(missing)))
            sys.exit(1)
        else:
            names = set(options.user_classes) & set(user_classes.keys())
            user_classes = [user_classes[n] for n in names]
    else:
        # list() call is needed to consume the dict_view object in Python 3
        user_classes = list(user_classes.values())

    try:
        import resource
        if resource.getrlimit(resource.RLIMIT_NOFILE)[0] < 10000:
            # Increasing the limit to 10000 within a running process should work on at least MacOS.
            # It does not work on all OS:es, but we should be no worse off for trying.
            resource.setrlimit(resource.RLIMIT_NOFILE,
                               [10000, resource.RLIM_INFINITY])
    except:
        logger.warning(
            "System open file limit setting is not high enough for load testing, and the OS didn't allow locust to increase it by itself. See https://github.com/locustio/locust/wiki/Installation#increasing-maximum-number-of-open-files-limit for more info."
        )

    # create locust Environment
    environment = create_environment(user_classes,
                                     options,
                                     events=locust.events,
                                     shape_class=shape_class)

    if shape_class and (options.num_users or options.spawn_rate
                        or options.step_load):
        logger.error(
            "The specified locustfile contains a shape class but a conflicting argument was specified: users, spawn-rate or step-load"
        )
        sys.exit(1)

    if options.show_task_ratio:
        print("\n Task ratio per User class")
        print("-" * 80)
        print_task_ratio(user_classes)
        print("\n Total task ratio")
        print("-" * 80)
        print_task_ratio(user_classes, total=True)
        sys.exit(0)
    if options.show_task_ratio_json:
        from json import dumps
        task_data = {
            "per_class": get_task_ratio_dict(user_classes),
            "total": get_task_ratio_dict(user_classes, total=True)
        }
        print(dumps(task_data))
        sys.exit(0)

    if options.step_time:
        if not options.step_load:
            logger.error(
                "The --step-time argument can only be used together with --step-load"
            )
            sys.exit(1)
        if options.worker:
            logger.error(
                "--step-time should be specified on the master node, and not on worker nodes"
            )
            sys.exit(1)
        try:
            options.step_time = parse_timespan(options.step_time)
        except ValueError:
            logger.error(
                "Valid --step-time formats are: 20, 20s, 3m, 2h, 1h20m, 3h30m10s, etc."
            )
            sys.exit(1)

    if options.master:
        runner = environment.create_master_runner(
            master_bind_host=options.master_bind_host,
            master_bind_port=options.master_bind_port,
        )
    elif options.worker:
        try:
            runner = environment.create_worker_runner(options.master_host,
                                                      options.master_port)
        except socket.error as e:
            logger.error("Failed to connect to the Locust master: %s", e)
            sys.exit(-1)
    else:
        runner = environment.create_local_runner()

    # main_greenlet is pointing to runners.greenlet by default, it will point the web greenlet later if in web mode
    main_greenlet = runner.greenlet

    if options.run_time:
        if not options.headless:
            logger.error(
                "The --run-time argument can only be used together with --headless"
            )
            sys.exit(1)
        if options.worker:
            logger.error(
                "--run-time should be specified on the master node, and not on worker nodes"
            )
            sys.exit(1)
        try:
            options.run_time = parse_timespan(options.run_time)
        except ValueError:
            logger.error(
                "Valid --run-time formats are: 20, 20s, 3m, 2h, 1h20m, 3h30m10s, etc."
            )
            sys.exit(1)

        def spawn_run_time_limit_greenlet():
            logger.info("Run time limit set to %s seconds" % options.run_time)

            def timelimit_stop():
                logger.info("Time limit reached. Stopping Locust.")
                runner.quit()

            gevent.spawn_later(
                options.run_time,
                timelimit_stop).link_exception(greenlet_exception_handler)

    if options.csv_prefix:
        stats_csv_writer = StatsCSVFileWriter(environment,
                                              stats.PERCENTILES_TO_REPORT,
                                              options.csv_prefix,
                                              options.stats_history_enabled)
    else:
        stats_csv_writer = StatsCSV(environment, stats.PERCENTILES_TO_REPORT)

    # start Web UI
    if not options.headless and not options.worker:
        # spawn web greenlet
        protocol = "https" if options.tls_cert and options.tls_key else "http"
        try:
            if options.web_host == "*":
                # special check for "*" so that we're consistent with --master-bind-host
                web_host = ''
            else:
                web_host = options.web_host
            if web_host:
                logger.info("Starting web interface at %s://%s:%s" %
                            (protocol, web_host, options.web_port))
            else:
                logger.info(
                    "Starting web interface at %s://0.0.0.0:%s (accepting connections from all network interfaces)"
                    % (protocol, options.web_port))
            web_ui = environment.create_web_ui(
                host=web_host,
                port=options.web_port,
                auth_credentials=options.web_auth,
                tls_cert=options.tls_cert,
                tls_key=options.tls_key,
                stats_csv_writer=stats_csv_writer,
            )
        except AuthCredentialsError:
            logger.error(
                "Credentials supplied with --web-auth should have the format: username:password"
            )
            sys.exit(1)
        else:
            main_greenlet = web_ui.greenlet
    else:
        web_ui = None

    # Fire locust init event which can be used by end-users' code to run setup code that
    # need access to the Environment, Runner or WebUI
    environment.events.init.fire(environment=environment,
                                 runner=runner,
                                 web_ui=web_ui)

    if options.headless:
        # headless mode
        if options.master:
            # wait for worker nodes to connect
            while len(runner.clients.ready) < options.expect_workers:
                logging.info(
                    "Waiting for workers to be ready, %s of %s connected",
                    len(runner.clients.ready), options.expect_workers)
                time.sleep(1)
        if not options.worker:
            # apply headless mode defaults
            if options.num_users is None:
                options.num_users = 1
            if options.spawn_rate is None:
                options.spawn_rate = 1
            if options.step_users is None:
                options.step_users = 1

            # start the test
            if options.step_time:
                runner.start_stepload(options.num_users, options.spawn_rate,
                                      options.step_users, options.step_time)
            if environment.shape_class:
                environment.runner.start_shape()
            else:
                runner.start(options.num_users, options.spawn_rate)

    if options.run_time:
        spawn_run_time_limit_greenlet()

    stats_printer_greenlet = None
    if not options.only_summary and (options.print_stats or
                                     (options.headless
                                      and not options.worker)):
        # spawn stats printing greenlet
        stats_printer_greenlet = gevent.spawn(stats_printer(runner.stats))
        stats_printer_greenlet.link_exception(greenlet_exception_handler)

    if options.csv_prefix:
        gevent.spawn(stats_csv_writer.stats_writer).link_exception(
            greenlet_exception_handler)

    gevent.spawn(stats_history, runner)

    def shutdown():
        """
        Shut down locust by firing quitting event, printing/writing stats and exiting
        """
        logger.info("Running teardowns...")
        environment.events.quitting.fire(environment=environment, reverse=True)

        # determine the process exit code
        if log.unhandled_greenlet_exception:
            code = 2
        elif environment.process_exit_code is not None:
            code = environment.process_exit_code
        elif len(runner.errors) or len(runner.exceptions):
            code = options.exit_code_on_error
        else:
            code = 0

        logger.info("Shutting down (exit code %s), bye." % code)
        if stats_printer_greenlet is not None:
            stats_printer_greenlet.kill(block=False)
        logger.info("Cleaning up runner...")
        if runner is not None:
            runner.quit()

        print_stats(runner.stats, current=False)
        print_percentile_stats(runner.stats)

        print_error_report(runner.stats)

        sys.exit(code)

    # install SIGTERM handler
    def sig_term_handler():
        logger.info("Got SIGTERM signal")
        shutdown()

    gevent.signal_handler(signal.SIGTERM, sig_term_handler)

    try:
        logger.info("Starting Locust %s" % version)
        main_greenlet.join()
        shutdown()
    except KeyboardInterrupt as e:
        shutdown()