[pypy-svn] r76659 - in pypy/benchmarks: . own
cfbolz at codespeak.net
cfbolz at codespeak.net
Tue Aug 17 17:59:51 CEST 2010
Author: cfbolz
Date: Tue Aug 17 17:59:50 2010
New Revision: 76659
Added:
pypy/benchmarks/own/interpreter.tar.bz2 (contents, props changed)
pypy/benchmarks/own/pyflate-fast.py (contents, props changed)
Modified:
pypy/benchmarks/benchmarks.py
Log:
(cfbolz, arigo): yet another benchmark: a pure-Python bz2 decoder
Modified: pypy/benchmarks/benchmarks.py
==============================================================================
--- pypy/benchmarks/benchmarks.py (original)
+++ pypy/benchmarks/benchmarks.py Tue Aug 17 17:59:50 2010
@@ -44,7 +44,7 @@
}
for name in ['float', 'nbody_modified', 'meteor-contest', 'fannkuch',
- 'spectral-norm', 'chaos', 'telco', 'go']:
+ 'spectral-norm', 'chaos', 'telco', 'go', 'pyflate-fast']:
_register_new_bm(name, name, globals(), **opts.get(name, {}))
for name in ['names', 'iteration', 'tcp', 'pb']:#, 'accepts', 'web']:
if name == 'web':
Added: pypy/benchmarks/own/interpreter.tar.bz2
==============================================================================
Binary file. No diff available.
Added: pypy/benchmarks/own/pyflate-fast.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/own/pyflate-fast.py Tue Aug 17 17:59:50 2010
@@ -0,0 +1,684 @@
+#!/usr/bin/env python
+# Copyright 2006--2007-01-21 Paul Sladen
+# http://www.paul.sladen.org/projects/compression/
+#
+# You may use and distribute this code under any DFSG-compatible
+# license (eg. BSD, GNU GPLv2).
+#
+# Stand-alone pure-Python DEFLATE (gzip) and bzip2 decoder/decompressor.
+# This is probably most useful for research purposes/index building; there
+# is certainly some room for improvement in the Huffman bit-matcher.
+#
+# With the as-written implementation, there was a known bug in BWT
+# decoding to do with repeated strings. This has been worked around;
+# see 'bwt_reverse()'. Correct output is produced in all test cases
+# but ideally the problem would be found...
+
+class BitfieldBase(object):
+ def __init__(self, x):
+ if isinstance(x,BitfieldBase):
+ self.f = x.f
+ self.bits = x.bits
+ self.bitfield = x.bitfield
+ self.count = x.bitfield
+ else:
+ self.f = x
+ self.bits = 0
+ self.bitfield = 0x0
+ self.count = 0
+ def _read(self, n):
+ s = self.f.read(n)
+ if not s:
+ raise "Length Error"
+ self.count += len(s)
+ return s
+ def needbits(self, n):
+ while self.bits < n:
+ self._more()
+ def _mask(self, n):
+ return (1 << n) - 1
+ def toskip(self):
+ return self.bits & 0x7
+ def align(self):
+ self.readbits(self.toskip())
+ def dropbits(self, n = 8):
+ while n >= self.bits and n > 7:
+ n -= self.bits
+ self.bits = 0
+ n -= len(self.f._read(n >> 3)) << 3
+ if n:
+ self.readbits(n)
+ # No return value
+ def dropbytes(self, n = 1):
+ self.dropbits(n << 3)
+ def tell(self):
+ return self.count - ((self.bits+7) >> 3), 7 - ((self.bits-1) & 0x7)
+ def tellbits(self):
+ bytes, bits = self.tell()
+ return (bytes << 3) + bits
+
+class Bitfield(BitfieldBase):
+ def _more(self):
+ c = self._read(1)
+ self.bitfield += ord(c) << self.bits
+ self.bits += 8
+ def snoopbits(self, n = 8):
+ if n > self.bits:
+ self.needbits(n)
+ return self.bitfield & self._mask(n)
+ def readbits(self, n = 8):
+ if n > self.bits:
+ self.needbits(n)
+ r = self.bitfield & self._mask(n)
+ self.bits -= n
+ self.bitfield >>= n
+ return r
+
+class RBitfield(BitfieldBase):
+ def _more(self):
+ c = self._read(1)
+ self.bitfield <<= 8
+ self.bitfield += ord(c)
+ self.bits += 8
+ def snoopbits(self, n = 8):
+ if n > self.bits:
+ self.needbits(n)
+ return (self.bitfield >> (self.bits - n)) & self._mask(n)
+ def readbits(self, n = 8):
+ if n > self.bits:
+ self.needbits(n)
+ r = (self.bitfield >> (self.bits - n)) & self._mask(n)
+ self.bits -= n
+ self.bitfield &= ~(self._mask(n) << self.bits)
+ return r
+
+def printbits(v, n):
+ o = ''
+ for i in range(n):
+ if v & 1:
+ o = '1' + o
+ else:
+ o = '0' + o
+ v >>= 1
+ return o
+
+class HuffmanLength(object):
+ def __init__(self, code, bits = 0):
+ self.code = code
+ self.bits = bits
+ self.symbol = None
+ def __repr__(self):
+ return `(self.code, self.bits, self.symbol, self.reverse_symbol)`
+ def __cmp__(self, other):
+ if self.bits == other.bits:
+ return cmp(self.code, other.code)
+ else:
+ return cmp(self.bits, other.bits)
+
+def reverse_bits(v, n):
+ a = 1 << 0
+ b = 1 << (n - 1)
+ z = 0
+ for i in range(n-1, -1, -2):
+ z |= (v >> i) & a
+ z |= (v << i) & b
+ a <<= 1
+ b >>= 1
+ return z
+
+def reverse_bytes(v, n):
+ a = 0xff << 0
+ b = 0xff << (n - 8)
+ z = 0
+ for i in range(n-8, -8, -16):
+ z |= (v >> i) & a
+ z |= (v << i) & b
+ a <<= 8
+ b >>= 8
+ return z
+
+class HuffmanTable(object):
+ def __init__(self, bootstrap):
+ l = []
+ start, bits = bootstrap[0]
+ for finish, endbits in bootstrap[1:]:
+ if bits:
+ for code in range(start, finish):
+ l.append(HuffmanLength(code, bits))
+ start, bits = finish, endbits
+ if endbits == -1:
+ break
+ l.sort()
+ self.table = l
+
+ def populate_huffman_symbols(self):
+ bits, symbol = -1, -1
+ for x in self.table:
+ symbol += 1
+ if x.bits != bits:
+ symbol <<= (x.bits - bits)
+ bits = x.bits
+ x.symbol = symbol
+ x.reverse_symbol = reverse_bits(symbol, bits)
+ #print printbits(x.symbol, bits), printbits(x.reverse_symbol, bits)
+
+ def tables_by_bits(self):
+ d = {}
+ for x in self.table:
+ try:
+ d[x.bits].append(x)
+ except:
+ d[x.bits] = [x]
+ pass
+
+ def min_max_bits(self):
+ self.min_bits, self.max_bits = 16, -1
+ for x in self.table:
+ if x.bits < self.min_bits: self.min_bits = x.bits
+ if x.bits > self.max_bits: self.max_bits = x.bits
+
+ def _find_symbol(self, bits, symbol, table):
+ for h in table:
+ if h.bits == bits and h.reverse_symbol == symbol:
+ #print "found, processing", h.code
+ return h.code
+ return -1
+
+ def find_next_symbol(self, field, reversed = True):
+ cached_length = -1
+ cached = None
+ for x in self.table:
+ if cached_length != x.bits:
+ cached = field.snoopbits(x.bits)
+ cached_length = x.bits
+ if (reversed and x.reverse_symbol == cached) or (not reversed and x.symbol == cached):
+ field.readbits(x.bits)
+ return x.code
+ raise "unfound symbol, even after end of table @ " + `field.tell()`
+
+ for bits in range(self.min_bits, self.max_bits + 1):
+ #print printbits(field.snoopbits(bits),bits)
+ r = self._find_symbol(bits, field.snoopbits(bits), self.table)
+ if 0 <= r:
+ field.readbits(bits)
+ return r
+ elif bits == self.max_bits:
+ raise "unfound symbol, even after max_bits"
+
+class OrderedHuffmanTable(HuffmanTable):
+ def __init__(self, lengths):
+ l = len(lengths)
+ z = zip(range(l), lengths) + [(l, -1)]
+ HuffmanTable.__init__(self, z)
+
+def code_length_orders(i):
+ return (16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15)[i]
+
+def distance_base(i):
+ return (1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577)[i]
+
+def length_base(i):
+ return (3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258)[i-257]
+
+def extra_distance_bits(n):
+ if 0 <= n <= 1:
+ return 0
+ elif 2 <= n <= 29:
+ return (n >> 1) - 1
+ else:
+ raise "illegal distance code"
+
+def extra_length_bits(n):
+ if 257 <= n <= 260 or n == 285:
+ return 0
+ elif 261 <= n <= 284:
+ return ((n-257) >> 2) - 1
+ else:
+ raise "illegal length code"
+
+def move_to_front(l, c):
+ l[:] = l[c:c+1] + l[0:c] + l[c+1:]
+
+def bwt_transform(L):
+ # Semi-inefficient way to get the character counts
+ F = ''.join(sorted(L))
+ base = []
+ for i in range(256):
+ base.append(F.find(chr(i)))
+
+ pointers = [-1] * len(L)
+ for i, char in enumerate(L):
+ symbol = ord(char)
+ pointers[base[symbol]] = i
+ base[symbol] += 1
+ return pointers
+
+def bwt_reverse(L, end):
+ out = []
+ if len(L):
+ T = bwt_transform(L)
+
+ # STRAGENESS WARNING: There was a bug somewhere here in that
+ # if the output of the BWT resolves to a perfect copy of N
+ # identical strings (think exact multiples of 255 'X' here),
+ # then a loop is formed. When decoded, the output string would
+ # be cut off after the first loop, typically '\0\0\0\0\xfb'.
+ # The previous loop construct was:
+ #
+ # next = T[end]
+ # while next != end:
+ # out += L[next]
+ # next = T[next]
+ # out += L[next]
+ #
+ # For the moment, I've instead replaced it with a check to see
+ # if there has been enough output generated. I didn't figured
+ # out where the off-by-one-ism is yet---that actually produced
+ # the cyclic loop.
+
+ for i in xrange(len(L)):
+ end = T[end]
+ out.append(L[end])
+
+ return "".join(out)
+
+def compute_used(b):
+ huffman_used_map = b.readbits(16)
+ #print 'used map', hex(huffman_used_map)
+ map_mask = 1 << 15
+ used = []
+ while map_mask > 0:
+ if huffman_used_map & map_mask:
+ huffman_used_bitmap = b.readbits(16)
+ bit_mask = 1 << 15
+ while bit_mask > 0:
+ if huffman_used_bitmap & bit_mask:
+ #print 'hit', len(used)
+ pass
+ used += [bool(huffman_used_bitmap & bit_mask)]
+ bit_mask >>= 1
+ else:
+ used += [False] * 16
+ map_mask >>= 1
+ return used
+
+def compute_selectors_list(b, huffman_groups):
+ selectors_used = b.readbits(15)
+ #print 'selectors used', selectors_used
+ mtf = range(huffman_groups)
+ selectors_list = []
+ for i in range(selectors_used):
+ # zero-terminated bit runs (0..62) of MTF'ed huffman table
+ c = 0
+ while b.readbits(1):
+ c += 1
+ if c >= huffman_groups:
+ raise "Bzip2 chosen selector greater than number of groups (max 6)"
+ if c >= 0:
+ move_to_front(mtf, c)
+ #print c, mtf
+ selectors_list.append(mtf[0])
+ return selectors_list
+
+def compute_tables(b, huffman_groups, symbols_in_use):
+ groups_lengths = []
+ for j in range(huffman_groups):
+ length = start_huffman_length = b.readbits(5)
+ #print 'start_huffman_length', start_huffman_length
+ lengths = []
+ for i in range(symbols_in_use):
+ if not 0 <= length <= 20:
+ raise "Bzip2 Huffman length code outside range 0..20"
+ while b.readbits(1):
+ length -= (b.readbits(1) * 2) - 1
+ lengths += [length]
+ groups_lengths += [lengths]
+ #print groups_lengths
+
+ tables = []
+ for g in groups_lengths:
+ codes = OrderedHuffmanTable(g)
+ codes.populate_huffman_symbols()
+ codes.min_max_bits()
+ tables.append(codes)
+ return tables
+
+def decode_huffman_block(b, out):
+ #print 'bzip2 Huffman block'
+ randomised = b.readbits(1)
+ if randomised:
+ raise "Bzip2 randomised support not implemented"
+ pointer = b.readbits(24)
+ #print 'pointer', pointer, hex(pointer)
+ used = compute_used(b)
+
+ huffman_groups = b.readbits(3)
+ #print 'huffman groups', huffman_groups
+ if not 2 <= huffman_groups <= 6:
+ raise "Bzip2: Number of Huffman groups not in range 2..6"
+
+ selectors_list = compute_selectors_list(b, huffman_groups)
+ symbols_in_use = sum(used) + 2 # remember RUN[AB] RLE symbols
+ tables = compute_tables(b, huffman_groups, symbols_in_use)
+
+ #favourites = map(chr,range(sum(used)))
+ #favourites = string.join([y for x,y in map(None,used,map(chr,range(len(used)))) if x],'')
+ favourites = [chr(i) for i, x in enumerate(used) if x]
+
+ data_start = b.tellbits()
+ selector_pointer = 0
+ decoded = 0
+ # Main Huffman loop
+ repeat = repeat_power = 0
+ buffer = []
+ t = None
+ while True:
+ decoded -= 1
+ if decoded <= 0:
+ #print 'RETABLE TIME', selectors_list[selector_pointer]
+ decoded = 50 # Huffman table re-evaluate/switch length
+ if selector_pointer <= len(selectors_list):
+ t = tables[selectors_list[selector_pointer]]
+ selector_pointer += 1
+ #print 'tables changed', tables[0].table
+ #print b.tell()
+ r = t.find_next_symbol(b, False)
+ #print 'symbol', r
+ if 0 <= r <= 1:
+ if repeat == 0:
+ repeat_power = 1
+ #print 'run', repeat
+ repeat += repeat_power << r
+ repeat_power <<= 1
+ continue
+ elif repeat > 0:
+ # Remember kids: If there is only one repeated
+ # real symbol, it is encoded with *zero* Huffman
+ # bits and not output... so buffer[-1] doesn't work.
+ #print 'runfinal', repeat
+ buffer.append(favourites[0] * repeat)
+ repeat = 0
+ if r == symbols_in_use - 1:
+ #print 'finished', `buffer[:10]`, '..', `buffer[-10:]`, 'len', len(buffer)
+ break
+ else:
+ o = favourites[r-1]
+ #print 'pre ', `favourites`
+ move_to_front(favourites, r-1)
+ #print 'post', `favourites`
+ #print 'output', `o`
+ buffer.append(o)
+ pass
+ #print 'huffman', `buffer`, pointer, len(buffer)
+ #nearly_there = bwt_reverse(buffer, len(buffer)-pointer-1)
+ nt = nearly_there = bwt_reverse("".join(buffer), pointer)
+ #print 'nearly there', `nearly_there`
+ i = 0
+ # Pointless/irritating run-length encoding step
+ while i < len(nearly_there):
+ #print 'RLE decode', `nt[i:]`
+ if i < len(nearly_there) - 4 and nt[i] == nt[i+1] == nt[i+2] == nt[i+3]:
+ out.append(nearly_there[i] * (ord(nearly_there[i+4]) + 4))
+ i += 5
+ else:
+ out.append(nearly_there[i])
+ i += 1
+ #print 'done', `done[:10]`, '..', `done[-10:]`, 'len', len(done)
+
+ #raise "Bip2 block support not implemented"
+
+# Sixteen bits of magic have been removed by the time we start decoding
+def bzip2_main(input):
+ b = RBitfield(input)
+
+ method = b.readbits(8)
+ if method != ord('h'):
+ raise "Unknown (not type 'h'uffman Bzip2) compression method"
+
+ blocksize = b.readbits(8)
+ if ord('1') <= blocksize <= ord('9'):
+ blocksize = blocksize - ord('0')
+ else:
+ raise "Unknown (not size '0'-'9') Bzip2 blocksize"
+
+ out = []
+ while True:
+ #header_start = b.tellbits()
+ blocktype = b.readbits(48)
+ crc = b.readbits(32)
+ #print hex(blocktype)
+ #print hex(crc)
+ if blocktype == 0x314159265359: # (pi)
+ decode_huffman_block(b, out)
+ elif blocktype == 0x177245385090: # sqrt(pi)
+ #print 'bzip2 end-of-stream block'
+ b.align()
+ break
+ else:
+ raise "Illegal Bzip2 blocktype"
+ #print len(out), set([len(s) for s in out])
+ return ''.join(out)
+
+# Sixteen bits of magic have been removed by the time we start decoding
+def gzip_main(field):
+ b = Bitfield(field)
+ method = b.readbits(8)
+ if method != 8:
+ raise "Unknown (not type eight DEFLATE) compression method"
+
+ # Use flags, drop modification time, extra flags and OS creator type.
+ flags = b.readbits(8)
+ #print 'flags', hex(flags)
+ mtime = b.readbits(32)
+ #print 'mtime', hex(mtime)
+ extra_flags = b.readbits(8)
+ #print 'extra_flags', hex(extra_flags)
+ os_type = b.readbits(8)
+ #print 'os_type', hex(os_type)
+
+ if flags & 0x04: # structured GZ_FEXTRA miscellaneous data
+ xlen = b.readbits(16)
+ b.dropbytes(xlen)
+ while flags & 0x08: # original GZ_FNAME filename
+ if not b.readbits(8):
+ break
+ while flags & 0x10: # human readable GZ_FCOMMENT
+ if not b.readbits(8):
+ break
+ if flags & 0x02: # header-only GZ_FHCRC checksum
+ b.readbits(16)
+
+ #print "gzip header skip", b.tell()
+ out = []
+
+ #print 'header 0 count 0 bits', b.tellbits()
+
+ while True:
+ header_start = b.tell()
+ bheader_start = b.tellbits()
+ #print 'new block at', b.tell()
+ lastbit = b.readbits(1)
+ #print "last bit", hex(lastbit)
+ blocktype = b.readbits(2)
+ #print "deflate-blocktype", blocktype, 'beginning at', header_start
+
+ #print 'raw block data at', b.tell()
+ if blocktype == 0:
+ b.align()
+ length = b.readbits(16)
+ if length & b.readbits(16):
+ raise "stored block lengths do not match each other"
+ #print "stored block of length", length
+ #print 'raw data at', b.tell(), 'bits', b.tellbits() - bheader_start
+ #print 'header 0 count 0 bits', b.tellbits() - bheader_start
+ for i in range(length):
+ out.append(chr(b.readbits(8)))
+ #print 'linear', b.tell()[0], 'count', length, 'bits', b.tellbits() - bheader_start
+
+ elif blocktype == 1 or blocktype == 2: # Huffman
+ main_literals, main_distances = None, None
+
+ if blocktype == 1: # Static Huffman
+ static_huffman_bootstrap = [(0, 8), (144, 9), (256, 7), (280, 8), (288, -1)]
+ static_huffman_lengths_bootstrap = [(0, 5), (32, -1)]
+ main_literals = HuffmanTable(static_huffman_bootstrap)
+ main_distances = HuffmanTable(static_huffman_lengths_bootstrap)
+
+ elif blocktype == 2: # Dynamic Huffman
+ literals = b.readbits(5) + 257
+ distances = b.readbits(5) + 1
+ code_lengths_length = b.readbits(4) + 4
+
+ l = [0] * 19
+ for i in range(code_lengths_length):
+ l[code_length_orders(i)] = b.readbits(3)
+
+ dynamic_codes = OrderedHuffmanTable(l)
+ dynamic_codes.populate_huffman_symbols()
+ dynamic_codes.min_max_bits()
+
+ # Decode the code_lengths for both tables at once,
+ # then split the list later
+
+ code_lengths = []
+ n = 0
+ while n < (literals + distances):
+ r = dynamic_codes.find_next_symbol(b)
+ if 0 <= r <= 15: # literal bitlength for this code
+ count = 1
+ what = r
+ elif r == 16: # repeat last code
+ count = 3 + b.readbits(2)
+ # Is this supposed to default to '0' if in the zeroth position?
+ what = code_lengths[-1]
+ elif r == 17: # repeat zero
+ count = 3 + b.readbits(3)
+ what = 0
+ elif r == 18: # repeat zero lots
+ count = 11 + b.readbits(7)
+ what = 0
+ else:
+ raise "next code length is outside of the range 0 <= r <= 18"
+ code_lengths += [what] * count
+ n += count
+
+ main_literals = OrderedHuffmanTable(code_lengths[:literals])
+ main_distances = OrderedHuffmanTable(code_lengths[literals:])
+
+ # Common path for both Static and Dynamic Huffman decode now
+
+ data_start = b.tell()
+ #print 'raw data at', data_start, 'bits', b.tellbits() - bheader_start
+ #print 'header 0 count 0 bits', b.tellbits() - bheader_start
+
+ main_literals.populate_huffman_symbols()
+ main_distances.populate_huffman_symbols()
+
+ main_literals.min_max_bits()
+ main_distances.min_max_bits()
+
+ literal_count = 0
+ literal_start = 0
+
+ while True:
+ lz_start = b.tellbits()
+ r = main_literals.find_next_symbol(b)
+ if 0 <= r <= 255:
+ if literal_count == 0:
+ literal_start = lz_start
+ literal_count += 1
+ #print 'found literal', `chr(r)`
+ out.append(chr(r))
+ elif r == 256:
+ if literal_count > 0:
+ #print 'add 0 count', literal_count, 'bits', lz_start-literal_start, 'data', `out[-literal_count:]`
+ literal_count = 0
+ #print 'eos 0 count 0 bits', b.tellbits() - lz_start
+ #print 'end of Huffman block encountered'
+ break
+ elif 257 <= r <= 285: # dictionary lookup
+ if literal_count > 0:
+ #print 'add 0 count', literal_count, 'bits', lz_start-literal_start, 'data', `out[-literal_count:]`
+ literal_count = 0
+ length_extra = b.readbits(extra_length_bits(r))
+ length = length_base(r) + length_extra
+ #print 'dictionary lookup: length', length,
+
+ r1 = main_distances.find_next_symbol(b)
+ if 0 <= r1 <= 29:
+ distance = distance_base(r1) + b.readbits(extra_distance_bits(r1))
+ cached_length = length
+ while length > distance:
+ out += out[-distance:]
+ length -= distance
+ if length == distance:
+ out += out[-distance:]
+ else:
+ out += out[-distance:length-distance]
+ #print 'copy', -distance, 'count', cached_length, 'bits', b.tellbits() - lz_start, 'data', `out[-cached_length:]`
+ elif 30 <= r1 <= 31:
+ raise "illegal unused distance symbol in use @" + `b.tell()`
+ elif 286 <= r <= 287:
+ raise "illegal unused literal/length symbol in use @" + `b.tell()`
+ elif blocktype == 3:
+ raise "illegal unused blocktype in use @" + `b.tell()`
+
+ if lastbit:
+ #print "this was the last block, time to leave", b.tell()
+ break
+
+ footer_start = b.tell()
+ bfooter_start = b.tellbits()
+ b.align()
+ crc = b.readbits(32)
+ final_length = b.readbits(32)
+ #print len(out)
+ next_unused = b.tell()
+ #print 'deflate-end-of-stream', 5, 'beginning at', footer_start, 'raw data at', next_unused, 'bits', b.tellbits() - bfooter_start
+ #print 'deflate-end-of-stream'
+ #print 'crc', hex(crc), 'final length', final_length
+ #print 'header 0 count 0 bits', b.tellbits()-bfooter_start
+
+ return "".join(out)
+
+import sys, os
+
+def _main():
+ filename = os.path.join(os.path.dirname(__file__), "interpreter.tar.bz2")
+ input = open(filename)
+ field = RBitfield(input)
+
+ magic = field.readbits(16)
+ if magic == 0x1f8b: # GZip
+ out = gzip_main(field)
+ elif magic == 0x425a: # BZip2
+ out = bzip2_main(field)
+ else:
+ raise "Unknown file magic "+hex(magic)+", not a gzip/bzip2 file"
+
+ import md5
+ assert md5.md5(out).hexdigest() == "afa004a630fe072901b1d9628b960974"
+ input.close()
+
+def main(n):
+ import time
+ times = []
+ for i in range(5):
+ _main() # warmup
+ for i in range(n):
+ t1 = time.time()
+ _main()
+ t2 = time.time()
+ times.append(t2 - t1)
+ return times
+
+if __name__ == "__main__":
+ import util, optparse
+ parser = optparse.OptionParser(
+ usage="%prog [options]",
+ description="Test the performance of the Chaos benchmark")
+ util.add_standard_options_to(parser)
+ options, args = parser.parse_args()
+
+ util.run_benchmark(options, options.num_runs, main)
+
More information about the Pypy-commit
mailing list