Skip to content

Commit

Permalink
Merge pull request #25 from MarkReedZ/loop_cleanup
Browse files Browse the repository at this point in the history
Loop cleanup
  • Loading branch information
MarkReedZ authored Mar 20, 2024
2 parents 1bf077e + 8d4b426 commit ce3d026
Show file tree
Hide file tree
Showing 56 changed files with 3,700 additions and 1,531 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,9 @@
*.swp
settings.py
build/*
gbench/parse
gbench/t
gbench/string
gbench/query
.DS_Store
__pycache__
44 changes: 27 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,39 @@ Async Python 3.5+ web server written in C
# Benchmarks

```
Hello pipelined 4,152,858 Requests/second
Hello 633,097 Requests/second
404 654,053 Requests/second
Cookies 422,728 Requests/second
Form parsing 328,780 Requests/second
Parse JSON 224,872 Requests/second
Templates 257,753 Requests/second
Sessions:
memcached 163,833 Requests/second
mrcache 283,359 Requests/second
MrWorkServer 338,891 Requests/second
File Upload 132,242 Requests/second
Pipelined
Hello (cached) 8,534,332 Requests/second
Hello 6,834,994 Requests/second
More hdrs 6,193,307 Requests/second
Sessions 4,396,364 Requests/second
File Upload 3,510,289 Requests/second
mrpacker 2,052,674 Requests/second
Form 1,182,228 Requests/second
One by one
Hello 707,667 Requests/second
Hello hdrs 728,639 Requests/second
Cookies 588,212 Requests/second
many args 691,910 Requests/second
404 natural 763,643 Requests/second
404 580,424 Requests/second
Form parsing 338,553 Requests/second
mrpacker 533,242 Requests/second
Sessions 325,354 Requests/second
File Upload 292,331 Requests/second
get ip 503,454 Requests/second
```

Versus sanic a pure python async server

```
Hello World 64,366 Requests/second
Cookies 50,867 Requests/second
404 9,256 Requests/second
forms 27,104 Requests/second
Hello World 22,366 Requests/second
Cookies 20,867 Requests/second
404 8,256 Requests/second
forms 11,104 Requests/second
sessions 4,053 Requests/second
File upload 21,457 Requests/second
File upload 1,457 Requests/second
```

Hello World Example
Expand Down
3 changes: 1 addition & 2 deletions bench/sanic/readme
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
pip install sanic
pip install sanic_session
pip install sanic sanic_session

wrk -t 4 -c 32 -d 2 http://localhost:8080/

Expand Down
30 changes: 30 additions & 0 deletions bench/sanic/session.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@

import aiomcache
import uvloop

from sanic import Sanic
from sanic.response import text
from sanic_session import Session, MemcacheSessionInterface

app = Sanic("app")

# create a memcache client
client = aiomcache.Client("127.0.0.1", 11211)

# pass the memcache client into the session
session = Session(app, interface=MemcacheSessionInterface(client))

@app.route("/")
async def test(request):
# interact with the session like a normal dict
if not request.ctx.session.get('foo'):
request.ctx.session['foo'] = 0

request.ctx.session['foo'] += 1

response = text("YAY")

return response

if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000, debug=True)
8 changes: 5 additions & 3 deletions bench/sanic/tst.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@

import sanic
from sanic.response import json

app = sanic.Sanic("my-hello-world-app")

@app.route('/')
async def test(request):
return sanic.text("Hello World")
return sanic.text("Hello World")

@app.route("/s")
async def sess(request):
return sanic.text("session")

if __name__ == '__main__':
app.run(port=8080)

6 changes: 2 additions & 4 deletions curl.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@

for run in {1..1000}
do
curl -d "param1=value1&param2=value2" -X POST http://localhost:8080/ -H "Content-Type: application/x-www-form-urlencoded"
for n in {1..10}; do
curl -d "param1=value1&param2=value2" -X POST http://localhost:8080/form -H "Content-Type: application/x-www-form-urlencoded"
done
209 changes: 98 additions & 111 deletions dotests.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@

readme = """
pip install psutil requests msgpack mrasyncmc tenjin mrpacker
pip install psutil requests msgpack mrasyncmc tenjin mrpacker mrworkserver
mrcache and mrworkserver must be running for the benchmarks
mrcache:
git clone https://github.com/MarkReedZ/mrcache.git
cd mrcache; ./bld; ./mrcache
mrworkserver
python workserver.py
"""


Expand All @@ -11,12 +18,24 @@

import tests

import argparse
import sys
import asyncio
import os
from asyncio.subprocess import PIPE, STDOUT
import statistics

import uvloop
import psutil
import atexit

# TODO
# Check for memcached being up and add the session key so we hit and load the json 43709dd361cc443e976b05714581a7fb
# memcached -l 127.0.0.1 -p 11211 -d -m 50
# Check for mrworkserver and mrcache being up and add the session key so we hit and load the json 43709dd361cc443e976b05714581a7fb
# mrcache -m 64 -i 16
# python mrworkserver/tst.py


if 1:
async def run_tests():
package = tests
for importer, modname, ispkg in pkgutil.iter_modules(package.__path__):
if modname.startswith("test"):
Expand All @@ -36,142 +55,110 @@
if f[0] == 'teardown':
f[1]()

print("Benchmarks")

import argparse
import sys
import asyncio
import os
from asyncio.subprocess import PIPE, STDOUT
import statistics

import uvloop
import psutil
import atexit

#from misc import cpu


def run_wrk(loop, endpoint=None, lua=None, options=None):
async def run_wrk(loop, endpoint=None, lua=None, options=None):
rps = 0
try:
endpoint = endpoint or 'http://localhost:8080/'
if lua:
if options != None:
wrk_fut = asyncio.create_subprocess_exec( 'wrk', '-t', '4', '-c', '32', '-d', '2', '-s', lua, *options, endpoint, stdout=PIPE, stderr=STDOUT)
proc = await asyncio.create_subprocess_exec( 'wrk', '-t', '4', '-c', '32', '-d', '2', '-s', lua, *options, endpoint, stdout=PIPE, stderr=STDOUT)
else:
wrk_fut = asyncio.create_subprocess_exec( 'wrk', '-t', '4', '-c', '32', '-d', '2', '-s', lua, endpoint, stdout=PIPE, stderr=STDOUT)
proc = await asyncio.create_subprocess_exec( 'wrk', '-t', '4', '-c', '32', '-d', '2', '-s', lua, endpoint, stdout=PIPE, stderr=STDOUT)
else:
if options != None:
wrk_fut = asyncio.create_subprocess_exec( 'wrk', '-t', '4', '-c', '32', '-d', '2', *options, endpoint, stdout=PIPE, stderr=STDOUT)
proc = await asyncio.create_subprocess_exec( 'wrk', '-t', '4', '-c', '32', '-d', '2', *options, endpoint, stdout=PIPE, stderr=STDOUT)
else:
wrk_fut = asyncio.create_subprocess_exec( 'wrk', '-t', '4', '-c', '32', '-d', '2', endpoint, stdout=PIPE, stderr=STDOUT)
proc = await asyncio.create_subprocess_exec( 'wrk', '-t', '4', '-c', '32', '-d', '2', endpoint, stdout=PIPE, stderr=STDOUT)

wrk = loop.run_until_complete(wrk_fut)
stdout, stderr = await proc.communicate()
rps = 0
lines = []
while 1:
line = loop.run_until_complete(wrk.stdout.readline())
if line:
line = line.decode('utf-8')
lines.append(line)
if line.startswith('Requests/sec:'):
rps = float(line.split()[-1])
else:
break
lines = stdout.decode('utf-8').split("\n")
for line in lines:
if line.startswith('Requests/sec:'):
rps = float(line.split()[-1])

retcode = loop.run_until_complete(wrk.wait())
if retcode != 0:
print('\r\n'.join(lines))
except Exception as e:
print(e)


return rps


noisy = ['atom', 'chrome', 'firefox', 'dropbox', 'opera', 'spotify', 'gnome-documents']
async def run_benchmarks():
proc = await asyncio.create_subprocess_exec( 'python', 'tests/s_bench.py', stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE )
process = psutil.Process(proc.pid)

def silence():
for proc in psutil.process_iter():
if proc.name() in noisy:
proc.suspend()
await asyncio.sleep(1)

def resume():
for proc in psutil.process_iter():
if proc.name() in noisy:
proc.resume()
atexit.register(resume)
if proc.returncode != None:
print("tests/s_bench.py failed to start:")
print(await proc.stdout.read())
print(await proc.stderr.read())
exit()

silence()
print("Benchmarks")

loop = uvloop.new_event_loop()
try:

more_headers = ('-H','User-Agent: Mozilla/5.0 (X11; Linux x86_64) Gecko/20130501 Firefox/30.0 AppleWebKit/600.00 Chrome/30.0.0000.0 Trident/10.0 Safari/600.00',
'-H','Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'-H','Accept-Language: en-US,en;q=0.5',
'-H','Cookie: mrsession=43709dd361cc443e976b05714581a7fb; foo=fdsfdasdfasdfdsfasdfsdfsdfasdfas; short=fazc;',
'-H','Connection: keep-alive')
opts = ('-H','Cookie: mrsession=43709dd361cc443e976b05714581a7fb; foo=fdsfdasdfasdfdsfasdfsdfsdfasdfas; short=fazc;')

print(" Pipelined")
print (" Hello ", await run_wrk(loop, 'http://localhost:8080/',lua='tests/lua/pipeline.lua'), "Requests/second" )
print (" More hdrs ", await run_wrk(loop, 'http://localhost:8080/',options=more_headers,lua='tests/lua/pipeline.lua'), "Requests/second" )
print (" Sessions ", await run_wrk(loop, 'http://localhost:8080/s',lua='tests/lua/q-session.lua'), "Requests/second" )
print (" File Upload ", await run_wrk(loop, 'http://localhost:8080/upload',lua='tests/lua/q-upload.lua'), "Requests/second" )
print (" mrpacker ", await run_wrk(loop, 'http://localhost:8080/mrpacker',lua='tests/lua/q-mrp.lua'), "Requests/second" )
print (" Form ", await run_wrk(loop, 'http://localhost:8080/form',lua='tests/lua/q-form.lua'), "Requests/second" )
if 1:

print("")
print(" One by one")
print (" Hello ", await run_wrk(loop, 'http://localhost:8080/'), "Requests/second" )
print (" Hello hdrs ", await run_wrk(loop, 'http://localhost:8080/', options=more_headers), "Requests/second" )
print (" Cookies ", await run_wrk(loop, 'http://localhost:8080/printCookies', options=opts), "Requests/second" )
print (" many args ", await run_wrk(loop, 'http://localhost:8080/sixargs/one/two/three/four/five/six'), "Requests/second" )
print (" 404 natural ", await run_wrk(loop, 'http://localhost:8080/dfads404/'), "Requests/second" )
print (" 404 ", await run_wrk(loop, 'http://localhost:8080/404/'), "Requests/second" )
print (" Form parsing ", await run_wrk(loop, 'http://localhost:8080/form',lua='tests/lua/form.lua'), "Requests/second" )
#print (" Templates ", await run_wrk(loop, 'http://localhost:8080/template'), "Requests/second" )
print (" mrpacker ", await run_wrk(loop,'http://localhost:8080/mrpacker',lua='tests/lua/mrpacker.lua'), "Requests/second" )
print (" Sessions ", await run_wrk(loop, 'http://localhost:8080/s', options=opts), "Requests/second" )
print (" File Upload ", await run_wrk(loop,'http://localhost:8080/upload',lua='tests/lua/upload.lua'), "Requests/second" )
# Disabled in s_bench.py print ("Sessions (py) ", run_wrk(loop, 'http://localhost:8080/pys', options=opts), "Requests/second" )
#print (" Session login ", await run_wrk(loop, 'http://localhost:8080/login'), "Requests/second" )
#print (" json post ", await run_wrk(loop,'http://localhost:8080/json',lua='tests/lua/json.lua'), "Requests/second" )
#print (" mrpacker py ", await run_wrk(loop,'http://localhost:8080/mrpackerpy',lua='tests/lua/mrpacker.lua'), "Requests/second" )
#print (" msgpack py ", await run_wrk(loop,'http://localhost:8080/msgpack',lua='tests/lua/msgpack.lua'), "Requests/second" )


opts = ('-H','XX-Real-IP: 1.2.3.4')
print (" get ip ", await run_wrk(loop,'http://localhost:8080/getip',options=opts), "Requests/second" )
#print ("many num args ", await run_wrk(loop, 'http://localhost:8080/sixargs/155/2001/29999/25/29999543/93243242394'), "Requests/second" )
#print ("404 ", await run_wrk(loop, 'http://localhost:8080/404/'), "Requests/second" )


asyncio.set_event_loop(loop)
except KeyboardInterrupt:
pass
finally:
proc.terminate()
await proc.wait()

server_fut = asyncio.create_subprocess_exec( 'python', 'tests/s_bench.py', stdout=asyncio.subprocess.PIPE )
server = loop.run_until_complete(server_fut)
process = psutil.Process(server.pid)

time.sleep(1)
try:

more_headers = ('-H','User-Agent: Mozilla/5.0 (X11; Linux x86_64) Gecko/20130501 Firefox/30.0 AppleWebKit/600.00 Chrome/30.0.0000.0 Trident/10.0 Safari/600.00',
'-H','Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'-H','Accept-Language: en-US,en;q=0.5',
'-H','Connection: keep-alive')
opts = ('-H','Cookie: mrsession=43709dd361cc443e976b05714581a7fb; foo=fdsfdasdfasdfdsfasdfsdfsdfasdfas; short=fazc;')
print ("Hello ", run_wrk(loop, 'http://localhost:8080/'), "Requests/second" )
print ("Sessions ", run_wrk(loop, 'http://localhost:8080/s', options=opts), "Requests/second" )
if 0:
print ("Hello pipelined", run_wrk(loop, 'http://localhost:8080/',lua='tests/lua/pipeline.lua'), "Requests/second" )
print ("More hdrs pipelined", run_wrk(loop, 'http://localhost:8080/',options=more_headers,lua='tests/lua/pipeline.lua'), "Requests/second" )
print ("Hello ", run_wrk(loop, 'http://localhost:8080/'), "Requests/second" )
print ("Hello hdrs ", run_wrk(loop, 'http://localhost:8080/', options=more_headers), "Requests/second" )

#print ("Cookies ", run_wrk(loop, 'http://localhost:8080/printCookies', options=opts), "Requests/second" )
#print ("many args ", run_wrk(loop, 'http://localhost:8080/sixargs/one/two/three/four/five/six'), "Requests/second" )
#print ("404 natural ", run_wrk(loop, 'http://localhost:8080/dfads404/'), "Requests/second" )
#print ("404 ", run_wrk(loop, 'http://localhost:8080/404/'), "Requests/second" )
#print ("Form parsing ", run_wrk(loop, 'http://localhost:8080/form',lua='tests/lua/form.lua'), "Requests/second" )
#print ("Templates ", run_wrk(loop, 'http://localhost:8080/template'), "Requests/second" )
#print ("mrpacker ", run_wrk(loop,'http://localhost:8080/mrpacker',lua='tests/lua/mrpacker.lua'), "Requests/second" )
#print ("Sessions ", run_wrk(loop, 'http://localhost:8080/s', options=opts), "Requests/second" )
# Disabled in s_bench.py print ("Sessions (py) ", run_wrk(loop, 'http://localhost:8080/pys', options=opts), "Requests/second" )
#print ("Session login ", run_wrk(loop, 'http://localhost:8080/login'), "Requests/second" )
#print ("json post ", run_wrk(loop,'http://localhost:8080/json',lua='tests/lua/json.lua'), "Requests/second" )
#print ("mrpacker py ", run_wrk(loop,'http://localhost:8080/mrpackerpy',lua='tests/lua/mrpacker.lua'), "Requests/second" )
#print ("msgpack py ", run_wrk(loop,'http://localhost:8080/msgpack',lua='tests/lua/msgpack.lua'), "Requests/second" )
async def main():
print("main")
await run_tests()
await run_benchmarks()


opts = ('-H','XX-Real-IP: 1.2.3.4')
#print ("get ip ", run_wrk(loop,'http://localhost:8080/getip',options=opts), "Requests/second" )
#print ("many num args ", run_wrk(loop, 'http://localhost:8080/sixargs/155/2001/29999/25/29999543/93243242394'), "Requests/second" )
#print ("404 ", run_wrk(loop, 'http://localhost:8080/404/'), "Requests/second" )

# Grab the stdout for debug
if 0:
lines = []
x = 0
while 1:
x += 1
print(x)
#if x > 19842: break
if x > 21605: break
line = loop.run_until_complete(server.stdout.readline())
if line:
line = line.decode('utf-8')
lines.append(line)
else:
break
print ( len(lines) )
o = open( "wrkout", "wb" )
o.write( (''.join(lines)).encode("utf-8") )
o.close()

except KeyboardInterrupt:
pass
finally:
server.terminate()
loop.run_until_complete(server.wait())
loop = uvloop.new_event_loop()
asyncio.set_event_loop(loop)
asyncio.run( main() )

Loading

0 comments on commit ce3d026

Please sign in to comment.