From 3509ae6bb1484d8770d13e4ba661f0aa1b1566e0 Mon Sep 17 00:00:00 2001 From: Alexis Delhaie Date: Fri, 2 Oct 2020 23:03:47 +0200 Subject: [PATCH] new default "starting threads" algorithm --- src/basic_producer_consumer.py | 59 ++++++++++++++++++++++++++ src/main.py | 77 ++++++++++++++++++++-------------- src/thread.py | 2 +- 3 files changed, 106 insertions(+), 32 deletions(-) create mode 100644 src/basic_producer_consumer.py diff --git a/src/basic_producer_consumer.py b/src/basic_producer_consumer.py new file mode 100644 index 0000000..122a7d4 --- /dev/null +++ b/src/basic_producer_consumer.py @@ -0,0 +1,59 @@ +import threading +import time +import queue +import os +import sys + +def get_available_threads(): + if sys.platform == 'win32': + return (int)(os.environ['NUMBER_OF_PROCESSORS']) + else: + return (int)(os.popen('grep -c cores /proc/cpuinfo').read()) + +SIZE = get_available_threads() +q = queue.Queue() +not_finished = True + +class ProducerThread(threading.Thread): + def __init__(self, threads): + super(ProducerThread,self).__init__() + self.threads = threads + + def run(self): + global not_finished + try: + i = 0 + while i < len(self.threads): + if q.qsize() < SIZE: + q.put(self.threads[i]) + i += 1 + while q.qsize() > 0: + time.sleep(1) + except: + pass + not_finished = False + + +class ConsumerThread(threading.Thread): + def __init__(self): + super(ConsumerThread,self).__init__() + + def run(self): + while not_finished: + if q.qsize() > 0: + t = q.get() + t.start() + t.join() + +def start(threads): + p = ProducerThread(threads) + p.start() + consumers = [] + for _ in range(get_available_threads()): + c = ConsumerThread() + consumers.append(c) + c.start() + p.join() + for c in consumers: + c.join() + \ No newline at end of file diff --git a/src/main.py b/src/main.py index ee83229..3ad30a3 100644 --- a/src/main.py +++ b/src/main.py @@ -8,9 +8,12 @@ from rich import box from rich.console import Console from rich.table import Table from thread import StressThread +import thread +import basic_producer_consumer console = Console(highlight=False) -VERSION = "1.2" +VERSION = "1.3" +thread.console = console def main(): if ((len(sys.argv) >= 2) and (("--help" in sys.argv) or ("/?" in sys.argv))): @@ -28,33 +31,44 @@ def main(): thread_number = int(get_args("-t", False, 1007, 1008, "5")) timeout = int(get_args("-tm", False, 1009, 1010, "10")) one_by_one = get_flag("--one-by-one") - + ignore_available_threads = get_flag("--ignore-available-threads") self_signed = get_flag("--allow-self-signed") - start(host, port, path, timeout, thread_number, allow_ssl, self_signed, one_by_one) + if one_by_one and ignore_available_threads: + console.print("[red]Error[/]: ambigous arguments, --one-by-one and --ignore-available-threads cannot be in the same command", style="bold") + return -def start(host, port, path, timeout, thread_number, allow_ssl, self_signed, one_by_one = False): + start(host, port, path, timeout, thread_number, allow_ssl, self_signed, one_by_one, ignore_available_threads) + +def start(host, port, path, timeout, thread_number, allow_ssl, self_signed, one_by_one = False, ignore_available_threads = False): thread_array = [] for i in range(0, thread_number): thread_array.append(StressThread(host, port, path, timeout, i, allow_ssl, self_signed, VERSION)) - for t in thread_array: - if one_by_one: - t.run() - else: + if one_by_one: + start_one_by_one(thread_array) + elif ignore_available_threads: + start_all(thread_array) + else: + basic_producer_consumer.start(thread_array) + show_stat(thread_array, (timeout * 1000)) + +# Run requests in one thread +def start_one_by_one(threads): + for t in threads: + t.run() + +# Start all requests in the same time +def start_all(threads): + for t in threads: + started = False + while not started: try: t.start() + started = True except: - b = False - while not b: - try: - t.start() - b = True - except: - time.sleep(1) - if not one_by_one: - for t in thread_array: - t.join() - show_stat(thread_array, (timeout * 1000)) + time.sleep(1) + for t in threads: + t.join() def show_stat(tArray, timeoutInMs): total, succeeded = [0, 0] @@ -86,21 +100,22 @@ def show_stat(tArray, timeoutInMs): def show_help(): console.print("") console.print("Usage: [bold] -h host -p path [--port port] [-t number_of_thread] [-tm timeout_in_second] [--ssl [--allow-self-signed]][/]") - console.print("Exemple: st.exe -h www.google.fr -p / -t 10") - console.print(" python main.py -h www.google.fr -p / -t 10") + console.print("Exemple: st -h www.google.fr -p / -t 10") + console.print(" py main.py -h www.google.fr -p / -t 10") console.print("") console.print("Available arguments:") - console.print(" -h host The server IP or domain name") - console.print(" -p path The path of the HTTP resource") - console.print(" --port port The server HTTP port") - console.print(" -t thread Number of threads") - console.print(" -tm second Timeout of the request") - console.print(" --one-by-one Send request one by one") - console.print(" --ssl Use HTTPS/SSL") - console.print(" --allow-self-signed Allow self signed SSL certificate") + console.print(" -h host The server IP or domain name") + console.print(" -p path The path of the HTTP resource") + console.print(" --port port The server HTTP port") + console.print(" -t thread Number of threads") + console.print(" -tm second Timeout of the request") + console.print(" --one-by-one Send request one by one") + console.print(" --ignore-available-threads Ignore physical number of threads and start all request in the same time") + console.print(" --ssl Use HTTPS/SSL") + console.print(" --allow-self-signed Allow self signed SSL certificate") console.print(" --help") - console.print(" /? Show this page") - console.print(" --version Get information about the application and the system") + console.print(" /? Show this page") + console.print(" --version Get information about the application and the system") def show_author(): console.print("[bold]Basic HTTP Stress test[/]") diff --git a/src/thread.py b/src/thread.py index 54b42c5..bf3c452 100644 --- a/src/thread.py +++ b/src/thread.py @@ -7,7 +7,7 @@ import ssl import encodings.idna from rich.console import Console -console = Console(highlight=False) +console = None class StressThread (threading.Thread):