[Zope-Checkins] CVS: Zope/lib/python/ZServer/medusa/test - __init__.py:1.1.2.1 asyn_http_bench.py:1.1.2.1 max_sockets.py:1.1.2.1 test_11.py:1.1.2.1 test_lb.py:1.1.2.1 test_medusa.py:1.1.2.1 test_single_11.py:1.1.2.1 tests.txt:1.1.2.1

Chris McDonough chrism@zope.com
Tue, 17 Sep 2002 01:16:11 -0400


Update of /cvs-repository/Zope/lib/python/ZServer/medusa/test
In directory cvs.zope.org:/tmp/cvs-serv12650/lib/python/ZServer/medusa/test

Added Files:
      Tag: chrism-install-branch
	__init__.py asyn_http_bench.py max_sockets.py test_11.py 
	test_lb.py test_medusa.py test_single_11.py tests.txt 
Log Message:
Moved ZServer into lib/python.


=== Added File Zope/lib/python/ZServer/medusa/test/__init__.py ===
# make test appear as a package



=== Added File Zope/lib/python/ZServer/medusa/test/asyn_http_bench.py ===
#! /usr/local/bin/python1.4
# -*- Mode: Python; tab-width: 4 -*-

import asyncore
import socket
import string
import sys

def blurt (thing):
    sys.stdout.write (thing)
    sys.stdout.flush ()
    
total_sessions = 0

class http_client (asyncore.dispatcher_with_send):
    def __init__ (self, host='127.0.0.1', port=80, uri='/', num=10):
        asyncore.dispatcher_with_send.__init__ (self)
        self.create_socket (socket.AF_INET, socket.SOCK_STREAM)
        self.host = host
        self.port = port
        self.uri = uri
        self.num = num
        self.bytes = 0
        self.connect ((host, port))
        
    def log (self, *info):
        pass
        
    def handle_connect (self):
        self.connected = 1
        #		blurt ('o')
        self.send ('GET %s HTTP/1.0\r\n\r\n' % self.uri)
        
    def handle_read (self):
    #		blurt ('.')
        d = self.recv (8192)
        self.bytes = self.bytes + len(d)
        
    def handle_close (self):
        global total_sessions
        #		blurt ('(%d)' % (self.bytes))
        self.close()
        total_sessions = total_sessions + 1
        if self.num:
            http_client (self.host, self.port, self.uri, self.num-1)
            
import time
class timer:
    def __init__ (self):
        self.start = time.time()
    def end (self):
        return time.time() - self.start
        
from asyncore import socket_map, poll

MAX = 0

def loop (timeout=30.0):
    global MAX
    while socket_map:
        if len(socket_map) > MAX:
            MAX = len(socket_map)
        poll (timeout)
        
if __name__ == '__main__':
    if len(sys.argv) < 6:
        print 'usage: %s <host> <port> <uri> <hits> <num_clients>' % sys.argv[0]
    else:
        [host, port, uri, hits, num] = sys.argv[1:]
        hits = string.atoi (hits)
        num = string.atoi (num)
        port = string.atoi (port)
        t = timer()
        clients = map (lambda x: http_client (host, port, uri, hits-1), range(num))
        #import profile
        #profile.run ('loop')
        loop()
        total_time = t.end()
        print (
                '\n%d clients\n%d hits/client\n'
                'total_hits:%d\n%.3f seconds\ntotal hits/sec:%.3f' % (
                        num,
                        hits,
                        total_sessions,
                        total_time,
                        total_sessions / total_time
                        )
                )
        print 'Max. number of concurrent sessions: %d' % (MAX)
        
        
        # linux 2.x, talking to medusa
        # 50 clients
        # 1000 hits/client
        # total_hits:50000
        # 2255.858 seconds
        # total hits/sec:22.165
        # Max. number of concurrent sessions: 50


=== Added File Zope/lib/python/ZServer/medusa/test/max_sockets.py ===

import socket
import select

# several factors here we might want to test:
# 1) max we can create
# 2) max we can bind
# 3) max we can listen on
# 4) max we can connect

def max_server_sockets():
    sl = []
    while 1:
        try:
            s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
            s.bind (('',0))
            s.listen(5)
            sl.append (s)
        except:
            break
    num = len(sl)
    for s in sl:
        s.close()
    del sl
    return num
    
def max_client_sockets():
        # make a server socket
    server = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
    server.bind (('', 9999))
    server.listen (5)
    sl = []
    while 1:
        try:
            s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
            s.connect (('', 9999))
            conn, addr = server.accept()
            sl.append ((s,conn))
        except:
            break
    num = len(sl)
    for s,c in sl:
        s.close()
        c.close()
    del sl
    return num
    
