Merge branch 'stable-2.6-esi' into stable-2.6-ippool-hotplug-esi
[ganeti-local] / test / lockperf.py
1 #!/usr/bin/python
2 #
3
4 # Copyright (C) 2011 Google Inc.
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 # 02110-1301, USA.
20
21
22 """Script for testing lock performance"""
23
24 import os
25 import sys
26 import time
27 import optparse
28 import threading
29 import resource
30
31 from ganeti import locking
32
33
34 def ParseOptions():
35   """Parses the command line options.
36
37   In case of command line errors, it will show the usage and exit the
38   program.
39
40   @return: the options in a tuple
41
42   """
43   parser = optparse.OptionParser()
44   parser.add_option("-t", dest="thread_count", default=1, type="int",
45                     help="Number of threads", metavar="NUM")
46   parser.add_option("-d", dest="duration", default=5, type="float",
47                     help="Duration", metavar="SECS")
48
49   (opts, args) = parser.parse_args()
50
51   if opts.thread_count < 1:
52     parser.error("Number of threads must be at least 1")
53
54   return (opts, args)
55
56
57 class State:
58   def __init__(self, thread_count):
59     """Initializes this class.
60
61     """
62     self.verify = [0 for _ in range(thread_count)]
63     self.counts = [0 for _ in range(thread_count)]
64     self.total_count = 0
65
66
67 def _Counter(lock, state, me):
68   """Thread function for acquiring locks.
69
70   """
71   counts = state.counts
72   verify = state.verify
73
74   while True:
75     lock.acquire()
76     try:
77       verify[me] = 1
78
79       counts[me] += 1
80
81       state.total_count += 1
82
83       if state.total_count % 1000 == 0:
84         sys.stdout.write(" %8d\r" % state.total_count)
85         sys.stdout.flush()
86
87       if sum(verify) != 1:
88         print "Inconsistent state!"
89         os._exit(1) # pylint: disable=W0212
90
91       verify[me] = 0
92     finally:
93       lock.release()
94
95
96 def main():
97   (opts, _) = ParseOptions()
98
99   lock = locking.SharedLock("TestLock")
100
101   state = State(opts.thread_count)
102
103   lock.acquire(shared=0)
104   try:
105     for i in range(opts.thread_count):
106       t = threading.Thread(target=_Counter, args=(lock, state, i))
107       t.setDaemon(True)
108       t.start()
109
110     start = time.clock()
111   finally:
112     lock.release()
113
114   while True:
115     if (time.clock() - start) > opts.duration:
116       break
117     time.sleep(0.1)
118
119   # Make sure we get a consistent view
120   lock.acquire(shared=0)
121
122   lock_cputime = time.clock() - start
123
124   res = resource.getrusage(resource.RUSAGE_SELF)
125
126   print "Total number of acquisitions: %s" % state.total_count
127   print "Per-thread acquisitions:"
128   for (i, count) in enumerate(state.counts):
129     print ("  Thread %s: %d (%0.1f%%)" %
130            (i, count, (100.0 * count / state.total_count)))
131
132   print "Benchmark CPU time: %0.3fs" % lock_cputime
133   print ("Average time per lock acquisition: %0.5fms" %
134          (1000.0 * lock_cputime / state.total_count))
135   print "Process:"
136   print "  User time: %0.3fs" % res.ru_utime
137   print "  System time: %0.3fs" % res.ru_stime
138   print "  Total time: %0.3fs" % (res.ru_utime + res.ru_stime)
139
140   # Exit directly without attempting to clean up threads
141   os._exit(0) # pylint: disable=W0212
142
143
144 if __name__ == "__main__":
145   main()