benchmark.py (8752B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\cherrypy\test\benchmark.py 2 import getopt 3 import os 4 curdir = os.path.join(os.getcwd(), os.path.dirname(__file__)) 5 import re 6 import sys 7 import time 8 import traceback 9 import cherrypy 10 from cherrypy._cpcompat import ntob 11 from cherrypy import _cperror, _cpmodpy 12 from cherrypy.lib import httputil 13 AB_PATH = '' 14 APACHE_PATH = 'apache' 15 SCRIPT_NAME = '/cpbench/users/rdelon/apps/blog' 16 __all__ = ['ABSession', 17 'Root', 18 'print_report', 19 'run_standard_benchmarks', 20 'safe_threads', 21 'size_report', 22 'startup', 23 'thread_report'] 24 size_cache = {} 25 26 class Root: 27 28 def index(self): 29 return '<html>\n<head>\n <title>CherryPy Benchmark</title>\n</head>\n<body>\n <ul>\n <li><a href="hello">Hello, world! (14 byte dynamic)</a></li>\n <li><a href="static/index.html">Static file (14 bytes static)</a></li>\n <li><form action="sizer">Response of length:\n <input type=\'text\' name=\'size\' value=\'10\' /></form>\n </li>\n </ul>\n</body>\n</html>' 30 31 index.exposed = True 32 33 def hello(self): 34 return 'Hello, world\r\n' 35 36 hello.exposed = True 37 38 def sizer(self, size): 39 resp = size_cache.get(size, None) 40 if resp is None: 41 size_cache[size] = resp = 'X' * int(size) 42 return resp 43 44 sizer.exposed = True 45 46 47 cherrypy.config.update({'log.error.file': '', 48 'environment': 'production', 49 'server.socket_host': '127.0.0.1', 50 'server.socket_port': 8080, 51 'server.max_request_header_size': 0, 52 'server.max_request_body_size': 0, 53 'engine.deadlock_poll_freq': 0}) 54 del cherrypy.config['tools.log_tracebacks.on'] 55 del cherrypy.config['tools.log_headers.on'] 56 del cherrypy.config['tools.trailing_slash.on'] 57 appconf = {'/static': {'tools.staticdir.on': True, 58 'tools.staticdir.dir': 'static', 59 'tools.staticdir.root': curdir}} 60 app = cherrypy.tree.mount(Root(), SCRIPT_NAME, appconf) 61 62 class NullRequest: 63 64 def __init__(self, local, remote, scheme = 'http'): 65 pass 66 67 def close(self): 68 pass 69 70 def run(self, method, path, query_string, protocol, headers, rfile): 71 cherrypy.response.status = '200 OK' 72 cherrypy.response.header_list = [('Content-Type', 'text/html'), 73 ('Server', 'Null CherryPy'), 74 ('Date', httputil.HTTPDate()), 75 ('Content-Length', '0')] 76 cherrypy.response.body = [''] 77 return cherrypy.response 78 79 80 class NullResponse: 81 pass 82 83 84 class ABSession: 85 parse_patterns = [('complete_requests', 'Completed', ntob('^Complete requests:\\s*(\\d+)')), 86 ('failed_requests', 'Failed', ntob('^Failed requests:\\s*(\\d+)')), 87 ('requests_per_second', 'req/sec', ntob('^Requests per second:\\s*([0-9.]+)')), 88 ('time_per_request_concurrent', 'msec/req', ntob('^Time per request:\\s*([0-9.]+).*concurrent requests\\)$')), 89 ('transfer_rate', 'KB/sec', ntob('^Transfer rate:\\s*([0-9.]+)'))] 90 91 def __init__(self, path = SCRIPT_NAME + '/hello', requests = 1000, concurrency = 10): 92 self.path = path 93 self.requests = requests 94 self.concurrency = concurrency 95 96 def args(self): 97 port = cherrypy.server.socket_port 98 return '-k -n %s -c %s http://127.0.0.1:%s%s' % (self.requests, 99 self.concurrency, 100 port, 101 self.path) 102 103 def run(self): 104 global AB_PATH 105 try: 106 self.output = _cpmodpy.read_process(AB_PATH or 'ab', self.args()) 107 except: 108 print _cperror.format_exc() 109 raise 110 111 for attr, name, pattern in self.parse_patterns: 112 val = re.search(pattern, self.output, re.MULTILINE) 113 if val: 114 val = val.group(1) 115 setattr(self, attr, val) 116 else: 117 setattr(self, attr, None) 118 119 120 safe_threads = (25, 50, 100, 200, 400) 121 if sys.platform in ('win32',): 122 safe_threads = (10, 20, 30, 40, 50) 123 124 def thread_report(path = SCRIPT_NAME + '/hello', concurrency = safe_threads): 125 sess = ABSession(path) 126 attrs, names, patterns = list(zip(*sess.parse_patterns)) 127 avg = dict.fromkeys(attrs, 0.0) 128 yield ('threads',) + names 129 for c in concurrency: 130 sess.concurrency = c 131 sess.run() 132 row = [c] 133 for attr in attrs: 134 val = getattr(sess, attr) 135 if val is None: 136 print sess.output 137 row = None 138 break 139 val = float(val) 140 avg[attr] += float(val) 141 row.append(val) 142 143 if row: 144 yield row 145 146 yield ['Average'] + [ str(avg[attr] / len(concurrency)) for attr in attrs ] 147 148 149 def size_report(sizes = (10, 100, 1000, 10000, 100000, 100000000), concurrency = 50): 150 sess = ABSession(concurrency=concurrency) 151 attrs, names, patterns = list(zip(*sess.parse_patterns)) 152 yield ('bytes',) + names 153 for sz in sizes: 154 sess.path = '%s/sizer?size=%s' % (SCRIPT_NAME, sz) 155 sess.run() 156 yield [sz] + [ getattr(sess, attr) for attr in attrs ] 157 158 159 def print_report(rows): 160 for row in rows: 161 print '' 162 for i, val in enumerate(row): 163 sys.stdout.write(str(val).rjust(10) + ' | ') 164 165 print '' 166 167 168 def run_standard_benchmarks(): 169 print '' 170 print 'Client Thread Report (1000 requests, 14 byte response body, %s server threads):' % cherrypy.server.thread_pool 171 print_report(thread_report()) 172 print '' 173 print 'Client Thread Report (1000 requests, 14 bytes via staticdir, %s server threads):' % cherrypy.server.thread_pool 174 print_report(thread_report('%s/static/index.html' % SCRIPT_NAME)) 175 print '' 176 print 'Size Report (1000 requests, 50 client threads, %s server threads):' % cherrypy.server.thread_pool 177 print_report(size_report()) 178 179 180 def startup_modpython(req = None): 181 global AB_PATH 182 if cherrypy.engine.state == cherrypy._cpengine.STOPPED: 183 if req: 184 if 'nullreq' in req.get_options(): 185 cherrypy.engine.request_class = NullRequest 186 cherrypy.engine.response_class = NullResponse 187 ab_opt = req.get_options().get('ab', '') 188 if ab_opt: 189 AB_PATH = ab_opt 190 cherrypy.engine.start() 191 if cherrypy.engine.state == cherrypy._cpengine.STARTING: 192 cherrypy.engine.wait() 193 return 0 194 195 196 def run_modpython(use_wsgi = False): 197 print 'Starting mod_python...' 198 pyopts = [] 199 if '--null' in opts: 200 pyopts.append(('nullreq', '')) 201 if '--ab' in opts: 202 pyopts.append(('ab', opts['--ab'])) 203 s = _cpmodpy.ModPythonServer 204 if use_wsgi: 205 pyopts.append(('wsgi.application', 'cherrypy::tree')) 206 pyopts.append(('wsgi.startup', 'cherrypy.test.benchmark::startup_modpython')) 207 handler = 'modpython_gateway::handler' 208 s = s(port=8080, opts=pyopts, apache_path=APACHE_PATH, handler=handler) 209 else: 210 pyopts.append(('cherrypy.setup', 'cherrypy.test.benchmark::startup_modpython')) 211 s = s(port=8080, opts=pyopts, apache_path=APACHE_PATH) 212 try: 213 s.start() 214 run() 215 finally: 216 s.stop() 217 218 219 if __name__ == '__main__': 220 longopts = ['cpmodpy', 221 'modpython', 222 'null', 223 'notests', 224 'help', 225 'ab=', 226 'apache='] 227 try: 228 switches, args = getopt.getopt(sys.argv[1:], '', longopts) 229 opts = dict(switches) 230 except getopt.GetoptError: 231 print __doc__ 232 sys.exit(2) 233 234 if '--help' in opts: 235 print __doc__ 236 sys.exit(0) 237 if '--ab' in opts: 238 AB_PATH = opts['--ab'] 239 if '--notests' in opts: 240 241 def run(): 242 port = cherrypy.server.socket_port 243 print 'You may now open http://127.0.0.1:%s%s/' % (port, SCRIPT_NAME) 244 if '--null' in opts: 245 print 'Using null Request object' 246 247 248 else: 249 250 def run(): 251 end = time.time() - start 252 print 'Started in %s seconds' % end 253 if '--null' in opts: 254 print '\nUsing null Request object' 255 try: 256 run_standard_benchmarks() 257 except: 258 print _cperror.format_exc() 259 raise 260 finally: 261 cherrypy.engine.exit() 262 263 264 print 'Starting CherryPy app server...' 265 266 class NullWriter(object): 267 268 def write(self, data): 269 pass 270 271 272 sys.stderr = NullWriter() 273 start = time.time() 274 if '--cpmodpy' in opts: 275 run_modpython() 276 elif '--modpython' in opts: 277 run_modpython(use_wsgi=True) 278 else: 279 if '--null' in opts: 280 cherrypy.server.request_class = NullRequest 281 cherrypy.server.response_class = NullResponse 282 cherrypy.engine.start_with_callback(run) 283 cherrypy.engine.block()