def max_select_sockets():
    sl = []
    while 1:
        try:
            num = len(sl)
            for i in range(1 + len(sl) * 0.05):
                    # Increase exponentially.
                s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
                s.bind (('',0))
                s.listen(5)
                sl.append (s)
            select.select(sl,[],[],0)
        except:
            break
    for s in sl:
        s.close()
    del sl
    return num


=== Added File Zope/lib/python/ZServer/medusa/test/test_11.py ===
# -*- Mode: Python; tab-width: 4 -*-

import asyncore
import asynchat
import socket
import string

# get some performance figures for an HTTP/1.1 server.
# use pipelining.

class test_client (asynchat.async_chat):

    ac_in_buffer_size = 16384
    ac_out_buffer_size = 16384	
    
    total_in = 0
    
    concurrent = 0
    max_concurrent = 0
    
    def __init__ (self, addr, chain):
        asynchat.async_chat.__init__ (self)
        self.create_socket (socket.AF_INET, socket.SOCK_STREAM)
        self.set_terminator ('\r\n\r\n')
        self.connect (addr)
        self.push (chain)
        
    def handle_connect (self):
        test_client.concurrent = test_client.concurrent + 1
        if (test_client.concurrent > test_client.max_concurrent):
            test_client.max_concurrent = test_client.concurrent
            
    def handle_expt (self):
        print 'unexpected FD_EXPT thrown.  closing()'
        self.close()
        
    def close (self):
        test_client.concurrent = test_client.concurrent - 1
        asynchat.async_chat.close(self)
        
    def collect_incoming_data (self, data):
        test_client.total_in = test_client.total_in + len(data)
        
    def found_terminator (self):
        pass
        
    def log (self, *args):
        pass
        
        
import time

class timer:
    def __init__ (self):
        self.start = time.time()
        
    def end (self):
        return time.time() - self.start
        
def build_request_chain (num, host, request_size):
    s = 'GET /test%d.html HTTP/1.1\r\nHost: %s\r\n\r\n' % (request_size, host)
    sl = [s] * (num-1)
    sl.append (
            'GET /test%d.html HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n' % (
                    request_size, host
                    )
            )
    return string.join (sl, '')
    
if __name__ == '__main__':
    import string
    import sys
    if len(sys.argv) != 6:
        print 'usage: %s <host> <port> <request-size> <num-requests> <num-connections>\n' % sys.argv[0]
    else:
        host = sys.argv[1]
        
        ip = socket.gethostbyname (host)
        
        [port, request_size, num_requests, num_conns] = map (
                string.atoi, sys.argv[2:]
                )
        
        chain = build_request_chain (num_requests, host, request_size)
        
        t = timer()
        for i in range (num_conns):
            test_client ((host,port), chain)
        asyncore.loop()
        total_time = t.end()
        
        # ok, now do some numbers
        total_bytes = test_client.total_in
        num_trans = num_requests * num_conns
        throughput = float (total_bytes) / total_time
        trans_per_sec = num_trans / total_time
        
        sys.stderr.write ('total time: %.2f\n' % total_time)
        sys.stderr.write ('number of transactions: %d\n' % num_trans)
        sys.stderr.write ('total bytes sent: %d\n' % total_bytes)
        sys.stderr.write ('total throughput (bytes/sec): %.2f\n' % throughput)
        sys.stderr.write ('transactions/second: %.2f\n' % trans_per_sec)
        sys.stderr.write ('max concurrent connections: %d\n' % test_client.max_concurrent)
        
        sys.stdout.write (
                string.join (
                        map (str, (num_conns, num_requests, request_size, throughput, trans_per_sec)),
                        ','
                        ) + '\n'
                )


=== Added File Zope/lib/python/ZServer/medusa/test/test_lb.py ===
# -*- Mode: Python; tab-width: 4 -*-

# Get a lower bound for Medusa performance with a simple async
# client/server benchmark built on the async lib.  The idea is to test
# all the underlying machinery [select, asyncore, asynchat, etc...] in
# a context where there is virtually no processing of the data.

import socket
import select
import sys

# ==================================================
# server
# ==================================================

import asyncore
import asynchat

class test_channel (asynchat.async_chat):

    ac_in_buffer_size = 16384
    ac_out_buffer_size = 16384	
    
    total_in = 0
    
    def __init__ (self, conn, addr):
        asynchat.async_chat.__init__ (self, conn)
        self.set_terminator ('\r\n\r\n')
        self.buffer = ''
        
    def collect_incoming_data (self, data):
        self.buffer = self.buffer + data
        test_channel.total_in = test_channel.total_in + len(data)
        
    def found_terminator (self):
            # we've gotten the data, now send it back
        data = self.buffer
        self.buffer = ''
        self.push (data+'\r\n\r\n')
        
    def handle_close (self):
        sys.stdout.write ('.'); sys.stdout.flush()
        self.close()
        
    def log (self, *args):
        pass
        
