From 4fce3e66b10a044c5358d28d0f40c67bdfbb7a16 Mon Sep 17 00:00:00 2001 From: Yarrington Date: Fri, 24 Jun 2016 14:08:35 -0400 Subject: [PATCH] Adding python scripts for load testing. --- ci/homebrew loadtester/blaster.py | 16 +++++ ci/homebrew loadtester/siteBlasting.py | 95 ++++++++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 ci/homebrew loadtester/blaster.py create mode 100644 ci/homebrew loadtester/siteBlasting.py diff --git a/ci/homebrew loadtester/blaster.py b/ci/homebrew loadtester/blaster.py new file mode 100644 index 0000000..683e62b --- /dev/null +++ b/ci/homebrew loadtester/blaster.py @@ -0,0 +1,16 @@ +# Sample call: +# python blaster.py -url 'https://pzsvc-hello.test.geointservices.io/' -p 0.01 -n 50 + +from siteBlasting import * + +if __name__ == '__main__': + + url = getTagValue('-url') # -url 'http://www.google.com' + period = float(getTagValue('-p')) # -p 0.01 + num = int(getTagValue('-n')) # -n 1000 + + (pArray, pStatus, pLock) = createSharedVars(num) + pRequests = createProcesses(url, num, pArray, pStatus, pLock) + l = startLogging(period, pArray, pStatus, pLock) + startProcesses(pRequests) + l.join() \ No newline at end of file diff --git a/ci/homebrew loadtester/siteBlasting.py b/ci/homebrew loadtester/siteBlasting.py new file mode 100644 index 0000000..e950fb5 --- /dev/null +++ b/ci/homebrew loadtester/siteBlasting.py @@ -0,0 +1,95 @@ +import multiprocessing +import time +import requests +import sys +import ctypes +import psutil + +# Function to pass to new process. Records elapsed time to the processes Array. If a bad +# status is returned, it is recorded in the status variable to be processed by the logger. +def sendGetRequest(url, pArray, pIndex, pStatus, pLock): + r = requests.get(url) + if r.status_code == 200: + pArray[pIndex] = r.elapsed.total_seconds() + else: + pArray[pIndex] = -1 + pLock.acquire() # Released in logger() + pStatus['fail'] = '%d --> %d: %s' % (pIndex, r.status_code, r.reason) + +# Logs imformation about running processes. Handles request errors as they happen. +def logger(period, pArray, pStatus, pLock): + global statusLock + startTime = time.time() + unfinished = 1 + failed = 0 + failed_printed = 0 + while unfinished + failed - failed_printed > 0: + if pStatus['fail'] != False: + # Replace with logging function. + print(pStatus['fail']) + failed_printed += 1 + pStatus['fail'] = False + pLock.release() + else: + unfinished = aCount(pArray,0) + failed = aCount(pArray, -1) + finished = len(pArray) - unfinished - failed + elapsed = time.time() - startTime + # Replace with logging function + print('%0.3f s: %d ToDo, %d Done, %d Fail' % (elapsed, unfinished, finished, failed)) + time.sleep(period) + print(['%0.1f' % p for p in pArray]) + +# Returns a list of processes that call sendGetRequest(). +def createProcesses(url, num, pArray, pStatus, pLock): + return [ + multiprocessing.Process( + target = sendGetRequest, + args = (url, pArray, i, pStatus, pLock) + ) for i in range(0,num) + ] + +# Start all processes in the supplied list. +def startProcesses(processes): + for p in processes: + cpus = list(range(psutil.cpu_count())) + p.start() + psutil.Process(p.pid).cpu_affinity(cpus[1:]) # Don't run blasters on the logger's core. + print('All started!') + +# Starts the logging process. +def startLogging(period, pArray, pStatus, pLock): + pLogger = multiprocessing.Process( + target = logger, + args = (period, pArray, pStatus, pLock) + ) + pLogger.start() + psutil.Process(pLogger.pid).cpu_affinity([0]) # Run logger only on first core + return pLogger + +# returns (pArray, pStatus, pLock) to be shared between processes. +def createSharedVars(num): + pArray = multiprocessing.Array('d', num) + m = multiprocessing.Manager() + pStatus = m.dict() + pLock = m.Lock() + pStatus['fail'] = False + return (pArray, pStatus, pLock) + +# Return the command line argument after the specified tag. +def getTagValue(tag): + for (i, ele) in enumerate(sys.argv): + if tag == ele: + val = sys.argv[i + 1] + if val[0] == val[-1] == "'": + val = val[1:-1] + return val + else: return '' + +# Hacked counter for array. +def aCount(array, val): + count = 0 + for ele in array: + if ele == val: + count += 1 + return count \ No newline at end of file