This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: OT: combinatorial source line swapper test


> On Feb 17, 2005, at 9:52 AM, Davide Rossetti wrote:
> > I remember I read on this mlist about a testing tool. a script or 
> > something which took a source file in input and tried to swap lines 
> > and compile it, then reported results... can't google it exacly.. any 
> > help ??

Here's something vaguely related: a quick hack for shrinking testcases,
when you're looking for a cutdown that still exhibits some
still-mysterious failure.

Its stupidity makes it slow. But you can run it while you're asleep.



#! /usr/bin/env python

"""
thinloop.py  <infile> <tester> <successfile>

Expects infile is C source.
Loops, writing successively "thinned" version of infile to tmpfiles.
	After each tmpfile is written, does system("<tester> <tmpfile>"),
	with a 15 second timeout. If that doesn't time out, examines
	<successfile>. If it's zero length, assumes the thinned version
	was a failure, and tries a different version. If it's nonzero,
	assumes the thinned version was a success, and bases the next
	thinning on that version.
Runs forever, or until 100 fails in a row.
Prints "+" or "_" (success or fail) on each iteration.
The most recent successful output is kept as file "<infile>.keep".
The most recent file that hung the tester is file "<infile>.hung".

Thinning algorithm:
	Deletes one randomly chosen source line, under the rules:
	1) doesn't delete lines containing "{" or "}"
	2) finds a text line containing ";"
	3) deletes that line, and all preceding lines up-to the 
		preceding candidate line (as defined by rules 1 and 2).

"""
from __future__ import nested_scopes

import sys,os
import os.path
import random
import tempfile
import copy
import signal

pid = 0
#-------------
def handlerfunc( signum, obj ):
	"""Post this as the signal handler.
	   Expects pid is valid.
	"""
	global pid
	signal.alarm( 0 )
	if signum == signal.SIGALRM:
		# Caught a timeout signal, so kill the pid.
		os.kill( pid, signal.SIGKILL )

signal.signal( signal.SIGCHLD, handlerfunc)
signal.signal( signal.SIGALRM, handlerfunc)

#-------------
def tag_of( line ):
	"""Given a text lines, returns:
		0 - preserve (contains '{' or '}'
		1 - target (contains ';')
		2 - freefire (not either of above)
	"""
	if '{' in line: return 0
	if '}' in line: return 0
	if ';' in line: return 1
	return 2
#-------------
def slim_list( line_list):
	""" Returns a slimmed copy of line_list"""

	# Get a shallow copy (ie same strings, but new ptrs)
	line_list = copy.copy( line_list )

	# Get a random in the range 0..N-1
	target = random.choice(xrange(len(line_list)))

	try:	
		# If we run off the end of arrays, just punt,
		# and make no change.

		# Search forward from random startpoint for a semicolon
		while ';' not in line_list[target]:
			target += 1

		# Search backward for all freefire's leading up to target
		freefire = target
		while tag_of( line_list[freefire-1]) == 2:
			freefire -= 1

		# delete all lines freefire upthu target
		# (Note each del renumbers them.)
		while freefire <= target:
			del line_list[freefire]
			target -= 1

	except:
		pass
	return line_list

#-------------
def main( infile_name, tester, success_file ):

	global pid
	line_list = open(infile_name).readlines()
	fail_count = 0;
	while 1:

		# Get a shortened file
		short_list = slim_list( line_list )

		# Emit the remaining lines to a tmpfile
		outfile_name = tempfile.mktemp(".c")
		outfile = open( outfile_name, "w")
		outfile.writelines(short_list)
		outfile.close()

		# Invoke the tester, after setting timeout
		signal.alarm( 15 )
		pid = os.spawnv( os.P_NOWAIT, tester, [tester,outfile_name] )

		# Wait for the tester to finish, turning any error from a KILL
		# into a bool. See handlerfunc, who expects we've set the pid.
		ok = 1
		try:
			os.wait()
		except OSError:
			ok = 0

		# Check the tester's success criteria, maybe keep the change
		if ok and os.path.getsize( success_file ) != 0:
			# Success: the change was good.
			line_list = short_list
			os.system( "/bin/cp -f %s %s.keep" % 
				( outfile_name, infile_name))
			sys.stderr.write("+")
			fail_count = 0
		else:
			if not ok:
				# Can't use rename, won't cross disks
				os.system( "/bin/cp -f %s %s.hung" %
					( outfile_name, infile_name ))
			sys.stderr.write("_")
			fail_count += 1
			if fail_count >= 100:
				sys.exit("Making no headway, stopping.")
		os.remove( outfile_name )
#-------------
if __name__ == '__main__':
	if len(sys.argv) != 4:
		sys.exit("TRY: thinloop.py  <infile> <tester> <successfile>" )
	infile_name 	= sys.argv[1]
	tester 		= sys.argv[2]
	success_file 	= sys.argv[3]
	main( infile_name, tester, success_file )


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]