class test_server (asyncore.dispatcher):
    def __init__ (self, addr):
    
        if type(addr) == type(''):
            f = socket.AF_UNIX
        else:
            f = socket.AF_INET
            
        self.create_socket (f, socket.SOCK_STREAM)
        self.bind (addr)
        self.listen (5)
        print 'server started on',addr
        
    def handle_accept (self):
        conn, addr = self.accept()
        test_channel (conn, addr)
        
        # ==================================================
        # client
        # ==================================================
        
        # pretty much the same behavior, except that we kick
        # off the exchange and decide when to quit
        
class test_client (test_channel):

    def __init__ (self, addr, packet, number):
        if type(addr) == type(''):
            f = socket.AF_UNIX
        else:
            f = socket.AF_INET
            
        asynchat.async_chat.__init__ (self)
        self.create_socket (f, socket.SOCK_STREAM)
        self.set_terminator ('\r\n\r\n')
        self.buffer = ''
        self.connect (addr)
        self.push (packet + '\r\n\r\n')
        self.number = number
        self.count = 0
        
    def handle_connect (self):
        pass
        
    def found_terminator (self):
        self.count = self.count + 1
        if self.count == self.number:
            sys.stdout.write('.'); sys.stdout.flush()
            self.close()
        else:
            test_channel.found_terminator (self)
            
import time

class timer:
    def __init__ (self):
        self.start = time.time()
        
    def end (self):
        return time.time() - self.start
        
if __name__ == '__main__':
    import string
    
    if '--poll' in sys.argv:
        sys.argv.remove ('--poll')
        use_poll=1
    else:
        use_poll=0
        
    if len(sys.argv) == 1:
        print 'usage: %s\n' \
        '  (as a server) [--poll] -s <ip> <port>\n' \
        '  (as a client) [--poll] -c <ip> <port> <packet-size> <num-packets> <num-connections>\n' % sys.argv[0]
        sys.exit(0)
    if sys.argv[1] == '-s':
        s = test_server ((sys.argv[2], string.atoi (sys.argv[3])))
        asyncore.loop(use_poll=use_poll)
    elif sys.argv[1] == '-c':
            # create the packet
        packet = string.atoi(sys.argv[4]) * 'B'
        host = sys.argv[2]
        port = string.atoi (sys.argv[3])
        num_packets = string.atoi (sys.argv[5])
        num_conns = string.atoi (sys.argv[6])
        
        t = timer()
        for i in range (num_conns):
            test_client ((host,port), packet, num_packets)
        asyncore.loop(use_poll=use_poll)
        total_time = t.end()
        
        # ok, now do some numbers
        bytes = test_client.total_in
        num_trans = num_packets * num_conns
        total_bytes = num_trans * len(packet)
        throughput = float (total_bytes) / total_time
        trans_per_sec = num_trans / total_time
        
        sys.stderr.write ('total time: %.2f\n' % total_time)
        sys.stderr.write ( 'number of transactions: %d\n' % num_trans)
        sys.stderr.write ( 'total bytes sent: %d\n' % total_bytes)
        sys.stderr.write ( 'total throughput (bytes/sec): %.2f\n' % throughput)
        sys.stderr.write ( ' [note, throughput is this amount in each direction]\n')
        sys.stderr.write ( 'transactions/second: %.2f\n' % trans_per_sec)
        
        sys.stdout.write (
                string.join (
                        map (str, (num_conns, num_packets, len(packet), throughput, trans_per_sec)),
                        ','
                        ) + '\n'
                )


=== Added File Zope/lib/python/ZServer/medusa/test/test_medusa.py ===
# -*- Mode: Python; tab-width: 4 -*-

import socket
import string
import time
import http_date

now = http_date.build_http_date (time.time())

cache_request = string.joinfields (
        ['GET / HTTP/1.0',
         'If-Modified-Since: %s' % now,
         ],
        '\r\n'
        ) + '\r\n\r\n'

nocache_request = 'GET / HTTP/1.0\r\n\r\n'

def get (request, host='', port=80):
    s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
    s.connect (host, port)
    s.send (request)
    while 1:
        d = s.recv (8192)
        if not d:
            break
    s.close()
    
class timer:
    def __init__ (self):
        self.start = time.time()
    def end (self):
        return time.time() - self.start
        
def test_cache (n=1000):
    t = timer()
    for i in xrange (n):
        get(cache_request)
    end = t.end()
    print 'cache: %d requests, %.2f seconds, %.2f hits/sec' % (n, end, n/end)
    
