[Python-checkins] python/dist/src/Lib/test regrtest.py,1.156,1.157

mwh at users.sourceforge.net mwh at users.sourceforge.net
Tue Aug 3 13:33:31 CEST 2004


Update of /cvsroot/python/python/dist/src/Lib/test
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32643

Modified Files:
	regrtest.py 
Log Message:
Check in my refleak hunting code.

It's not the 100% solution -- it may not even be the 90% solution -- but
it does seem to help.


Index: regrtest.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/test/regrtest.py,v
retrieving revision 1.156
retrieving revision 1.157
diff -C2 -d -r1.156 -r1.157
*** regrtest.py	26 Jul 2004 12:09:13 -0000	1.156
--- regrtest.py	3 Aug 2004 11:33:28 -0000	1.157
***************
*** 9,25 ****
  Command line options:
  
! -v: verbose   -- run tests in verbose mode with output to stdout
! -q: quiet     -- don't print anything except if a test fails
! -g: generate  -- write the output file for a test instead of comparing it
! -x: exclude   -- arguments are tests to *exclude*
! -s: single    -- run only a single test (see below)
! -r: random    -- randomize test execution order
! -f: fromfile  -- read names of tests to run from a file (see below)
! -l: findleaks -- if GC is available detect tests that leak memory
! -u: use       -- specify which special resource intensive tests to run
! -h: help      -- print this text and exit
! -t: threshold -- call gc.set_threshold(N)
! -T: coverage  -- turn on code coverage using the trace module
! -L: runleaks  -- run the leaks(1) command just before exit
  
  If non-option arguments are present, they are names for tests to run,
--- 9,26 ----
  Command line options:
  
! -v: verbose    -- run tests in verbose mode with output to stdout
! -q: quiet      -- don't print anything except if a test fails
! -g: generate   -- write the output file for a test instead of comparing it
! -x: exclude    -- arguments are tests to *exclude*
! -s: single     -- run only a single test (see below)
! -r: random     -- randomize test execution order
! -f: fromfile   -- read names of tests to run from a file (see below)
! -l: findleaks  -- if GC is available detect tests that leak memory
! -u: use        -- specify which special resource intensive tests to run
! -h: help       -- print this text and exit
! -t: threshold  -- call gc.set_threshold(N)
! -T: coverage   -- turn on code coverage using the trace module
! -L: runleaks   -- run the leaks(1) command just before exit
! -R: huntrleaks -- search for reference leaks (needs debug build, v. slow)
  
  If non-option arguments are present, they are names for tests to run,
***************
*** 48,51 ****
--- 49,60 ----
  FreeBSD-derived systems.
  
+ -R runs each test several times and examines sys.gettotalrefcount() to
+ see if the test appears to be leaking references.  The argument should
+ be of the form stab:run:fname where 'stab' is the number of times the
+ test is run to let gettotalrefcount settle down, 'run' is the number
+ of times further it is run and 'fname' is the name of the file the
+ reports are written to.  These parameters all have defaults (5, 4 and
+ "reflog.txt" respectively), so the minimal invocation is '-R ::'.
+ 
  -u is used to specify which special resource intensive tests to run,
  such as those requiring large file support or network connectivity.
***************
*** 85,88 ****
--- 94,98 ----
  import random
  import warnings
+ import sre
  import cStringIO
  import traceback
***************
*** 128,132 ****
  def main(tests=None, testdir=None, verbose=0, quiet=False, generate=False,
           exclude=False, single=False, randomize=False, fromfile=None,
!          findleaks=False, use_resources=None, trace=False, runleaks=False):
      """Execute a test suite.
  
--- 138,143 ----
  def main(tests=None, testdir=None, verbose=0, quiet=False, generate=False,
           exclude=False, single=False, randomize=False, fromfile=None,
!          findleaks=False, use_resources=None, trace=False, runleaks=False,
!          huntrleaks=False):
      """Execute a test suite.
  
***************
*** 153,161 ****
      test_support.record_original_stdout(sys.stdout)
      try:
!         opts, args = getopt.getopt(sys.argv[1:], 'hvgqxsrf:lu:t:TL',
                                     ['help', 'verbose', 'quiet', 'generate',
                                      'exclude', 'single', 'random', 'fromfile',
                                      'findleaks', 'use=', 'threshold=', 'trace',
!                                     'runleaks'
                                      ])
      except getopt.error, msg:
--- 164,172 ----
      test_support.record_original_stdout(sys.stdout)
      try:
