lockperf.py 3.53 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#!/usr/bin/python
#

# Copyright (C) 2011 Google Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.


"""Script for testing lock performance"""

import os
import sys
import time
import optparse
import threading
import resource

from ganeti import locking


def ParseOptions():
  """Parses the command line options.

  In case of command line errors, it will show the usage and exit the
  program.

  @return: the options in a tuple

  """
  parser = optparse.OptionParser()
  parser.add_option("-t", dest="thread_count", default=1, type="int",
                    help="Number of threads", metavar="NUM")
  parser.add_option("-d", dest="duration", default=5, type="float",
                    help="Duration", metavar="SECS")

  (opts, args) = parser.parse_args()

  if opts.thread_count < 1:
    parser.error("Number of threads must be at least 1")

  return (opts, args)


class State:
  def __init__(self, thread_count):
    """Initializes this class.

    """
    self.verify = [False for _ in range(thread_count)]
    self.counts = [0 for _ in range(thread_count)]
    self.total_count = 0


def _Counter(lock, state, me):
  """Thread function for acquiring locks.

  """
  counts = state.counts
  verify = state.verify

  while True:
    lock.acquire()
    try:
      verify[me] = 1

      counts[me] += 1

      state.total_count += 1

      if state.total_count % 1000 == 0:
        sys.stdout.write(" %8d\r" % state.total_count)
        sys.stdout.flush()

      if sum(verify) != 1:
        print "Inconsistent state!"
        os._exit(1) # pylint: disable=W0212

      verify[me] = 0
    finally:
      lock.release()


def main():
  (opts, _) = ParseOptions()

  lock = locking.SharedLock("TestLock")

  state = State(opts.thread_count)

  lock.acquire(shared=0)
  try:
    for i in range(opts.thread_count):
      t = threading.Thread(target=_Counter, args=(lock, state, i))
      t.setDaemon(True)
      t.start()

    start = time.clock()
  finally:
    lock.release()

  while True:
    if (time.clock() - start) > opts.duration:
      break
    time.sleep(0.1)

  # Make sure we get a consistent view
  lock.acquire(shared=0)

  lock_cputime = time.clock() - start

  res = resource.getrusage(resource.RUSAGE_SELF)

  print "Total number of acquisitions: %s" % state.total_count
  print "Per-thread acquisitions:"
  for (i, count) in enumerate(state.counts):
    print ("  Thread %s: %d (%0.1f%%)" %
           (i, count, (100.0 * count / state.total_count)))

  print "Benchmark CPU time: %0.3fs" % lock_cputime
  print ("Average time per lock acquisition: %0.5fms" %
         (1000.0 * lock_cputime / state.total_count))
  print "Process:"
  print "  User time: %0.3fs" % res.ru_utime
  print "  System time: %0.3fs" % res.ru_stime
  print "  Total time: %0.3fs" % (res.ru_utime + res.ru_stime)

  # Exit directly without attempting to clean up threads
  os._exit(0) # pylint: disable=W0212


if __name__ == "__main__":
  main()