def test_nocache (n=1000):
    t = timer()
    for i in xrange (n):
        get(nocache_request)
    end = t.end()
    print 'nocache: %d requests, %.2f seconds, %.2f hits/sec' % (n, end, n/end)
    
if __name__ == '__main__':
    test_cache()
    test_nocache()


=== Added File Zope/lib/python/ZServer/medusa/test/test_single_11.py ===
# -*- Mode: Python; tab-width: 4 -*-

# no-holds barred, test a single channel's pipelining speed

import string
import socket

def build_request_chain (num, host, request_size):
    s = 'GET /test%d.html HTTP/1.1\r\nHost: %s\r\n\r\n' % (request_size, host)
    sl = [s] * (num-1)
    sl.append (
            'GET /test%d.html HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n' % (
                    request_size, host
                    )
            )
    return string.join (sl, '')
    
import time

class timer:
    def __init__ (self):
        self.start = time.time()
        
    def end (self):
        return time.time() - self.start
        
if __name__ == '__main__':
    import sys
    if len(sys.argv) != 5:
        print 'usage: %s <host> <port> <request-size> <num-requests>' % (sys.argv[0])
    else:
        host = sys.argv[1]
        [port, request_size, num_requests] = map (
                string.atoi,
                sys.argv[2:]
                )
        chain = build_request_chain (num_requests, host, request_size)
        import socket
        s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
        s.connect ((host,port))
        t = timer()
        s.send (chain)
        num_bytes = 0
        while 1:
            data = s.recv(16384)
            if not data:
                break
            else:
                num_bytes = num_bytes + len(data)
        total_time = t.end()
        print 'total bytes received: %d' % num_bytes
        print 'total time: %.2f sec' % (total_time)
        print 'transactions/sec: %.2f' % (num_requests/total_time)


=== Added File Zope/lib/python/ZServer/medusa/test/tests.txt ===
# server: linux, 486dx2/66
# client: win95, cyrix 6x86 p166+
# over ethernet.
#
# number of connections
# |     number of requests per connection   
# |        |      packet size
# |        |         |    throughput (bytes/sec)
# |        |         |       |      transactions/sec
# |        |         |       |         |
  1        50        64   3440.86    53.76
  1       100        64   3422.45    53.47
  1         1       256   5120.00    20.00
  1        50       256  13763.44    53.76
  1       100       256  13333.33    52.08
  1         1      1024   6400.00     6.25
  1        50      1024   6909.58     6.74
  1       100      1024   6732.41     6.57
  1         1      4096  14628.56     3.57
  1        50      4096  17181.20     4.19
  1       100      4096  16835.18     4.11
  5         1        64   1882.35    29.41
  5        50        64   3990.02    62.34
  5       100        64   3907.20    61.05
  5         1       256   5818.18    22.72
  5        50       256  15533.98    60.67
  5       100       256  15744.15    61.50
  5         1      1024  15515.14    15.15
  5        50      1024  23188.40    22.64
  5       100      1024  23659.88    23.10
  5         1      4096  28444.44     6.94
  5        50      4096  34913.05     8.52
  5       100      4096  35955.05     8.77
 10         1        64    191.04     2.98
 10        50        64   4045.51    63.21
 10       100        64   4045.51    63.21
 10         1       256    764.17     2.98
 10        50       256  15552.85    60.75
 10       100       256  15581.25    60.86
 10         1      1024   2959.53     2.89
 10        50      1024  25061.18    24.47
 10       100      1024  25498.00    24.90
 10         1      4096  11314.91     2.76
 10        50      4096  39002.09     9.52
 10       100      4096  38780.53     9.46
 15         1        64    277.45     4.33
 15        50        64   4067.79    63.55
 15       100        64   4083.36    63.80
 15         1       256    386.31     1.50
 15        50       256  15262.32    59.61
 15       100       256  15822.00    61.80
 15         1      1024   1528.35     1.49
 15        50      1024  27263.04    26.62
 15       100      1024  27800.90    27.14
 15         1      4096   6047.24     1.47
 15        50      4096  39695.05     9.69
 15       100      4096  37112.65     9.06
 20         1        64    977.09    15.26
 20        50        64   2538.67    39.66
 20       100        64   3377.30    52.77
 20         1       256    221.93     0.86
 20        50       256  10815.37    42.24
 20       100       256  15880.89    62.03
 20         1      1024    883.52     0.86
 20        50      1024  29315.77    28.62
 20       100      1024  29569.73    28.87
 20         1      4096   7892.10     1.92
 20        50      4096  40223.90     9.82
 20       100      4096  41325.73    10.08
# 
# There's a big gap in trans/sec between 256 and 1024 bytes, we should
# probably stick a 512 in there.
#