!         opts, args = getopt.getopt(sys.argv[1:], 'hvgqxsrf:lu:t:TLR:',
                                     ['help', 'verbose', 'quiet', 'generate',
                                      'exclude', 'single', 'random', 'fromfile',
                                      'findleaks', 'use=', 'threshold=', 'trace',
!                                     'runleaks', 'huntrleaks='
                                      ])
      except getopt.error, msg:
***************
*** 192,195 ****
--- 203,221 ----
          elif o in ('-T', '--coverage'):
              trace = True
+         elif o in ('-R', '--huntrleaks'):
+             huntrleaks = a.split(':')
+             if len(huntrleaks) != 3:
+                 print a, huntrleaks
+                 usage(2, '-R takes three colon-separated arguments')
+             if len(huntrleaks[0]) == 0:
+                 huntrleaks[0] = 5
+             else:
+                 huntrleaks[0] = int(huntrleaks[0])
+             if len(huntrleaks[1]) == 0:
+                 huntrleaks[1] = 4
+             else:
+                 huntrleaks[1] = int(huntrleaks[1])
+             if len(huntrleaks[2]) == 0:
+                 huntrleaks[2] = "reflog.txt"
          elif o in ('-u', '--use'):
              u = [x.lower() for x in a.split(',')]
***************
*** 289,293 ****
                            globals=globals(), locals=vars())
          else:
!             ok = runtest(test, generate, verbose, quiet, testdir)
              if ok > 0:
                  good.append(test)
--- 315,319 ----
                            globals=globals(), locals=vars())
          else:
!             ok = runtest(test, generate, verbose, quiet, testdir, huntrleaks)
              if ok > 0:
                  good.append(test)
***************
*** 398,402 ****
      return stdtests + tests
  
! def runtest(test, generate, verbose, quiet, testdir=None):
      """Run a single test.
      test -- the name of the test
--- 424,428 ----
      return stdtests + tests
  
! def runtest(test, generate, verbose, quiet, testdir=None, huntrleaks=False):
      """Run a single test.
      test -- the name of the test
***************
*** 416,419 ****
--- 442,447 ----
      else:
          cfp = cStringIO.StringIO()
+     if huntrleaks:
+         refrep = open(huntrleaks[2], "a")
      try:
          save_stdout = sys.stdout
***************
*** 436,439 ****
--- 464,511 ----
              if indirect_test is not None:
                  indirect_test()
+             if huntrleaks:
+                 # This code *is* hackish and inelegant, yes.
+                 # But it seems to do the job.
+                 import copy_reg
+                 fs = warnings.filters[:]
+                 ps = copy_reg.dispatch_table.copy()
+                 pic = sys.path_importer_cache.copy()
+                 import gc
+                 def cleanup():
+                     import _strptime, urlparse, warnings, dircache
+                     from distutils.dir_util import _path_created
+                     _path_created.clear()
+                     warnings.filters[:] = fs
+                     gc.collect()
+                     sre.purge()
+                     _strptime._regex_cache.clear()
+                     urlparse.clear_cache()
+                     copy_reg.dispatch_table.clear()
+                     copy_reg.dispatch_table.update(ps)
+                     sys.path_importer_cache.clear()
+                     sys.path_importer_cache.update(pic)
+                     dircache.reset()
+                 if indirect_test:
+                     def run_the_test():
+                         indirect_test()
+                 else:
+                     def run_the_test():
+                         reload(the_module)
+                 deltas = []
+                 repcount = huntrleaks[0] + huntrleaks[1]
+                 print >> sys.stderr, "beginning", repcount, "repetitions"
+                 print >> sys.stderr, \
+                       ("1234567890"*(repcount//10 + 1))[:repcount]
+                 for i in range(repcount):
+                     rc = sys.gettotalrefcount()
+                     run_the_test()
+                     sys.stderr.write('.')
+                     cleanup()
+                     deltas.append(sys.gettotalrefcount() - rc - 2)
+                 print >>sys.stderr
+                 if max(map(abs, deltas[-huntrleaks[1]:])) > 0:
+                     print >>refrep, test, 'leaked', \
+                           deltas[-huntrleaks[1]:], 'references'
+                 # The end of the huntrleaks hackishness.
          finally:
              sys.stdout = save_stdout
***************
*** 487,491 ****
          else:
              expected = test + "\n"
!         if output == expected:
              return 1
          print "test", test, "produced unexpected output:"
--- 559,563 ----
          else:
              expected = test + "\n"
!         if output == expected or huntrleaks:
              return 1
          print "test", test, "produced unexpected output:"



More information about the Python-checkins mailing list