222
|
1 #!/usr/bin/python
|
|
2 #
|
|
3 # Silly benchmarking program, to give a vague idea of how fast a few
|
|
4 # tools are on a handful of common operations.
|
|
5 #
|
|
6 # Use a fairly big and real source tarball to test with: Firefox
|
|
7 # 2.0.0.3 (37622 files, 5374 directories, 343MB unpacked onto
|
|
8 # 4KB-blocksize ext3).
|
|
9
|
|
10 import csv
|
|
11 import os
|
|
12 import shutil
|
|
13 import sys
|
|
14 import tempfile
|
|
15 import time
|
|
16 import urllib2
|
|
17
|
|
18 url = 'ftp://ftp.mozilla.org/pub/mozilla.org/firefox/releases/2.0.0.3/source/firefox-2.0.0.3-source.tar.bz2'
|
|
19
|
|
20 class CommandFailure(Exception):
|
|
21 pass
|
|
22
|
|
23 class rcs(object):
|
|
24 def __init__(self):
|
|
25 self.logfp = open(self.__class__.__name__ + '.csv', 'w')
|
|
26 self.csv = csv.writer(self.logfp)
|
|
27
|
|
28 def download(self):
|
|
29 name = url[url.rfind('/')+1:]
|
|
30 path = os.path.join(os.environ['HOME'], name)
|
|
31 if not os.path.isfile(path):
|
|
32 ofp = open(path + '.part', 'wb')
|
|
33 try:
|
|
34 ifp = urllib2.urlopen(url)
|
|
35 nbytes = ifp.info()['content-length']
|
|
36 sys.stdout.write('%s: %s bytes ' % (name, nbytes))
|
|
37 sys.stdout.flush()
|
|
38 while True:
|
|
39 data = ifp.read(131072)
|
|
40 if not data: break
|
|
41 sys.stdout.write('.')
|
|
42 sys.stdout.flush()
|
|
43 ofp.write(data)
|
|
44 del ofp
|
|
45 os.rename(path + '.part', path)
|
|
46 except:
|
|
47 if os.path.exists(path + '.part'):
|
|
48 os.unlink(path + '.part')
|
|
49 if os.path.exists(path):
|
|
50 os.unlink(path)
|
|
51 raise
|
|
52 return path
|
|
53
|
|
54 def run(self, args, mustsucceed=True):
|
|
55 ret = os.spawnvp(os.P_WAIT, args[0], args)
|
|
56 if ret < 0:
|
|
57 msg = 'killed by signal %d' % (-ret)
|
|
58 if ret > 0:
|
|
59 msg = 'exited with status %d' % (ret)
|
|
60 if ret:
|
|
61 if mustsucceed:
|
|
62 raise CommandFailure('%s: %s' % (msg, ' '.join(args)))
|
|
63 print >> sys.stderr, 'WARNING: %s: %s' % (msg, ' '.join(args))
|
|
64
|
|
65 def time(self, *args, **kwargs):
|
|
66 start = time.time()
|
|
67 self.run(*args, **kwargs)
|
|
68 end = time.time()
|
|
69 return end - start
|
|
70
|
|
71 def logtime(self, name, elapsed, rest=[]):
|
|
72 self.log('time:' + name, '%.3f' % elapsed, rest)
|
|
73
|
|
74 def log(self, name, value, rest=[]):
|
|
75 item = (name, value, repr(rest))
|
|
76 print ' '.join(item)
|
|
77 self.csv.writerow(item)
|
|
78 self.logfp.flush()
|
|
79
|
|
80 def unpack(self):
|
|
81 tarball = self.download()
|
|
82 t = self.time(['tar', '-C', self.wdir, '-jxf', tarball])
|
|
83 self.logtime('internal:untar', t)
|
|
84 for name in os.listdir(os.path.join(self.wdir, 'mozilla')):
|
|
85 os.rename(os.path.join(self.wdir, 'mozilla', name),
|
|
86 os.path.join(self.wdir, name))
|
|
87
|
|
88 def cleanup(self):
|
|
89 pass
|
|
90
|
|
91 def add(self, paths):
|
|
92 pass
|
|
93
|
|
94 def commit(self, msg, paths):
|
|
95 pass
|
|
96
|
|
97 def status(self, path):
|
|
98 pass
|
|
99
|
|
100 def remove(self, path):
|
|
101 pass
|
|
102
|
|
103
|
|
104 class subversion(rcs):
|
|
105 def __init__(self, root):
|
|
106 rcs.__init__(self)
|
|
107 self.repo = os.path.join(root, 'repo')
|
|
108 self.wdir = os.path.join(root, 'wc')
|
|
109 create = self.time(['svnadmin', 'create', '--fs-type=fsfs', self.repo])
|
|
110 self.logtime('svn:create', create)
|
|
111 co = self.time(['svn', 'co', 'file://' + self.repo, self.wdir])
|
|
112 self.logtime('svn:co', co)
|
|
113 self.logtime('init', create + co)
|
|
114 os.chdir(self.wdir)
|
|
115
|
|
116 def dropmeta(self, names):
|
|
117 return [n for n in names if os.path.basename(n) != '.svn']
|
|
118
|
|
119 def add(self, paths):
|
|
120 t = self.time(['svn', 'add', '-q'] + paths)
|
|
121 self.logtime('add %r' % paths, t)
|
|
122
|
|
123 def commit(self, msg, paths=[]):
|
|
124 if paths:
|
|
125 t = self.time(['svn', 'ci', '-q', '-m', msg] + paths)
|
|
126 else:
|
|
127 t = self.time(['svn', 'ci', '-q', '-m', msg])
|
|
128 self.logtime('commit %r' % paths, t)
|
|
129
|
|
130
|
|
131 class mercurial(rcs):
|
|
132 def __init__(self, root):
|
|
133 rcs.__init__(self)
|
|
134 self.repo = os.path.join(root, 'repo')
|
|
135 self.wdir = self.repo
|
|
136 init = self.time(['hg', 'init', self.repo])
|
|
137 self.logtime('init', init)
|
|
138 os.chdir(self.wdir)
|
|
139
|
|
140 def dropmeta(self, names):
|
|
141 return [n for n in names if os.path.basename(n) != '.hg']
|
|
142
|
|
143 def add(self, paths):
|
|
144 t = self.time(['hg', 'add', '-q'] + paths)
|
|
145 self.logtime('add %r' % paths, t)
|
|
146
|
|
147 def commit(self, msg, paths=[]):
|
|
148 if paths:
|
|
149 t = self.time(['hg', 'ci', '-q', '-m', msg] + paths)
|
|
150 else:
|
|
151 t = self.time(['hg', 'ci', '-q', '-m', msg])
|
|
152 self.logtime('commit %r' % paths, t)
|
|
153
|
|
154 def benchmark(cls):
|
|
155 oldcwd = os.getcwd()
|
|
156 root = tempfile.mkdtemp(prefix='sillybench.')
|
|
157 try:
|
|
158 print 'root', root
|
|
159 inst = cls(root)
|
|
160 inst.unpack()
|
|
161 names = inst.dropmeta(os.listdir('.'))
|
|
162 dirs = [n for n in names if os.path.isdir(n)]
|
|
163 nondirs = [n for n in names if not os.path.isdir(n)]
|
|
164 dirs.sort(key=hash)
|
|
165 names.sort(key=hash)
|
|
166 for d in dirs[:len(dirs)/2]:
|
|
167 inst.add([d])
|
|
168 inst.commit('Add %r' % d, [d])
|
|
169 inst.add(dirs[len(dirs)/2:] + names)
|
|
170 inst.commit('Add remaining dirs and files')
|
|
171 finally:
|
|
172 print >> sys.stderr, '[cleaning up...]'
|
|
173 shutil.rmtree(root)
|
|
174 os.chdir(oldcwd)
|
|
175
|
|
176 benchmark(mercurial)
|
|
177 #benchmark(subversion)
|