Commit 026dc173 authored by Elvis Pranskevichus's avatar Elvis Pranskevichus

Consolidate server implementations under servers/

parent 63696046
......@@ -19,9 +19,9 @@ RUN pip3 install vex
RUN vex --python=python3.5 -m bench pip install -U pip
RUN mkdir -p /var/lib/cache/pip
ADD http_server.py /tmp/http_server.py
ADD torecho.py /tmp/torecho.py
ADD requirements.txt /tmp/requirements.txt
ADD servers /usr/src/servers
RUN vex bench pip --cache-dir=/var/lib/cache/pip \
install -r /usr/src/servers/requirements.txt
EXPOSE 25000
......
......@@ -143,7 +143,7 @@ if __name__ == '__main__':
latency_std = math.sqrt(variance)
latency_cv = latency_std / mean_latency
percentiles = [25, 50, 75, 90, 99]
percentiles = [25, 50, 75, 90, 99, 99.99]
percentile_data = []
quantiles = weighted_quantile(arange, [p / 100 for p in percentiles],
......
#!/bin/bash
echo 'Installing packages...'
vex bench pip --cache-dir=/var/lib/cache/pip install -r /tmp/requirements.txt
mkdir -p /usr/local/repos
cd /usr/local/repos
git clone https://github.com/dabeaz/curio.git
git clone https://github.com/MagicStack/uvloop.git
cp /tmp/http_server.py uvloop/examples/bench/
UID=${UID:-0}
GID=${GID:-0}
......
import argparse
import asyncio
import aiohttp
import aiohttp.server
from aiohttp import web
import gc
import sys
import uvloop
from socket import *
PRINT = 0
def abort(msg):
print(msg, file=sys.stderr)
sys.exit(1)
def aiohttp_server(loop, addr):
PAYLOAD = b'<h1>Hello, World!</h1>'
async def handle(request):
return web.Response(body=PAYLOAD)
app = web.Application(loop=loop)
app.router.add_route('GET', '/', handle)
handler = app.make_handler()
server = loop.create_server(handler, *addr)
return server
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--type', default='asyncio+aiohttp', action='store')
parser.add_argument('--addr', default='127.0.0.1:25000', type=str)
args = parser.parse_args()
if args.type:
parts = args.type.split('+')
if len(parts) > 1:
loop_type = parts[0]
server_type = parts[1]
else:
server_type = args.type
if server_type == 'aiohttp':
if not loop_type:
loop_type = 'asyncio'
else:
loop_type = None
if loop_type not in {'asyncio', 'uvloop'}:
abort('unrecognized loop type: {}'.format(loop_type))
if server_type not in {'aiohttp', 'httptools'}:
abort('unrecognized server type: {}'.format(server_type))
if loop_type:
loop = globals()[loop_type].new_event_loop()
else:
loop = None
print('using {} loop: {!r}'.format(loop_type, loop))
print('using {} HTTP server'.format(server_type))
if loop:
asyncio.set_event_loop(loop)
loop.set_debug(False)
unix = False
if args.addr.startswith('file:'):
unix = True
addr = args.addr[5:]
else:
addr = args.addr.split(':')
addr[1] = int(addr[1])
addr = tuple(addr)
server_factory = globals()['{}_server'.format(server_type)]
print('serving on: {}'.format(addr))
if loop:
server = loop.run_until_complete(server_factory(loop, addr))
try:
loop.run_forever()
finally:
server.close()
loop.close()
......@@ -17,10 +17,6 @@ _dir = os.path.dirname(__file__)
_cache = os.path.abspath(os.path.join(_dir, '.cache'))
_socket = os.path.abspath(os.path.join(_dir, 'sockets'))
http_client = "wrk --latency -d 30 -c 200 -t 4 http://127.0.0.1:25000/{msize}"
http_server = "uvloop/examples/bench/http_server.py --addr='0.0.0.0:25000'"
server_base = ['docker', 'run', '--rm', '-t', '-p', '25000:25000',
'-e', 'UID={}'.format(os.geteuid()),
'-e', 'GID={}'.format(os.getegid()),
......@@ -54,10 +50,12 @@ unix_address = 'file:{_socket}/server.sock'.format(_socket=_socket)
tcp_client = echo_client + ['--addr={}'.format(tcp_address)]
unix_client = echo_client + ['--addr={}'.format(unix_address)]
http_client = "wrk --latency -d 30 -c 200 -t 4 http://127.0.0.1:25000/{msize}"
benchmarks = [{
'name': 'tcpecho-gevent',
'title': 'TCP echo server (gevent)',
'server': python + ['curio/examples/bench/gevecho.py'],
'server': python + ['/usr/src/servers/gevecho.py'],
'server_address': tcp_address,
'client': tcp_client,
'warmup': echo_warmup,
......@@ -65,7 +63,7 @@ benchmarks = [{
}, {
'name': 'tcpecho-tornado',
'title': 'TCP echo server (tornado)',
'server': python + ['/tmp/torecho.py'],
'server': python + ['/usr/src/servers/torecho.py'],
'server_address': tcp_address,
'client': tcp_client,
'warmup': echo_warmup,
......@@ -73,7 +71,7 @@ benchmarks = [{
}, {
'name': 'tcpecho-curio',
'title': 'TCP echo server (curio)',
'server': python + ['curio/examples/bench/curioecho.py'],
'server': python + ['/usr/src/servers/curioecho.py'],
'server_address': tcp_address,
'client': tcp_client,
'warmup': echo_warmup,
......@@ -81,7 +79,7 @@ benchmarks = [{
}, {
'name': 'tcpecho-nodejs',
'title': 'TCP echo server (nodejs)',
'server': nodejs + ['curio/examples/bench/nodeecho.js'],
'server': nodejs + ['/usr/src/servers/nodeecho.js'],
'server_address': tcp_address,
'client': tcp_client,
'warmup': echo_warmup,
......@@ -89,7 +87,7 @@ benchmarks = [{
}, {
'name': 'tcpecho-asyncio-stdstreams',
'title': 'TCP echo server (asyncio/stdstreams)',
'server': python + ['uvloop/examples/bench/server.py',
'server': python + ['/usr/src/servers/asyncioecho.py',
'--addr=0.0.0.0:25000',
'--streams'],
'server_address': tcp_address,
......@@ -99,7 +97,7 @@ benchmarks = [{
}, {
'name': 'tcpecho-asyncio-minproto',
'title': 'TCP echo server (asyncio/minproto)',
'server': python + ['uvloop/examples/bench/server.py',
'server': python + ['/usr/src/servers/asyncioecho.py',
'--addr=0.0.0.0:25000',
'--proto'],
'server_address': tcp_address,
......@@ -109,7 +107,7 @@ benchmarks = [{
}, {
'name': 'unixecho-asyncio-stdstreams',
'title': 'Unix socket echo server (asyncio/stdstreams)',
'server': python + ['uvloop/examples/bench/server.py',
'server': python + ['/usr/src/servers/asyncioecho.py',
'--addr=file:/tmp/sockets/server.sock',
'--streams'],
'server_address': unix_address,
......@@ -119,7 +117,7 @@ benchmarks = [{
}, {
'name': 'unixecho-asyncio-minproto',
'title': 'Unix socket echo server (asyncio/minproto)',
'server': python + ['uvloop/examples/bench/server.py',
'server': python + ['/usr/src/servers/asyncioecho.py',
'--addr=file:/tmp/sockets/server.sock',
'--proto'],
'server_address': unix_address,
......@@ -129,7 +127,7 @@ benchmarks = [{
}, {
'name': 'tcpecho-uvloop-stdstreams',
'title': 'TCP echo server (uvloop/stdstreams)',
'server': python + ['uvloop/examples/bench/server.py',
'server': python + ['/usr/src/servers/asyncioecho.py',
'--addr=0.0.0.0:25000',
'--streams', '--uvloop'],
'server_address': tcp_address,
......@@ -139,7 +137,7 @@ benchmarks = [{
}, {
'name': 'tcpecho-uvloop-minproto',
'title': 'TCP echo server (uvloop/minproto)',
'server': python + ['uvloop/examples/bench/server.py',
'server': python + ['/usr/src/servers/asyncioecho.py',
'--addr=0.0.0.0:25000',
'--proto', '--uvloop'],
'server_address': tcp_address,
......@@ -149,7 +147,7 @@ benchmarks = [{
}, {
'name': 'unixecho-uvloop-stdstreams',
'title': 'Unix socket echo server (uvloop/stdstreams)',
'server': python + ['uvloop/examples/bench/server.py',
'server': python + ['/usr/src/servers/asyncioecho.py',
'--addr=file:/tmp/sockets/server.sock',
'--streams', '--uvloop'],
'server_address': unix_address,
......@@ -159,7 +157,7 @@ benchmarks = [{
}, {
'name': 'unixecho-uvloop-minproto',
'title': 'Unix socket echo server (uvloop/minproto)',
'server': python + ['uvloop/examples/bench/server.py',
'server': python + ['/usr/src/servers/asyncioecho.py',
'--addr=file:/tmp/sockets/server.sock',
'--proto', '--uvloop'],
'server_address': unix_address,
......@@ -258,7 +256,7 @@ def main():
help='duration of each benchmark in seconds')
parser.add_argument('--benchmarks', type=str,
help='comma-separated list of benchmarks to run')
parser.add_argument('--save-json', '-J', default='text', type=str,
parser.add_argument('--save-json', '-J', type=str,
help='path to save benchmark results in JSON format')
args = parser.parse_args()
......@@ -321,7 +319,7 @@ def main():
output = textwrap.dedent('''\
{messages} messages in {duration} seconds
Latency: min {latency_min}ms; max {latency_max}ms; mean {latency_mean}ms; std: {latency_std}ms ({latency_cv}%)
Latency: min {latency_min}ms; max {latency_max}ms; mean {latency_mean}ms; std {latency_std}ms ({latency_cv}%);
Latency distribtion: {latency_percentiles}
Requests/sec: {rps}
Transfer/sec: {transfer}MiB
......
import argparse
import asyncio
import aiohttp
import aiohttp.server
from aiohttp import web
import sys
import httptools
import uvloop
from socket import *
PRINT = 0
class HttpRequest:
......@@ -87,3 +97,82 @@ class HttpProtocol(asyncio.Protocol):
def handle(self, request, response):
response.write(RESP)
def abort(msg):
print(msg, file=sys.stderr)
sys.exit(1)
def aiohttp_server(loop, addr):
PAYLOAD = b'<h1>Hello, World!</h1>'
async def handle(request):
return web.Response(body=PAYLOAD)
app = web.Application(loop=loop)
app.router.add_route('GET', '/', handle)
handler = app.make_handler()
server = loop.create_server(handler, *addr)
return server
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--type', default='asyncio+aiohttp', action='store')
parser.add_argument('--addr', default='127.0.0.1:25000', type=str)
args = parser.parse_args()
if args.type:
parts = args.type.split('+')
if len(parts) > 1:
loop_type = parts[0]
server_type = parts[1]
else:
server_type = args.type
if server_type == 'aiohttp':
if not loop_type:
loop_type = 'asyncio'
else:
loop_type = None
if loop_type not in {'asyncio', 'uvloop'}:
abort('unrecognized loop type: {}'.format(loop_type))
if server_type not in {'aiohttp', 'httptools'}:
abort('unrecognized server type: {}'.format(server_type))
if loop_type:
loop = globals()[loop_type].new_event_loop()
else:
loop = None
print('using {} loop: {!r}'.format(loop_type, loop))
print('using {} HTTP server'.format(server_type))
if loop:
asyncio.set_event_loop(loop)
loop.set_debug(False)
unix = False
if args.addr.startswith('file:'):
unix = True
addr = args.addr[5:]
else:
addr = args.addr.split(':')
addr[1] = int(addr[1])
addr = tuple(addr)
server_factory = globals()['{}_server'.format(server_type)]
print('serving on: {}'.format(addr))
if loop:
server = loop.run_until_complete(server_factory(loop, addr))
try:
loop.run_forever()
finally:
server.close()
loop.close()
import argparse
import asyncio
import gc
import uvloop
import os.path
import socket as socket_module
from socket import *
PRINT = 0
async def echo_server(loop, address, unix):
if unix:
sock = socket(AF_UNIX, SOCK_STREAM)
else:
sock = socket(AF_INET, SOCK_STREAM)
sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
sock.bind(address)
sock.listen(5)
sock.setblocking(False)
if PRINT:
print('Server listening at', address)
with sock:
while True:
client, addr = await loop.sock_accept(sock)
if PRINT:
print('Connection from', addr)
loop.create_task(echo_client(loop, client))
async def echo_client(loop, client):
with client:
while True:
data = await loop.sock_recv(client, 10000)
if not data:
break
await loop.sock_sendall(client, data)
if PRINT:
print('Connection closed')
async def echo_client_streams(reader, writer):
if PRINT:
sock = writer.get_extra_info('socket')
print('Connection from', sock.getpeername())
while True:
data = await reader.read(100000)
if not data:
break
writer.write(data)
if PRINT:
print('Connection closed')
writer.close()
class EchoProtocol(asyncio.Protocol):
def connection_made(self, transport):
self.transport = transport
def connection_lost(self, exc):
self.transport = None
def data_received(self, data):
self.transport.write(data)
async def print_debug(loop):
while True:
print(chr(27) + "[2J") # clear screen
loop.print_debug_info()
await asyncio.sleep(0.5, loop=loop)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--uvloop', default=False, action='store_true')
parser.add_argument('--streams', default=False, action='store_true')
parser.add_argument('--proto', default=False, action='store_true')
parser.add_argument('--addr', default='127.0.0.1:25000', type=str)
parser.add_argument('--print', default=False, action='store_true')
args = parser.parse_args()
if args.uvloop:
loop = uvloop.new_event_loop()
print('using UVLoop')
else:
loop = asyncio.new_event_loop()
print('using asyncio loop')
asyncio.set_event_loop(loop)
loop.set_debug(False)
if args.print:
PRINT = 1
if hasattr(loop, 'print_debug_info'):
loop.create_task(print_debug(loop))
PRINT = 0
unix = False
if args.addr.startswith('file:'):
unix = True
addr = args.addr[5:]
if os.path.exists(addr):
os.remove(addr)
else:
addr = args.addr.split(':')
addr[1] = int(addr[1])
addr = tuple(addr)
print('serving on: {}'.format(addr))
if args.streams:
if args.proto:
print('cannot use --stream and --proto simultaneously')
exit(1)
print('using asyncio/streams')
if unix:
coro = asyncio.start_unix_server(echo_client_streams,
addr, loop=loop)
else:
coro = asyncio.start_server(echo_client_streams,
*addr, loop=loop)
srv = loop.run_until_complete(coro)
elif args.proto:
if args.streams:
print('cannot use --stream and --proto simultaneously')
exit(1)
print('using simple protocol')
if unix:
coro = loop.create_unix_server(EchoProtocol, addr)
else:
coro = loop.create_server(EchoProtocol, *addr)
srv = loop.run_until_complete(coro)
else:
print('using sock_recv/sock_sendall')
loop.create_task(echo_server(loop, addr, unix))
try:
loop.run_forever()
finally:
if hasattr(loop, 'print_debug_info'):
gc.collect()
print(chr(27) + "[2J")
loop.print_debug_info()
loop.close()
# Taken from curio: https://github.com/dabeaz/curio
# A simple echo server
from curio import Kernel, new_task, run_server
async def echo_handler(client, addr):
print('Connection from', addr)
while True:
data = await client.recv(10000)
if not data:
break
await client.sendall(data)
print('Connection closed')
if __name__ == '__main__':
kernel = Kernel()
kernel.run(run_server('', 25000, echo_handler))
# Taken from curio: https://github.com/dabeaz/curio
from gevent.server import StreamServer
# this handler will be run for each incoming connection in a dedicated greenlet
def echo(socket, address):
print('New connection from %s:%s' % address)
while True:
data = socket.recv(100000)
if not data:
break
socket.sendall(data)
socket.close()
if __name__ == '__main__':
server = StreamServer(('0.0.0.0', 25000), echo)
server.serve_forever()
// Taken from http://learn.bevry.me/node/server/
// Simple install node.js,
// run with (e.g.):
// $ /usr/local/bin/node nodeecho.js
var net = require('net');
net.createServer(function(socket){
socket.on('data', function(data){
socket.write(data)
});
}).listen(25000);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment