mirror of
				https://github.com/psycopg/psycopg2.git
				synced 2025-11-01 00:07:36 +03:00 
			
		
		
		
	Added script to look for refcounting bugs
This commit is contained in:
		
							parent
							
								
									3cc8719998
								
							
						
					
					
						commit
						a44441f5e5
					
				
							
								
								
									
										111
									
								
								scripts/refcounter.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										111
									
								
								scripts/refcounter.py
									
									
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,111 @@ | |||
| #!/usr/bin/env python | ||||
| """Detect reference leaks after several unit test runs. | ||||
| 
 | ||||
| The script runs the unit test and counts the objects alive after the run. If | ||||
| the object count differs between the last two runs, a report is printed and the | ||||
| script exits with error 1. | ||||
| """ | ||||
| 
 | ||||
| # Copyright (C) 2011 Daniele Varrazzo <daniele.varrazzo@gmail.com> | ||||
| # | ||||
| # 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. | ||||
| 
 | ||||
| import gc | ||||
| import sys | ||||
| import difflib | ||||
| import unittest | ||||
| from pprint import pprint | ||||
| from collections import defaultdict | ||||
| 
 | ||||
| def main(): | ||||
|     opt = parse_args() | ||||
| 
 | ||||
|     import psycopg2.tests | ||||
|     test = psycopg2.tests | ||||
|     if opt.suite: | ||||
|         test = getattr(test, opt.suite) | ||||
| 
 | ||||
|     sys.stdout.write("test suite %s\n" % test.__name__) | ||||
| 
 | ||||
|     for i in range(1, opt.nruns + 1): | ||||
|         sys.stdout.write("test suite run %d of %d\n" % (i, opt.nruns)) | ||||
|         runner = unittest.TextTestRunner() | ||||
|         runner.run(test.test_suite()) | ||||
|         dump(i, opt) | ||||
| 
 | ||||
|     f1 = open('debug-%02d.txt' % (opt.nruns - 1)).readlines() | ||||
|     f2 = open('debug-%02d.txt' % (opt.nruns)).readlines() | ||||
|     for line in difflib.unified_diff(f1, f2, | ||||
|             "run %d" % (opt.nruns - 1), "run %d" % opt.nruns): | ||||
|         sys.stdout.write(line) | ||||
| 
 | ||||
|     rv = f1 != f2 and 1 or 0 | ||||
| 
 | ||||
|     if opt.objs: | ||||
|         f1 = open('objs-%02d.txt' % (opt.nruns - 1)).readlines() | ||||
|         f2 = open('objs-%02d.txt' % (opt.nruns)).readlines() | ||||
|         for line in difflib.unified_diff(f1, f2, | ||||
|                 "run %d" % (opt.nruns - 1), "run %d" % opt.nruns): | ||||
|             sys.stdout.write(line) | ||||
| 
 | ||||
|     return rv | ||||
| 
 | ||||
| def parse_args(): | ||||
|     import optparse | ||||
| 
 | ||||
|     parser = optparse.OptionParser(description=__doc__) | ||||
|     parser.add_option('--nruns', type='int', metavar="N", default=3, | ||||
|         help="number of test suite runs [default: %default]") | ||||
|     parser.add_option('--suite', metavar="NAME", | ||||
|         help="the test suite to run (e.g. 'test_cursor'). [default: all]") | ||||
|     parser.add_option('--objs', metavar="TYPE", | ||||
|         help="in case of leaks, print a report of object TYPE " | ||||
|             "(support still incomplete)") | ||||
| 
 | ||||
|     opt, args = parser.parse_args() | ||||
|     return opt | ||||
| 
 | ||||
| 
 | ||||
| def dump(i, opt): | ||||
|     gc.collect() | ||||
|     objs = gc.get_objects() | ||||
| 
 | ||||
|     c = defaultdict(int) | ||||
|     for o in objs: | ||||
|         c[type(o)] += 1 | ||||
| 
 | ||||
|     pprint( | ||||
|         sorted(((v,str(k)) for k,v in c.items()), reverse=True), | ||||
|         stream=open("debug-%02d.txt" % i, "w")) | ||||
| 
 | ||||
|     if opt.objs: | ||||
|         co = [] | ||||
|         t = getattr(__builtins__, opt.objs) | ||||
|         for o in objs: | ||||
|             if type(o) is t: | ||||
|                 co.append(o) | ||||
| 
 | ||||
|         # TODO: very incomplete | ||||
|         if t is dict: | ||||
|             co.sort(key = lambda d: d.items()) | ||||
|         else: | ||||
|             co.sort() | ||||
| 
 | ||||
|         pprint(co, stream=open("objs-%02d.txt" % i, "w")) | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     sys.exit(main()) | ||||
| 
 | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user